jacc/src/docs/resources/Calc.jacc

165 lines
4.3 KiB
Text

// To compile and run this program using jacc and Sun's JDK:
//
// In a directory containing only the file Calc.jacc:
//
// jacc Calc.jacc
// javac *.java
// java CalcParser
// ... enter arithmetic expressions ... hit EOF to terminate
//
%{
abstract class Expr {
abstract int eval();
}
class IntExpr extends Expr {
private int value;
IntExpr(int value) { this.value = value; }
int eval() { return value; }
}
abstract class BinExpr extends Expr {
protected Expr left, right;
BinExpr(Expr left, Expr right) {
this.left = left; this.right = right;
}
}
class AddExpr extends BinExpr {
AddExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() + right.eval(); }
}
class SubExpr extends BinExpr {
SubExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() - right.eval(); }
}
class MulExpr extends BinExpr {
MulExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() * right.eval(); }
}
class DivExpr extends BinExpr {
DivExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() / right.eval(); }
}
class CalcLexer implements CalcTokens {
private int c = ' ';
/** Read a single input character from standard input.
*/
private void nextChar() {
if (c>=0) {
try {
c = System.in.read();
} catch (Exception e) {
c = (-1);
}
}
}
private int token;
private IntExpr yylval;
/** Read the next token and return the
* corresponding integer code.
*/
int nextToken() {
for (;;) {
// Skip whitespace
while (c==' ' || c=='\n' || c=='\t' || c=='\r') {
nextChar();
}
if (c<0) {
return (token=ENDINPUT);
}
switch (c) {
case '+' : nextChar();
return token='+';
case '-' : nextChar();
return token='-';
case '*' : nextChar();
return token='*';
case '/' : nextChar();
return token='/';
case '(' : nextChar();
return token='(';
case ')' : nextChar();
return token=')';
case ';' : nextChar();
return token=';';
default : if (Character.isDigit((char)c)) {
int n = 0;
do {
n = 10*n + (c - '0');
nextChar();
} while (Character.isDigit((char)c));
yylval = new IntExpr(n);
return token=INTEGER;
} else {
Main.error("Illegal character "+c);
nextChar();
}
}
}
}
/** Return the token code for the current lexeme.
*/
int getToken() {
return token;
}
/** Return the semantic value for the current lexeme.
*/
IntExpr getSemantic() {
return yylval;
}
}
class Main {
public static void main(String[] args) {
CalcLexer lexer = new CalcLexer();
lexer.nextToken();
CalcParser parser = new CalcParser(lexer);
parser.parse();
}
static void error(String msg) {
System.out.println("ERROR: " + msg);
System.exit(1);
}
}
%}
%semantic Expr
%token '+' '-' '*' '/' '(' ')' ';' INTEGER
%left '+' '-'
%left '*' '/'
%%
prog : prog ';' expr { System.out.println($3.eval()); }
| expr { System.out.println($1.eval()); }
;
expr : expr '+' expr { $$ = new AddExpr($1, $3); }
| expr '-' expr { $$ = new SubExpr($1, $3); }
| expr '*' expr { $$ = new MulExpr($1, $3); }
| expr '/' expr { $$ = new DivExpr($1, $3); }
| '(' expr ')' { $$ = $2; }
| INTEGER { $$ = $1; }
;
%%
private CalcLexer lexer;
CalcParser(CalcLexer lexer) { this.lexer = lexer; }
private void yyerror(String msg) {
Main.error(yyerrno<0 ? msg : yyerrmsgs[yyerrno]);
}