Compilerbau: Recursive Descent Parser für arithmetische Ausdrücke |
public class Token {
public static final int
Eof = 1,
Plus = 2,
Minus = 3,
Times = 4,
Div = 5,
Id = 6,
Num = 7,
Lparent = 8,
Rparent = 9,
Err = 10;
public int token;
public String text;
Token(int token,
String text) {
this.token = token;
this.text = new String(text);
}
public String toString() {
return
"token: " + token +
"\ttext: \"" + text + "\"";
}
}
|
%%
%class ExprScanner
%type Token
%function nextSymbol
%full
%line
%char
%eofval{
yy_reader.close();
return
new Token(Token.Eof, "");
%eofval}
letter=[a-zA-Z]
letterdigit=[a-zA-Z0-9]
digit=[0-9]
digits={digit}+
whitespace=[ \t\n]+
%%
"+" { return
new Token(Token.Plus, yytext());
}
"-" { return
new Token(Token.Minus, yytext());
}
"*" { return
new Token(Token.Times, yytext());
}
"/" { return
new Token(Token.Div, yytext());
}
"(" { return
new Token(Token.Lparent, yytext());
}
")" { return
new Token(Token.Rparent, yytext());
}
{letter}{letterdigit}*
{ return
new Token(Token.Id, yytext());
}
{digits}
{ return
new Token(Token.Num, yytext());
}
("--".*[\n])|{whitespace}
{ }
. { return
new Token(Token.Err, yytext());
}
|
S E $
E T E'
E' + T E'
- T E'
T F T'
T' * F T'
/ F T'
F id
num
( E )
|
import java.io.IOException;
public class RecDescentParser {
private ExprScanner s;
private Token t;
public RecDescentParser() {
s = new ExprScanner(System.in);
}
void advance() {
try {
t = s.nextSymbol();
}
catch (IOException e) {
t = new Token(Token.Eof, "");
}
}
void eat(int token) {
if ( token == t.token ) {
advance();
} else {
error();
}
}
void S() {
E();
if (t.token != Token.Eof)
error();
}
void E() {
switch (t.token) {
case Token.Id:
case Token.Num:
case Token.Lparent:
T();
Eprime();
break;
default:
error();
}
}
void Eprime() {
switch (t.token) {
case Token.Plus:
advance();
T();
Eprime();
break;
case Token.Minus:
advance();
T();
Eprime();
break;
case Token.Eof:
break;
case Token.Rparent:
break;
default:
error();
}
}
void T() {
switch (t.token) {
case Token.Id:
case Token.Num:
case Token.Lparent:
F();
Tprime();
break;
default:
error();
}
}
void Tprime() {
switch (t.token) {
case Token.Plus:
break;
case Token.Minus:
break;
case Token.Times:
advance();
F();
Tprime();
break;
case Token.Div:
advance();
F();
Tprime();
break;
case Token.Eof:
break;
case Token.Rparent:
break;
default:
error();
}
}
void F() {
switch (t.token) {
case Token.Id:
advance();
break;
case Token.Num:
advance();
break;
case Token.Lparent:
advance();
E();
eat(Token.Rparent);
break;
default:
error();
}
}
private int errcnt = 0;
void error() {
++errcnt;
System.out.println("parse error, illegal symbol \""
+ t.text + "\"");
if ( t.token != Token.Eof ) {
advance();
}
}
public void parse()
throws java.io.IOException {
advance();
S();
System.out.println("Parsing done, "
+ errcnt
+ " error(s) found");
}
public static void main(String argv[])
throws java.io.IOException {
(new RecDescentParser())
.parse();
}
}
|
JCP := $(PWD)/../../../software:.:$(CLASSPATH)
JAVA := java -classpath $(JCP)
JAVAC := javac -classpath $(JCP)
JLEX := java -classpath $(JCP) JLex.Main
lexsrc := $(shell echo *.lex)
javagen := $(lexsrc:.lex=.java)
javasrc := $(shell echo *.java)
classes := $(lexsrc:.lex=.class) $(javasrc:.java=.class)
output := Test.expr.tokens Test.expr.parse
all : examples
examples : $(javagen) $(classes) $(output)
Test.expr.tokens : Test.expr $(classes)
$(JAVA) TestExprScanner < Test.expr > Test.expr.tokens
Test.expr.parse : Test.expr $(classes)
$(JAVA) RecDescentParser < Test.expr > Test.expr.parse
%.java : %.lex
$(JLEX) $<
mv -f $<.java $*.java
%.class : %.java
$(JAVAC) $<
.SUFFIXES : .class .java .lex
clean :
rm -f $(javagen) $(classes) $(output) *~ .*~
|
Letzte Änderung: 14.02.2012 | © Prof. Dr. Uwe Schmidt |