1.1.1             Gema

Elaboratore di testi

Gema (GEneral purpose MAcro generator) è uno strumento per traformare testi creato da David N. Gray nel 1995.

E’ disponibile sotto Unix, Windows e Macintosh  (adattato da David A. Mundie).

Gema utilizza un insieme di regole di trasformazione, eventualmente presenti in un file, per analizzare e trasformare un testo. Nella terminologia di Gema le regole sono formate da un template, che individua un frammento di testo ed una action, che, eventualmente,  lo modifica.

Il template è formato o da testo o da espressioni regolari o da operatori di match, divisi in tre categorie:

\B

Inizio del file di input

\B=\!@datime{}\n

\E

Fine file

\E=\n\@line{} lines

\N

dall'inizio della riga

 

\C

confronto case insensitive

 

\W

ignora white spaces

 

<D>

Numeri

<D3>=$1\.

<L>

Caratteri alfabetici

 

·         Riconoscitori; <X>, i frammenti di testo riconosciuti sono disponibili nelle variabili $1, $2 ....  X può essere seguito da un numero che impone una lunghezza fissa.

La parte action delle regole è formata da testo e funzioni e produce la sostituzione del testo riconosciuto con il testo presente nella action e quello generato dalle funzioni presenti. L’azione può essere terminata o dal fine linea o dal carattere ! che individua l’inizio di un commento.

Le regole possono essere raggruppate in domini: nome_dominio:template=action, allo scopo di avere  regole da applicare selettivamente, ma anche da utilizzare come funzioni, infatti sono invocate con la sintassi di queste, per esempio :

<D>\W<D>\W<D>\W\n=Triangolo rettangolo $1,$2,$3\? @ret{$1 $2 $3}

ret:* * *=@cmpn{@mul{$3;$3};@add{@mul{$1;$1};@mul{$2;$2}};no;si;no}

Si noti il template della regola * * * e la chiamata @ret{$1 $2 $3}.

Come linguaggio di programmazione Gema opera su stringhe di caratteri, con un sufficiente repertorio di funzioni; accetta inoltre numeri (interi) le cui usuali operazioni elementari sono in forma di funzione. Non sono presenti (quasi) operatori, ma solo funzioni per cui il concatenamento di stringhe e la sequenzialità delle operazioni si ottengono semplicemente per giustapposizione. L’unica struttura complessa è lo stack, di fatto ogni variabile è potenzialmente uno stack:

Condizionali e loop

Gema è relativamente povero di strutture condizionali, ci sono tre funzioni di confronto, rispettivamente per i numeri e due per le stringhe (@cmpn, @cmps e @cmpi), che eseguono azioni in funzione dei tre risultati possibili del confronto, nell’esempio la funzione gcm utilizza il confronto numerico per calcolare il massimo comun divisore di due numeri, la funzione fatt utilizza il confronto per calcolare ricorsivamente il fattoriale di un numero.

fatt:*=@cmpn{$1;1;0;1;@mul{$1;@fatt{@sub{$1;1}}}}
<D>\! =  Fatt $1 = @fatt{$1}! pattern per trovare il fattoriale
gcd:* *=@cmpn{$1;$2;@gcd{$1 @sub{$2;$1}};$1 ;@gcd{@sub{$1;$2} $2}}
<D>\W<D>\W=GCD $1 $2 = @gcd{$1 $2}! pattern per trovare due numeri   

88 22 97 61 11!

GCD 88 22 = 22 GCD 97 61 = 1  Fatt 11 = 39916800

Le funzioni di confronto sostituiscono (ed estendono) la struttura if then else; con l’uso della ricorsione, si emula la struttura  while, così come il for si può realizzare tramite la funzione @repeat{quantità; azione}.

Sono presenti funzioni per l’input output e per operare dinamicamente sulle regole, ad esempio si può utilizzare una regola per individuare la prima occorrenza di un testo e poi eliminarla tramite la funzione @undefine{template}.

L’operatore $, premesso ad  un nome di variabile, ha l’effetto di sostituire questo complesso con il valore della variabile, per cui nelle funzioni in cui un operando è la variabile stessa (@set, @push, @var, …)  il nome è senza il $ premesso, viceversa nelle funzioni che operano sulle variabili esso deve essere presente.

E’ disponibile una versione di Gema, gel, che include Lua per estenderne le capacità di calcolo, le istruzioni Lua sono inserite entro i delimitatori ![ e !].

Aspetti moderni

Gema ha degli aspetti di un linguaggio moderno: i domini sono di fatto una sorta di polimorfismo, è possibile scrivere funzioni ricorsive e la maggior parte delle regole sono di tipo funzionale. Esiste anche una certa ereditarietà: con la dichiarazionr dominio1::dominio2 si indica che dominio1 eredita da  dominio2, in altre parole dominio1 include dominio2.

Nell’esempio che segue le regole generano una programma Gema a partire da un testo con alcune istruzioni (di un linguaggio indefinito).

Rules

!gel 1.0RC Mar 31, 2004

\B=\!@datime{}\n! at beginning of data

*/\n*/\!]=@undefine{\*/\\n\*/\\\!]}!     discard embedded lua code and rule

\N<L1>\W\=*\n=\@set\{$1\;@frm{*}\}\\n\n!  variable name <L1> only one letter

<D>\!\W\n=@frm{$0}\n

frm:<D>\W/[\*|+|-]/\W<D>\W=@frm{$1 $2 $3}

frm:<D>\W/[\*|+|-]/\W<L1>\W=@frm{$1 $2 \$$3}

frm:<L1>\W/[\*|+|-]/\W<D>\W=@frm{\$$1 $2 $3}

frm:<L1>\W/[\*|+|-]/\W<L1>\W=@frm{\$$1 $2 \$$3}

frm:*\W+\W*=\@add\{*\;*\}

frm:*\W\*\W*=\@mul\{*\;*\}

frm:*\W-\W*=\@sub\{*\;*\}

frm:<D>\!=\@lua\{return fattoriale($1)\}\\n

print:<L1>*=\@out\{\$$1 \}@print{$2}

\N\Cloop <L1> <D> *\n=\@set\{$1\;0\}\@repeat\{$2\; \@incr\{$1\}@frm{*}\}\\n\n

\N\CPrint *\n=@print{*}\\n\n

\E=\n\!@line{} lines\n! at end

Text

![

function fattoriale(n)

  local fatt = 1

  for ij = 1,n do fatt = ij*fatt end

  return fatt

end

!]

a=7

b=17 - a

c=a*b

Print a b c

loop i 10 i*i

11!

30!

Output

!Tue Sep 11 19:39:28 2007

@set{a;7}\n

@set{b;@sub{17;$a}}\n

@set{c;@mul{$a;$b}}\n

@out{$a } @out{$b } @out{$c }\n

@set{i;0}@repeat{10; @incr{i}@mul{$i;$i}}\n

@lua{return fattoriale(11)}\n

@lua{return fattoriale(30)}\n

!14 lines

Run (after manual insertion of Lua code)  

H:\Software\Gema>gel -f x.gem 

7 10 70

1 4 9 16 25 36 49 64 81 100

39916800

2.6525285981219e+032