parserlib: calculator example
The following example (located in parserlib/parserlib/test )
shows three parsers for a calculator grammar.
CalcParse.T simply checks the grammar,
CalcParseStd.T evaluates the expressions, and
CalcParseTree.T prints the expressions in prefix form.
Calc.t (used to generate CalcTok.i3 )
%char [+\-*/()\n]
%const ASSIGN ERROR
%token LETTER DIGIT
Calc.l (used to generate CalcLex.i3 )
ASSIGN ":="
LETTER [a-zA-Z_]
DIGIT [0-9]
char {%char}
skip [ \t]*
ERROR [^]
Calc.y (used to generate CalcParse.i3 )
%left '+' '-'
%left '*' '/'
%nonassoc uminus_expr
%start list
list:
empty
cons list stat '\n'
stat:
eval expr
assign LETTER ASSIGN expr
expr:
paren '(' expr ')'
add expr '+' expr
sub expr '-' expr
mul expr '*' expr
div expr '/' expr
uminus '-' expr
ident LETTER
num number
number:
digit DIGIT
cons number DIGIT
CalcTokStd .e (used to generate CalcTokStd .i3 )
%source Calc.t
%import CalcTok
LETTER: {val: CHAR}
DIGIT: {val: INTEGER}
CalcLexStd .e (used to generate CalcLexStd .i3 )
%source Calc.t Calc.l
%import CalcTokStd CalcLex
%module{
IMPORT Text;
}
LETTER {$R LETTER{$$ := Text.GetChar($,0)}}
DIGIT {$R DIGIT{$$ := ORD(Text.GetChar($,0)) - ORD('0')}}
CalcParseStd .e (used to generate CalcParseStd .i3 )
%source Calc.t Calc.y
%import CalcTokStd CalcParse
%private{
regs: ARRAY ['a'..'z'] OF INTEGER;
base: INTEGER;
}
%module{
IMPORT Fmt;
IMPORT Wr, Thread;
FROM Stdio IMPORT stdout;
<* FATAL Wr.Failure, Thread.Alerted *>
}
stat:
eval {Wr.PutText(stdout, Fmt.Int($1) & "\n");Wr.Flush(stdout)}
assign {self.regs[$1] := $2}
expr: {val: INTEGER}
paren {$$.discard(); result := $1.detach()}
add {$$ := $1 + $2}
sub {$$ := $1 - $2}
mul {$$ := $1 * $2}
div {$$ := $1 DIV $2}
uminus {$$ := -$1}
ident {$$ := self.regs[$1]}
num {$$ := $1}
number: {val: INTEGER}
digit {$$ := $1;IF $1 = 0 THEN self.base:=8 ELSE self.base:=10 END}
cons {$$ := self.base * $1 + $2}
CalcParseTree .e (used to generate CalcParseTree .i3 )
%source Calc.t Calc.y
%import CalcTokStd CalcParseStd
stat:
eval {Explain($1.detach())}
assign{Wr.PutText(stdout, Fmt.Char($1) & " := " &
Fmt.Int($2) & "\n");Explain($2.detach())}
expr: {e1, e2: expr; kind: CHAR := 'N'}
add {$$.e1 := $1.detach(); $$.e2 := $2.detach(); $$.kind := '+'}
sub {$$.e1 := $1.detach(); $$.e2 := $2.detach(); $$.kind := '-'}
mul {$$.e1 := $1.detach(); $$.e2 := $2.detach(); $$.kind := '*'}
div {$$.e1 := $1.detach(); $$.e2 := $2.detach(); $$.kind := '/'}
uminus {$$.e1 := $1.detach(); $$.kind := 'U'}
ident {$$.kind := $1}
%module{
IMPORT Fmt;
IMPORT Wr, Thread;
FROM Stdio IMPORT stdout;
<* FATAL Wr.Failure, Thread.Alerted *>
PROCEDURE Format(e: expr): TEXT =
BEGIN
CASE e.kind OF
| 'U' => RETURN "(uminus " & Format(e.e1) & ")";
| '+','-','*','/' =>
RETURN "(" & Fmt.Char(e.kind) & " " &
Format(e.e1) & " " & Format(e.e2) & ")";
| 'N' => RETURN Fmt.Int(e.val);
ELSE
RETURN Fmt.Char(e.kind);
END;
END Format;
PROCEDURE Explain(e: expr) =
BEGIN
Wr.PutText(stdout, " = " & Format(e) & "\n\n");
Wr.Flush(stdout);
END Explain;
}
Main.m3
MODULE Main;
IMPORT Wr, Fmt, Thread;
IMPORT SeekRd;
IMPORT RTBrand;
IMPORT CalcLex, CalcParse;
IMPORT CalcLexStd, CalcParseStd;
IMPORT CalcParseTree;
IMPORT Stdio;
FROM Stdio IMPORT stdout;
<* FATAL Wr.Failure, Thread.Alerted, RTBrand.NotBranded *>
PROCEDURE TestCalc(lex: CalcLex.T; parse: CalcParse.T) =
VAR
rd := SeekRd.Stdin();
lb := RTBrand.Get(lex);
pb := RTBrand.Get(parse);
BEGIN
EVAL lex.setRd(rd);
Wr.PutText(stdout, "Testing " & lb & " & " & pb & "\n");
Wr.Flush(stdout);
parse.setLex(lex).parse().discard();
Wr.PutText(stdout, "undiscarded tokens: " & Fmt.Int(lex.purge()) & "\n");
Wr.PutText(stdout, "undiscarded others: " & Fmt.Int(parse.purge()) & "\n");
Wr.Flush(stdout);
END TestCalc;
BEGIN
TestCalc(NEW(CalcLex.T), NEW(CalcParse.T));
TestCalc(NEW(CalcLexStd.T), NEW(CalcParseStd.T));
TestCalc(NEW(CalcLexStd.T), NEW(CalcParseTree.T));
END Main.
m3makefile
import("cit_util")
import("parserlib")
token("Calc")
lexer("Calc", "Calc")
parser("Calc", "Calc")
extended("CalcTokStd")
extended("CalcLexStd")
extended("CalcParseStd")
extended("CalcParseTree")
implementation("Main")
program("test")
[ parserlib page ] [ ktok ] [ klex ] [ kyacc ] [ kext ] [ m3build ]
$Id: calc.html,v 1.3 2001/01/08 07:08:02 kp Exp $