165 lines
4.3 KiB
Text
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]);
|
|
}
|
|
|