Description Give the Lisp
Syntax, we can now apply it to parse textual Lisp expressions
and convert them to the runtime representation
Lval
.
module demo::lang::Lisra::Parse
import Prelude;
import demo::lang::Lisra::Syntax;
import demo::lang::Lisra::Runtime;
public Lval parse(str txt) = build(parse(#LispExp, txt));
// Build Abstract Synax Tree: Transform a LispExp to an Lval
public Lval build((LispExp)`<IntegerLiteral il>`) = Integer(toInt("<il>"));
public Lval build((LispExp)`<AtomExp at>`) = Atom("<at>");
public Lval build((LispExp)`( <LispExp* lst> )`) = List([build(le) | le <- lst]);
First we define the actual
parse
function (

): it takes a string as argument and returns an
Lval
.
It proceeds in two steps:
- First the text is parsed using
parse(#LispExp, txt)
. The result is parse tree.
- Next, the auxiliary function
build
is used to transform the parse tree to an Lval
.
Function
build
(

--

) is defined in cases, for the various parse tree forms.
Fortunately, we do not have to spell out the details of the parse tree, but we can use concrete
patterns instead. For instance, the argument pattern
(LispExp)`<IntegerLiteral il>`
says:
- Match something of type
LispExp
.
- It should be an
IntegerLiteral
and bind it to a variable il
.
More precisely, the text between backquotes should be a string that can be parsed according to the non-terminal
that precedes it (
LispExp
in this example). This is illustrated by the list case where the parentheses appear in the concrete pattern:
(LispExp)`( <LispExp* lst> )`
The right-hand sides of (

--

) deserve some attention:
- In
the argument il
is a parse tree (!!) that represents an integer literal. We first convert it to a string using string interpolation ("<il>"
) and then convert it to an integer.
- In
the text of the atom is reconstructed in a similar fashion.
- In
the concrete list elements in lst
are converted one-by-one using build and are then used to create a new List
value.
Examples rascal>import demo::lang::Lisra::Parse;
ok
rascal>import demo::lang::Lisra::Runtime;
ok
rascal>parse("1");
Lval: Integer(1)
rascal>parse("x");
Lval: Atom("x")
rascal>parse("(+ 5 7)");
Lval: List([
Atom("+"),
Integer(5),
Integer(7)
])