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 $