Adaish
Die Funktion adaish erlaubt es, ein Codeschnippsel in einer Algol/Pascal/Ada-artigen Notation zu formulieren, in Lisp zu übersetzen und dann auszuführen. Sie basiert auf den Prinzipien von EBNF (siehe Wörter von formalen Sprachen erkennen). Die verwendeten Regeln sind:
NUMBER = <Ganzzahl, Folge von Ziffern an deren Anfang nicht die 0 steht>
NAME = <Bezeichner, Folge von Kleinbuchstaben>
ARGUMENTS = EXPRESSION { "," EXPRESSION }
CALL = NAME "(" ARGUMENTS ")"
BRACKETED-EXPRESSION = "(" EXPRESSION ")"
FACTOR = BRACKETED-EXPRESSION | NUMBER | CALL | NAME
PRODUCT = FACTOR { "*" FACTOR }
QUOTIENT = FACTOR "/" FACTOR
PRODUCT-OR-QUOTIENT = PRODUCT | QUOTIENT
SUM = PRODUCT-OR-QUOTIENT { "+" PRODUCT-OR-QUOTIENT }
DIFFERENCE = PRODUCT-OR-QUOTIENT "-" PRODUCT-OR-QUOTIENT
EXPRESSION = DIFFERENCE | SUM
COMPARISON-OPERATOR = "<=" | ">=" | "<" | ">" | "="
ATOM = EXPRESSION COMPARISON-OPERATOR EXPRESSION
NEGATION = "NOT" LITERAL
BRACKETED-DISJUNCTION = "(" DISJUNCTION ")"
LITERAL = BRACKETED-DISJUNCTION | NEGATION | ATOM
CONJUNCTION = LITERAL { "AND" LITERAL }
DISJUNCTION = CONJUNCTION { "OR" CONJUNCTION }
PREDICATE = DISJUNCTION
PARAMETERS = NAME { "," NAME }
VARIABLE-DEFINITIONS = "VAR" PARAMETERS
SEQUENCE = STATEMENT { ";" STATEMENT }
BLOCK = [ VARIABLE-DEFINITIONS ] "BEGIN" SEQUENCE "END"
IF = "IF" PREDICATE "THEN" SEQUENCE [ ELSE-BRANCH ]
IF-OR-SEQUENCE = IF | SEQUENCE
ELSE-BRANCH = "ELSE" IF-OR-SEQUENCE
CONDITIONAL = "IF" PREDICATE "THEN" STATEMENT [ ELSE-BRANCH ] "END" "IF"
FOR = "FOR" NAME "IN" EXPRESSION
WHILE = "WHILE" PREDICATE
LOOP = [ FOR ] [ WHILE ] "LOOP" SEQUENCE "END" "LOOP"
EXIT-WHEN = "EXIT "WHEN" PREDICATE
ASSIGNMENT = NAME ":=" EXPRESSION
RETURN = "RETURN" EXPRESSION
STATEMENT = BLOCK | CONDITIONAL | LOOP | EXIT-WHEN | ASSIGNMENT | RETURN
Die Regeln finden sich im Programm als Funktionen wieder. Die Funktion translate-statement repräsentiert dabei die letzte Regel. Sie wird von der Funktion adaish-to-lisp aufgerufen.
(defproc adaish-to-lisp (source)
(quasi-quote
(catch
(quote adaish-return)
(unquote
(first
(translate-statement
(tokenize-string
source
(concatenate (code-char 10) (code-char 13) " (),;:=+-*/<>")
t)))))))
Diese Funktion liefert beispielsweise für die Zeichenkette
VAR p
BEGIN
p := 1;
FOR i IN list(2, 3, 4, 5) WHILE p < 20 LOOP
p := p * i
END LOOP;
RETURN p
END
den übersetzten Lisp-Ausdruck
(catch (quote adaish-return)
(let
((p nil))
(progn
(setq p 1)
(catch (quote adaish-break)
(dolist (i (list 2 3 4 5))
(unless (< p 20)
(throw (quote adaish-break) nil))
(setq p (* p i))))
(throw (quote adaish-return) p))))
Die Funktion adaish nimmt den von adaish-to-lisp erzeugten Ausdruck und wertet ihn aus.
(defproc adaish (source)
(eval (adaish-to-lisp source)))
Für das Beispiel
VAR i, ps, rps
BEGIN
i := 2;
WHILE length(ps) < 20 LOOP
VAR c
BEGIN
FOR p IN ps WHILE c = nil AND p * p <= i LOOP
IF integer?(i / p) = t THEN
c := t
END IF
END LOOP;
IF c = nil THEN
rps := cons(i, rps);
ps := reverse(rps)
END IF
END;
i := i + 1
END LOOP;
RETURN ps
END
liefert ein Aufruf von adaish die Liste
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71)
als Ergebnis.
Die unten verlinkte Datei adaish.sheet.xml enthält den vollständigen Quelltext und weitere Beispiele. Die Datei kann mit dem Programm Calc ausgeführt werden.
NUMBER = <Ganzzahl, Folge von Ziffern an deren Anfang nicht die 0 steht>
NAME = <Bezeichner, Folge von Kleinbuchstaben>
ARGUMENTS = EXPRESSION { "," EXPRESSION }
CALL = NAME "(" ARGUMENTS ")"
BRACKETED-EXPRESSION = "(" EXPRESSION ")"
FACTOR = BRACKETED-EXPRESSION | NUMBER | CALL | NAME
PRODUCT = FACTOR { "*" FACTOR }
QUOTIENT = FACTOR "/" FACTOR
PRODUCT-OR-QUOTIENT = PRODUCT | QUOTIENT
SUM = PRODUCT-OR-QUOTIENT { "+" PRODUCT-OR-QUOTIENT }
DIFFERENCE = PRODUCT-OR-QUOTIENT "-" PRODUCT-OR-QUOTIENT
EXPRESSION = DIFFERENCE | SUM
COMPARISON-OPERATOR = "<=" | ">=" | "<" | ">" | "="
ATOM = EXPRESSION COMPARISON-OPERATOR EXPRESSION
NEGATION = "NOT" LITERAL
BRACKETED-DISJUNCTION = "(" DISJUNCTION ")"
LITERAL = BRACKETED-DISJUNCTION | NEGATION | ATOM
CONJUNCTION = LITERAL { "AND" LITERAL }
DISJUNCTION = CONJUNCTION { "OR" CONJUNCTION }
PREDICATE = DISJUNCTION
PARAMETERS = NAME { "," NAME }
VARIABLE-DEFINITIONS = "VAR" PARAMETERS
SEQUENCE = STATEMENT { ";" STATEMENT }
BLOCK = [ VARIABLE-DEFINITIONS ] "BEGIN" SEQUENCE "END"
IF = "IF" PREDICATE "THEN" SEQUENCE [ ELSE-BRANCH ]
IF-OR-SEQUENCE = IF | SEQUENCE
ELSE-BRANCH = "ELSE" IF-OR-SEQUENCE
CONDITIONAL = "IF" PREDICATE "THEN" STATEMENT [ ELSE-BRANCH ] "END" "IF"
FOR = "FOR" NAME "IN" EXPRESSION
WHILE = "WHILE" PREDICATE
LOOP = [ FOR ] [ WHILE ] "LOOP" SEQUENCE "END" "LOOP"
EXIT-WHEN = "EXIT "WHEN" PREDICATE
ASSIGNMENT = NAME ":=" EXPRESSION
RETURN = "RETURN" EXPRESSION
STATEMENT = BLOCK | CONDITIONAL | LOOP | EXIT-WHEN | ASSIGNMENT | RETURN
Die Regeln finden sich im Programm als Funktionen wieder. Die Funktion translate-statement repräsentiert dabei die letzte Regel. Sie wird von der Funktion adaish-to-lisp aufgerufen.
(defproc adaish-to-lisp (source)
(quasi-quote
(catch
(quote adaish-return)
(unquote
(first
(translate-statement
(tokenize-string
source
(concatenate (code-char 10) (code-char 13) " (),;:=+-*/<>")
t)))))))
Diese Funktion liefert beispielsweise für die Zeichenkette
VAR p
BEGIN
p := 1;
FOR i IN list(2, 3, 4, 5) WHILE p < 20 LOOP
p := p * i
END LOOP;
RETURN p
END
den übersetzten Lisp-Ausdruck
(catch (quote adaish-return)
(let
((p nil))
(progn
(setq p 1)
(catch (quote adaish-break)
(dolist (i (list 2 3 4 5))
(unless (< p 20)
(throw (quote adaish-break) nil))
(setq p (* p i))))
(throw (quote adaish-return) p))))
Die Funktion adaish nimmt den von adaish-to-lisp erzeugten Ausdruck und wertet ihn aus.
(defproc adaish (source)
(eval (adaish-to-lisp source)))
Für das Beispiel
VAR i, ps, rps
BEGIN
i := 2;
WHILE length(ps) < 20 LOOP
VAR c
BEGIN
FOR p IN ps WHILE c = nil AND p * p <= i LOOP
IF integer?(i / p) = t THEN
c := t
END IF
END LOOP;
IF c = nil THEN
rps := cons(i, rps);
ps := reverse(rps)
END IF
END;
i := i + 1
END LOOP;
RETURN ps
END
liefert ein Aufruf von adaish die Liste
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71)
als Ergebnis.
Die unten verlinkte Datei adaish.sheet.xml enthält den vollständigen Quelltext und weitere Beispiele. Die Datei kann mit dem Programm Calc ausgeführt werden.