ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/disk/prep/calc.tab.b/
implement Calc;
#line 2 "calc.y"
#
# from Plan 9. subject to the Lucent Public License 1.02
#
include "sys.m";
sys: Sys;
include "draw.m";
NUM,
DOT,
DOLLAR,
ADD,
SUB,
MUL,
DIV,
FRAC,
NEG: con iota;
Exp: adt {
ty: int;
n: big;
e1, e2: cyclic ref Exp;
};
YYSTYPE: adt {
e: ref Exp;
};
yyexp: ref Exp;
YYLEX: adt {
s: string;
n: int;
lval: YYSTYPE;
lex: fn(l: self ref YYLEX): int;
error: fn(l: self ref YYLEX, msg: string);
};
Calc: module {
parseexpr: fn(s: string, a, b, c: big): (big, string);
init: fn(nil: ref Draw->Context, nil: list of string);
NUMBER: con 57346;
UNARYMINUS: con 57347;
};
YYEOFCODE: con 1;
YYERRCODE: con 2;
YYMAXDEPTH: con 200;
#line 68 "calc.y"
mkNUM(x: big): ref Exp
{
return ref Exp(NUM, x, nil, nil);
}
mkOP(ty: int, e1: ref Exp, e2: ref Exp): ref Exp
{
return ref Exp(ty, big 0, e1, e2);
}
dot, size, dollar: big;
YYLEX.lex(l: self ref YYLEX): int
{
while(l.n < len l.s && isspace(l.s[l.n]))
l.n++;
if(l.n == len l.s)
return -1;
if(isdigit(l.s[l.n])){
for(o := l.n; o < len l.s && isdigit(l.s[o]); o++)
;
l.lval.e = mkNUM(big l.s[l.n:o]);
l.n = o;
return NUMBER;
}
return l.s[l.n++];
}
isdigit(c: int): int
{
return c >= '0' && c <= '9';
}
isspace(c: int): int
{
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f';
}
YYLEX.error(nil: self ref YYLEX, s: string)
{
raise s;
}
eval(e: ref Exp): big
{
case e.ty {
NUM =>
return e.n;
DOT =>
return dot;
DOLLAR =>
return dollar;
ADD =>
return eval(e.e1)+eval(e.e2);
SUB =>
return eval(e.e1)-eval(e.e2);
MUL =>
return eval(e.e1)*eval(e.e2);
DIV =>
i := eval(e.e2);
if(i == big 0)
raise "division by zero";
return eval(e.e1)/i;
FRAC =>
return (size*eval(e.e1))/big 100;
NEG =>
return -eval(e.e1);
* =>
raise "invalid operator";
}
}
parseexpr(s: string, xdot: big, xdollar: big, xsize: big): (big, string)
{
dot = xdot;
size = xsize;
dollar = xdollar;
l := ref YYLEX(s, 0, YYSTYPE(nil));
{
yyparse(l);
if(yyexp == nil)
return (big 0, "nil yylval?");
return (eval(yyexp), nil);
}exception e{
"*" =>
return (big 0, e);
}
}
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
while((args = tl args) != nil){
(r, e) := parseexpr(hd args, big 1000, big 1000000, big 1000000);
if(e != nil)
sys->print("%s\n", e);
else
sys->print("%bd\n", r);
}
}
yyexca := array[] of {-1, 1,
1, -1,
-2, 0,
};
YYNPROD: con 12;
YYPRIVATE: con 57344;
yytoknames: array of string;
yystates: array of string;
yydebug: con 0;
YYLAST: con 30;
yyact := array[] of {
8, 9, 10, 11, 3, 12, 7, 2, 12, 19,
1, 4, 5, 6, 13, 14, 15, 16, 17, 18,
8, 9, 10, 11, 0, 12, 10, 11, 0, 12,
};
yypact := array[] of {
0,-1000, 15,-1000,-1000,-1000, 0, 0, 0, 0,
0, 0,-1000, -5,-1000, 19, 19, -2, -2,-1000,
};
yypgo := array[] of {
0, 7, 10,
};
yyr1 := array[] of {
0, 2, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1,
};
yyr2 := array[] of {
0, 1, 1, 1, 1, 3, 3, 3, 3, 3,
2, 2,
};
yychk := array[] of {
-1000, -2, -1, 4, 11, 12, 13, 6, 5, 6,
7, 8, 10, -1, -1, -1, -1, -1, -1, 14,
};
yydef := array[] of {
0, -2, 1, 2, 3, 4, 0, 0, 0, 0,
0, 0, 10, 0, 11, 6, 7, 8, 9, 5,
};
yytok1 := array[] of {
1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 12, 10, 3, 3,
13, 14, 7, 5, 3, 6, 11, 8,
};
yytok2 := array[] of {
2, 3, 4, 9,
};
yytok3 := array[] of {
0
};
YYSys: module
{
FD: adt
{
fd: int;
};
fildes: fn(fd: int): ref FD;
fprint: fn(fd: ref FD, s: string, *): int;
};
yysys: YYSys;
yystderr: ref YYSys->FD;
YYFLAG: con -1000;
# parser for yacc output
yytokname(yyc: int): string
{
if(yyc > 0 && yyc <= len yytoknames && yytoknames[yyc-1] != nil)
return yytoknames[yyc-1];
return "<"+string yyc+">";
}
yystatname(yys: int): string
{
if(yys >= 0 && yys < len yystates && yystates[yys] != nil)
return yystates[yys];
return "<"+string yys+">\n";
}
yylex1(yylex: ref YYLEX): int
{
c : int;
yychar := yylex.lex();
if(yychar <= 0)
c = yytok1[0];
else if(yychar < len yytok1)
c = yytok1[yychar];
else if(yychar >= YYPRIVATE && yychar < YYPRIVATE+len yytok2)
c = yytok2[yychar-YYPRIVATE];
else{
n := len yytok3;
c = 0;
for(i := 0; i < n; i+=2) {
if(yytok3[i+0] == yychar) {
c = yytok3[i+1];
break;
}
}
if(c == 0)
c = yytok2[1]; # unknown char
}
if(yydebug >= 3)
yysys->fprint(yystderr, "lex %.4ux %s\n", yychar, yytokname(c));
return c;
}
YYS: adt
{
yyv: YYSTYPE;
yys: int;
};
yyparse(yylex: ref YYLEX): int
{
if(yydebug >= 1 && yysys == nil) {
yysys = load YYSys "$Sys";
yystderr = yysys->fildes(2);
}
yys := array[YYMAXDEPTH] of YYS;
yyval: YYSTYPE;
yystate := 0;
yychar := -1;
yynerrs := 0; # number of errors
yyerrflag := 0; # error recovery flag
yyp := -1;
yyn := 0;
yystack:
for(;;){
# put a state and value onto the stack
if(yydebug >= 4)
yysys->fprint(yystderr, "char %s in %s", yytokname(yychar), yystatname(yystate));
yyp++;
if(yyp >= len yys)
yys = (array[len yys * 2] of YYS)[0:] = yys;
yys[yyp].yys = yystate;
yys[yyp].yyv = yyval;
for(;;){
yyn = yypact[yystate];
if(yyn > YYFLAG) { # simple state
if(yychar < 0)
yychar = yylex1(yylex);
yyn += yychar;
if(yyn >= 0 && yyn < YYLAST) {
yyn = yyact[yyn];
if(yychk[yyn] == yychar) { # valid shift
yychar = -1;
yyp++;
if(yyp >= len yys)
yys = (array[len yys * 2] of YYS)[0:] = yys;
yystate = yyn;
yys[yyp].yys = yystate;
yys[yyp].yyv = yylex.lval;
if(yyerrflag > 0)
yyerrflag--;
if(yydebug >= 4)
yysys->fprint(yystderr, "char %s in %s", yytokname(yychar), yystatname(yystate));
continue;
}
}
}
# default state action
yyn = yydef[yystate];
if(yyn == -2) {
if(yychar < 0)
yychar = yylex1(yylex);
# look through exception table
for(yyxi:=0;; yyxi+=2)
if(yyexca[yyxi] == -1 && yyexca[yyxi+1] == yystate)
break;
for(yyxi += 2;; yyxi += 2) {
yyn = yyexca[yyxi];
if(yyn < 0 || yyn == yychar)
break;
}
yyn = yyexca[yyxi+1];
if(yyn < 0){
yyn = 0;
break yystack;
}
}
if(yyn != 0)
break;
# error ... attempt to resume parsing
if(yyerrflag == 0) { # brand new error
yylex.error("syntax error");
yynerrs++;
if(yydebug >= 1) {
yysys->fprint(yystderr, "%s", yystatname(yystate));
yysys->fprint(yystderr, "saw %s\n", yytokname(yychar));
}
}
if(yyerrflag != 3) { # incompletely recovered error ... try again
yyerrflag = 3;
# find a state where "error" is a legal shift action
while(yyp >= 0) {
yyn = yypact[yys[yyp].yys] + YYERRCODE;
if(yyn >= 0 && yyn < YYLAST) {
yystate = yyact[yyn]; # simulate a shift of "error"
if(yychk[yystate] == YYERRCODE)
continue yystack;
}
# the current yyp has no shift onn "error", pop stack
if(yydebug >= 2)
yysys->fprint(yystderr, "error recovery pops state %d, uncovers %d\n",
yys[yyp].yys, yys[yyp-1].yys );
yyp--;
}
# there is no state on the stack with an error shift ... abort
yyn = 1;
break yystack;
}
# no shift yet; clobber input char
if(yydebug >= 2)
yysys->fprint(yystderr, "error recovery discards %s\n", yytokname(yychar));
if(yychar == YYEOFCODE) {
yyn = 1;
break yystack;
}
yychar = -1;
# try again in the same state
}
# reduction by production yyn
if(yydebug >= 2)
yysys->fprint(yystderr, "reduce %d in:\n\t%s", yyn, yystatname(yystate));
yypt := yyp;
yyp -= yyr2[yyn];
# yyval = yys[yyp+1].yyv;
yym := yyn;
# consult goto table to find next state
yyn = yyr1[yyn];
yyg := yypgo[yyn];
yyj := yyg + yys[yyp].yys + 1;
if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
yystate = yyact[yyg];
case yym {
1=>
#line 54 "calc.y"
{ yyexp = yys[yypt-0].yyv.e; return 0; }
2=>
yyval.e = yys[yyp+1].yyv.e;
3=>
#line 57 "calc.y"
{ yyval.e = mkOP(DOT, nil, nil); }
4=>
#line 58 "calc.y"
{ yyval.e = mkOP(DOLLAR, nil, nil); }
5=>
#line 59 "calc.y"
{ yyval.e = yys[yypt-1].yyv.e; }
6=>
#line 60 "calc.y"
{ yyval.e = mkOP(ADD, yys[yypt-2].yyv.e, yys[yypt-0].yyv.e); }
7=>
#line 61 "calc.y"
{ yyval.e = mkOP(SUB, yys[yypt-2].yyv.e, yys[yypt-0].yyv.e); }
8=>
#line 62 "calc.y"
{ yyval.e = mkOP(MUL, yys[yypt-2].yyv.e, yys[yypt-0].yyv.e); }
9=>
#line 63 "calc.y"
{ yyval.e = mkOP(DIV, yys[yypt-2].yyv.e, yys[yypt-0].yyv.e); }
10=>
#line 64 "calc.y"
{ yyval.e = mkOP(FRAC, yys[yypt-1].yyv.e, nil); }
11=>
#line 65 "calc.y"
{ yyval.e = mkOP(NEG, yys[yypt-0].yyv.e, nil); }
}
}
return yyn;
}