1.1        elastiC

elastiC è un linguaggio concepito e sviluppato da Marco Pantaleoni a partire dal 1999.

Il linguaggio ha una sintassi simile al C, supporta il paradigma ad oggetti (alla Smalltalk) e può essere incluso come libreria in programmi C, è estensibile tramite librerie con funzioni, classi e metodi. Esiste un compilatore che produce un codice intermedio ed un interprete di detto codice.

elastiC è dinamicamente tipizzato con obbligo di dichiarare le variabili,i tipi di dato sono: numeri interi e floating, caratteri, booleani (@true e @false), simboli, matrici, liste, dizionari (tabelle Hash), classi e funzioni. Le variabili dichiarate al di fuori delle funzioni sono visibili anche all’interno di queste e non il viceversa. Le variabili dichiarate static all’interno di una funzione preservano il contenuto durante i successivi richiami della funzione.

Il linguaggio ha una certa completezza anche se non sembra abbia attualmente ulteriori sviluppi e la documentazione, per la parte che riguarda le librerie, è piuttosto scarsa.

elastiC è sviluppato sul concetto di librerie di funzioni, da importare esplicitamente tramite il comando import nomelibreria; molte funzioni comuni sono contenute nella libreria basic. Le librerie “standard” oltre al modulo basic, comprendono: sys, math, string, list, array, file e re (espressioni regolari).

Per gestire i cicli si dispone di:

·         while (condizione) istruzioni

·         do istruzioni while (condizione);

·         for (variabile=inizio; confronto; modifica variabile;) istruzioni;

·         for (variabile in sequenza) istruzioni      // per percorrere una matrice

Oltre all’istruzione break per uscire da un ciclo e le istruzioni per gestire le eccezioni (try e catch), elastiC dispone anche dell’istruzione goto label.

Le funzioni disponibili per matrici, liste e dizionari sono complete, ad esempio liste e matrici possono essere gestite come stack tramite push e pop, viceversa sono relativamente poche le funzioni per gestire le stringhe. La creazione di una matrice o di una tavola hash avviene rispettivamente tramite gli operatori # e %.

Le funzioni accettano un numero variabile di parametri variabili: function show(a, args ...) dove args è un’ insieme di valori, che, all’interno della funzione, sono disponibili come matrice:

// ec version 0.02 (elastiC 0.0.14)

package pr;

import basic;

import file;

import array;

function Funct(item,x) {return x(item);}

function GeneralisedMean(m, values ...) {

  local item,accum = 0;

  for (item in values) accum = accum + item**m;

  return (accum/array.length(values))**1/m;

}

function Cube(x) {return x**3;}

basic.print(GeneralisedMean(1,1.0,2.0,3.0,4.0,5.0),"\n");

basic.print(GeneralisedMean(2,1.0,2.0,3.0,4.0,5.0),"\n");

basic.print(GeneralisedMean(-1,1.0,2.0,3.0,4.0,5.0),"\n");

basic.print(Funct(7,function (x) {return x**4; } ),"\n");

basic.print(Funct(11,Cube),"\n");

3

5.5

-0.456667

2401

1331

Nell’esempio c’è anche l’utilizzo di funzioni passate come parametri

C’è una piccola incongruenza nel trattamento dei valori booleani, oltre alla costante @false è considerato falso anche il valore numerico 0, tranne quando è restituito dal metodo find (disponibile per matrici e stringhe); l’operatore in restituisce invece @true o @false.

L’esempio che segue è stato generato con Txl che ha interpretato uno script Corc per calcolare la radice cubica col metodo di Newton.

// ec version 0.02 (elastiC 0.0.14)

package corc;

import basic;

public i_;

basic.print(" Cube Root with Newton method ","\n");

 

public Y = 1.0;

public N = 999.0;

public DIFF = 0;

function CICLO () {

    Y = ((N / (Y * Y)) + 2 * Y) / 3;

}

ROOTLOOP:

// Compute next value

for (i_ = 1; i_ <= 1; i_ = i_ + 1) CICLO ();

// Compute absolute value of difference

DIFF = Y * Y * Y - N;

if (DIFF >= 0) goto POSITIVE;

DIFF = - DIFF;

POSITIVE:

if (DIFF >= 0.001) goto ROOTLOOP;

basic.print(N," ", Y,"\n");

Loading `corc'

Load completed.

 Cube Root with Newton method

999 9.99667

C’è una buona gestione degli oggetti e dell’ereditarietà, mutuata da Smalltalk. Il metodo init, se presente, è richiamato al momento della creazione dell’istanza dell’oggetto; self e super permettono di accedere, rispettivamente, ai metodi dell’oggetto o della classe da cui si eredita.

La dichiarazioni dei metodi è analoga alla dichiarazione delle funzioni, ma è accettta anche una variante con l’indicazione del nome del parametro:

    method nome: parametro1 keyword2: parametro2 ...

Con questa seconda forma, il programma è più leggibile, tuttavia nonostante la presenza delle parole chiave, l’ordine di scrittura è fisso.

L’esempio che segue è un interprete (incompleto) di CLP (Cornell List Processor) è l’estensione di CORC per la simulazione(v. CLP par. 1.21.3 ).

// ec version 0.02 (elastiC 0.0.14)

package clp;

import basic; import file; import string; import array; import hash;

public class objs extends basic.Object {

     local objAttr,item;

    method init() {    // initializer (called by new)

        objAttr = %[];

    }

    method update: Key with: Value {    // Update hash table of attributes array's

       if (!hash.has_key(objAttr,Key)) objAttr[Key] = #[];

       array.push(objAttr[Key],Value);

    }

    method remove: Value from: Key {    // Update hash table of attributes array's

     local transitArray= #[];

       if (hash.has_key(objAttr,Key)) {

         for (item in objAttr[Key]) if (item != Value) array.push(transitArray,item);

         objAttr[Key] = transitArray;

       }

    }

    method list() {

       local arrKey = hash.keys(objAttr);     // keys array

       for (item in arrKey) basic.print(item,": ",objAttr[item],"\n" );

    }

}

public bag = [objs new];

function Clean(item,stuffs) {

  // clean input from chars in stuffs and remove extra spaces  

  local stuff="",i,chr = "";

  for (i=0;i< string.length(item);i++) {

    if (array.find(stuffs,string.sub(item,i,1)) != @false)

    item = string.sub(item,0,i) + " " + string.sub(item,i+1);

     if (chr != " " || string.sub(item,i,1) != " ")

         stuff = stuff + string.sub(item,i,1);

     chr = string.sub(item,i,1);

  }

  return stuff;

}

function Interp(item) {

     local Split = string.split(Clean(item,#["(",")"])," ");;

      basic.print(item,"\n" );

      if (Split[0] == "LET") {

        [bag update: Split[4] with: Split[1]]; }

      else if (Split[0] == "INSERT") {

        [bag update: Split[4] with: Split[2]]; }         

      else if (Split[0] == "REMOVE") [bag remove: Split[2] from: Split[4]];

}

local line, fl = file.open("c:\\condor\\elastic\\bin\\clp.inp","r");

while (!file.eof(fl)) {

  line = file.gets(fl);

  if (file.eof(fl)) break;

  Interp(string.sub(line,0,string.length(line)-1)); // drop line feed

}

file.close(fl);

[bag list];

 

LET(I) = NEW CAR

LET(J) = NEW CAR

LET(K) = NEW CAR

LET(L) = NEW CAR

INSERT CAR J ON LANE

INSERT CAR K ON LANE

INSERT CAR I ON REPAIR

INSERT CAR L ON LANE

REMOVE CAR J FROM LANE

CAR: ["I", "J", "K", "L"]

LANE: ["K", "L"]

REPAIR: ["I"]

Qui accanto il listato dell’esecuzione del programma.