149 lines
4 KiB
Text
149 lines
4 KiB
Text
-- demo\rosetta\Compiler\parse.e
|
|
-- The reusable part of parse.exw
|
|
with javascript_semantics
|
|
include lex.e
|
|
|
|
sequence tok
|
|
|
|
procedure errd(sequence msg, sequence args={})
|
|
{tok_line,tok_col} = tok
|
|
error(msg,args)
|
|
end procedure
|
|
|
|
global sequence toks
|
|
integer next_tok = 1
|
|
|
|
function get_tok()
|
|
sequence tok = toks[next_tok]
|
|
next_tok += 1
|
|
return tok
|
|
end function
|
|
|
|
procedure expect(string msg, integer s)
|
|
integer tk = tok[3]
|
|
if tk!=s then
|
|
errd("%s: Expecting '%s', found '%s'\n", {msg, tkNames[s], tkNames[tk]})
|
|
end if
|
|
tok = get_tok()
|
|
end procedure
|
|
|
|
function expr(integer p)
|
|
object x = NULL, node
|
|
integer op = tok[3]
|
|
|
|
switch op do
|
|
case tk_LeftParen:
|
|
tok = get_tok()
|
|
x = expr(0)
|
|
expect("expr",tk_RightParen)
|
|
case tk_sub:
|
|
case tk_add:
|
|
tok = get_tok()
|
|
node = expr(precedences[tk_neg]);
|
|
x = iff(op==tk_sub?{tk_neg, node, NULL}:node)
|
|
case tk_not:
|
|
tok = get_tok();
|
|
x = {tk_not, expr(precedences[tk_not]), NULL}
|
|
case tk_Identifier:
|
|
x = {tk_Identifier, tok[4]}
|
|
tok = get_tok();
|
|
case tk_Integer:
|
|
x = {tk_Integer, tok[4]}
|
|
tok = get_tok();
|
|
default:
|
|
errd("Expecting a primary, found: %s\n", tkNames[op])
|
|
end switch
|
|
|
|
op = tok[3]
|
|
while narys[op]=BINARY
|
|
and precedences[op]>=p do
|
|
tok = get_tok()
|
|
x = {op, x, expr(precedences[op]+1)}
|
|
op = tok[3]
|
|
end while
|
|
return x;
|
|
end function
|
|
|
|
function paren_expr(string msg)
|
|
expect(msg, tk_LeftParen);
|
|
object t = expr(0)
|
|
expect(msg, tk_RightParen);
|
|
return t
|
|
end function
|
|
|
|
function stmt()
|
|
object t = NULL, e, s
|
|
|
|
switch tok[3] do
|
|
case tk_if:
|
|
tok = get_tok();
|
|
object condition = paren_expr("If-cond");
|
|
object ifblock = stmt();
|
|
object elseblock = NULL;
|
|
if tok[3] == tk_else then
|
|
tok = get_tok();
|
|
elseblock = stmt();
|
|
end if
|
|
t = {tk_if, condition, {tk_if, ifblock, elseblock}}
|
|
case tk_putc:
|
|
tok = get_tok();
|
|
e = paren_expr("Prtc")
|
|
t = {tk_putc, e, NULL}
|
|
expect("Putc", tk_Semicolon);
|
|
case tk_print:
|
|
tok = get_tok();
|
|
expect("Print",tk_LeftParen)
|
|
while 1 do
|
|
if tok[3] == tk_String then
|
|
e = {tk_Prints, {tk_String, tok[4]}, NULL}
|
|
tok = get_tok();
|
|
else
|
|
e = {tk_Printi, expr(0), NULL}
|
|
end if
|
|
t = {tk_Sequence, t, e}
|
|
if tok[3]!=tk_Comma then exit end if
|
|
expect("Print", tk_Comma)
|
|
end while
|
|
expect("Print", tk_RightParen);
|
|
expect("Print", tk_Semicolon);
|
|
case tk_Semicolon:
|
|
tok = get_tok();
|
|
case tk_Identifier:
|
|
object v
|
|
v = {tk_Identifier, tok[4]}
|
|
tok = get_tok();
|
|
expect("assign", tk_assign);
|
|
e = expr(0);
|
|
t = {tk_assign, v, e}
|
|
expect("assign", tk_Semicolon);
|
|
case tk_while:
|
|
tok = get_tok();
|
|
e = paren_expr("while");
|
|
s = stmt();
|
|
t = {tk_while, e, s}
|
|
case tk_LeftBrace: /* {stmt} */
|
|
expect("LeftBrace", tk_LeftBrace)
|
|
while not find(tok[3],{tk_RightBrace,tk_EOI}) do
|
|
t = {tk_Sequence, t, stmt()}
|
|
end while
|
|
expect("LeftBrace", tk_RightBrace);
|
|
break;
|
|
case tk_EOI:
|
|
break;
|
|
default:
|
|
errd("expecting start of statement, found '%s'\n", tkNames[tok[3]]);
|
|
end switch
|
|
return t
|
|
end function
|
|
|
|
global function parse()
|
|
object t = NULL
|
|
tok = get_tok()
|
|
while 1 do
|
|
object s = stmt()
|
|
if s=NULL then exit end if
|
|
t = {tk_Sequence, t, s}
|
|
end while
|
|
return t
|
|
end function
|
|
And a simple test driver for the specific task:
|