JCup / JFlex

Werbung
JCup / JFlex
●
Compilergenerierungswerkzeuge in java
●
Gestatten linksrekursive Grammatiken
●
●
●
●
Erzeugen LALR(1)-Parser, in etwa vergleichbar mit
yacc
JFlex generiert den passenden Lexer
Letzte getestete Version: JCup 11.a, 11b
●
Liegt in Form von jar-Files vor
●
Ist nun sehr einfach in der Handhabung
Jflex: Das Installationsverzeichnis enthält
lib/jflex-1.5.0.jar
1
JCUP/JLEX Vers.11
●
●
JCup Doku und Download:
http://www2.cs.tum.edu/projects/cup/
Jflex
http://www.jflex.de/
●
●
Mit Version jflex-1.6.0 haben die
Beispielanwendungen nicht funktioniert.
Ausweg ist Verwendung von Version 1.5
http://sourceforge.net/projects/jflex/files/jflex/1.5.0/
2
Jcup/JFlex
●
http://www2.cs.tum.edu/projects/cup/
●
Folgende Files werden benötigt:
●
java-cup-11b.jar
●
java-cup-11b-runtime.jar
●
Jflex.jar bzw. jflex-1.5.0.jar
3
Bearbeitung eines Beispiels
●
java -jar jflex.jar example.lex
→ Yylex.java
●
java -jar java-cup-11b.jar < example.cup
→ parser.java sym.java
●
javac -cp java-cup-11b-runtime.jar:. parser.java
Yylex.java sym.java
→ parser.class
●
java -cp java-cup-11a-runtime.jar:. parser
4
Bestandteile cup-File
Package und import
user code
action code {: . . .:};
parser code {: . . .:};
init with {: . . .:};
scan with {:. . .:};
Symbollisten
es werden die terminalen und nicht terminalen Symbole beschrieben. Die
terminalen Symbole werden in einer Klasse sym.class abgelegt, die die
Verbindung zw. Lex und Cup herstellt.
Precedence-Declarations
Die Reihenfolge von oben nach unten bestimmt die Priorität
precedence left linksassoziativte Terminals
precedence right rechtsassoziativen Terminals
precedence nonasssoc
Regeln
5
Regelteil
●
●
Regeln werden in einer einfacher BNF ähnlichen
Notation angegeben
Werte, die mit Symbolen verbunden sind, werden
über Namen, die dem Symbol durch einen
Doppelpunkt folgen, angegeben.
●
●
●
●
expr:e
Auf diesen Bezeichner kann man in der
nachgestellten Aktion Bezug nehmen.
Der Typ ist in den Symboldeklarationen festgelegt
und muss eine Klasse sein. (Integer, String …)
Durch autoboxing und autounboxing ist eine
explizite Konvertierung nach beispielsweise int
unnötig.
6
Beispiel 1 expr, term, factor
import java_cup.runtime.*;
parser code {:
public static void main(String args[])throws Exception {
new parser(new Yylex(System.in)).parse();
}
:}
terminal SEMI, PLUS, MINUS, TIMES, DIVIDE, LPAREN, RPAREN;
terminal Integer NUMBER;
non terminal expr_list, expr_part;
non terminal Integer expr, term, fac;
7
Regelteil
Wiederholung durch
Endlosrekursion
expr_part für
Ausgabe
expr_list ::= expr_list expr_part | expr_part;
expr_part ::= expr:e {: System.out.println(" = "+e+";"); :} SEMI;
expr ::= expr:l PLUS term:r {: RESULT=l.intValue() + r.intValue(); :}
| expr:l MINUS term:r {: RESULT=l.intValue() ­ r.intValue(); :}
| term:l {: RESULT=l.intValue(); :};
term ::= term:l TIMES fac:r {: RESULT=l.intValue() * r.intValue(); :}
| term:l DIVIDE fac:r {: RESULT=l.intValue() / r.intValue(); :}
| fac:l {: RESULT=l.intValue(); :};
fac ::= MINUS NUMBER:n {: RESULT=­n; :}
| NUMBER:n {: RESULT=n; :}
| LPAREN expr:e RPAREN {: RESULT=e; :};
8
Der Lexer dazu
import java_cup.runtime.Symbol;
%%
%cup
%%
";" { return new Symbol(sym.SEMI); }
"+" { return new Symbol(sym.PLUS); }
"­" { return new Symbol(sym.MINUS); }
"*" { return new Symbol(sym.TIMES); }
Class Integer
"/" { return new Symbol(sym.DIVIDE); }
"(" { return new Symbol(sym.LPAREN); }
")" { return new Symbol(sym.RPAREN); }
[0­9]+ { return new Symbol(sym.NUMBER, new Integer(yytext())); }
[ \t\r\n\f] { /* ignore white space. */ }
. { System.err.println("Illegal character: "+yytext()); }
9
Verbindung JCup / JLex
sym.java / sym.class
//­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
// The following code was generated by CUP v0.10k
// Mon Jan 24 11:38:40 CET 2011
//­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
/** CUP generated class containing symbol constants. */
public class sym {
/* terminals */
public static final int MINUS = 4;
public static final int DIVIDE = 6;
public static final int NUMBER = 9;
public static final int SEMI = 2;
public static final int EOF = 0;
public static final int PLUS = 3;
public static final int error = 1;
public static final int RPAREN = 8;
public static final int TIMES = 5;
public static final int LPAREN = 7;
}
10
import java_cup.runtime.*;
Variante 2
parser code {:
public static void main(String args[]) throws Exception {
System.out.println("Start:");
new parser(new Yylex(System.in)).parse();
}
:}
/* Terminals (tokens returned by the scanner). */
terminal SEMI, PLUS, MINUS, TIMES, DIVIDE, MOD;
terminal UMINUS, LPAREN, RPAREN;
terminal Integer NUMBER;
/* Non­terminals */
non terminal expr_list, expr_part;
non terminal Integer expr;
/* Precedences */
precedence left PLUS, MINUS;
precedence left TIMES, DIVIDE, MOD;
precedence left UMINUS;
11
/* The grammar */
expr_list ::= expr_list expr_part | expr_part
;
expr_part ::= expr:e {: System.out.println("= " + e); :} SEMI
;
expr ::= expr:e1 PLUS expr:e2 {: RESULT = e1.intValue() + e2.intValue(); :} | expr:e1 MINUS expr:e2 {: RESULT = e1.intValue() ­ e2.intValue(); :} | expr:e1 TIMES expr:e2 {: RESULT = e1.intValue() * e2.intValue(); :} | expr:e1 DIVIDE expr:e2 {: RESULT = e1.intValue() / e2.intValue(); :} | expr:e1 MOD expr:e2 {: RESULT = e1.intValue() % e2.intValue(); :} | NUMBER:n {: RESULT = n; :} | MINUS expr:e {: RESULT = 0 ­ e.intValue(); :} //%prec MINUS
| LPAREN expr:e RPAREN {: RESULT = e; :} 12
;
j_pl0
import java_cup.runtime.*;
parser code {:
public static void main(String args[]) throws Exception {
new parser(new Yylex(System.in)).parse();
}
:}
terminal SEMI, PLUS, MINUS, TIMES, DIVIDE, LPAREN, RPAREN,OUTPUT, INPUT,
ASSIGN, GT, LT, GE, LE, EQUAL, NE, DOT, COMMA,
BEGIN, CALL, CONST, DO, ELSE, END, IF, ODD, PROC, THEN, VAR, WHILE, EOFile,
YYEOF;
terminal Integer NUM;
terminal String Ident;
non terminal program, block, blockDecl,constDecl,constList,varDecl,varList,
procDeclList,procDecl,procHead,statement,statementList, ass,if1,while1,
while2, exprList, expression, term1, term, factor, cmpOP, condition;
13
program ::= block DOT
System.exit(1);:};
block
{: System.out.println("all OK");
::= blockDecl statement {: System.out.println("Block accepted");:};
blockDecl::= constDecl varDecl procDeclList {: :};
constDecl::= CONST constList SEMI {: :}
| {: :};
constList::= constList COMMA Ident EQUAL NUM {: :}
| Ident EQUAL NUM {: :};
varDecl ::= VAR varList SEMI {: :}
| {: :};
varList ::= varList COMMA Ident {: :}
| Ident {: :};
procDeclList::= procDeclList procDecl {: :}
| {: :};
procDecl ::= procHead block SEMI {: :};
14
procHead ::= PROC Ident SEMI {: :};
statement::= BEGIN statementList END
| ass expression
| if1 statement
| while1 while2 statement
| CALL Ident
| INPUT Ident
| OUTPUT expression
{:System.out.println("Begin .. End accepted"); :}
{: :}
{: :}
{: :}
{: :}
{: :}
{:System.out.println("Output accepted");:};
statementList ::= statementList SEMI statement {:System.out.println("... epted"); :}
| statement
{:System.out.println("StaementList 2 accepted"); :};
ass
if1
::= Ident ASSIGN
::= IF condition THEN
while1 ::= WHILE
while2 ::= condition DO
{: :};
{: :};
{: :};
{: :};
15
expression::= term1 PLUS exprList
|
term1 MINUS exprList
|
term1
term1
|
::= MINUS term
term
{: :}
{: :};
exprList::=
exprList PLUS term
|
exprList MINUS term
|
term
term
::=
|
|
{:System.out.println("Expression accepted");:}
{: :}
{: :};
{:System.out.println("ExprList:ExprList + Term accepted"); :}
{:System.out.println("ExprList:ExprList - Term accepted"); :}
{:System.out.println("ExprList:Term accepted");
:};
term TIMES factor {:System.out.println("Term:Term * Fact accepted"); :}
term DIVIDE factor {:System.out.println("Term:Term / Fact accepted"); :}
factor
{:System.out.println("Term:Fact accepted");
:};
factor::=
NUM:x
{:System.out.println("Fact Fact "+x+" accepted"); :}
|
Ident :x
{:System.out.println("Fact Fact "+x+" accepted"); :}
|
LPAREN expression RPAREN {:System.out.println("Fact Fact (... ) accepted"); :};
cmpOP ::=
EQUAL
|
NE
|
LT
|
GT
|
LE
|
GE
{: :}
{: :}
{: :}
{: :}
{: :}
{: :};
condition::= ODD expression
{: :}
| expression cmpOP expression {: :};
16
Herunterladen