[12 - Tree Grammar] Add type check
This commit is contained in:
@@ -90,6 +90,8 @@ public class AntlrXCompiler {
|
||||
// Type check
|
||||
XTypeCheck typeCheck = new XTypeCheck(new CommonTreeNodeStream(xTreeAdaptor, tree));
|
||||
CommonTree typeCheckedTree = typeCheck.program().getTree();
|
||||
|
||||
|
||||
|
||||
// X to Java
|
||||
XtoJava javaConverter = new XtoJava(new CommonTreeNodeStream(xTreeAdaptor, typeCheckedTree));
|
||||
|
||||
@@ -60,7 +60,7 @@ decl: ID ':' (type='int' | type='float' | type='string') ';' -> ^(DECL ID
|
||||
decllist: decl* -> ^(DECLLIST decl*);
|
||||
|
||||
// Ausdr<64>cke
|
||||
expr: multexpr (('+'^ | '-'^) multexpr)*;
|
||||
expr: multexpr (('+'^ | '-'^) multexpr)*;
|
||||
multexpr: simpleexpr (('*'^ | '/'^) simpleexpr)*;
|
||||
simpleexpr: '('! expr ')'!
|
||||
| INTCONST | '-' INTCONST -> ^(UMINUS INTCONST)
|
||||
|
||||
@@ -18,7 +18,7 @@ options {
|
||||
private String addString(String first, String last) {
|
||||
return first.substring(0, first.length()-1)+last.substring(1);
|
||||
}
|
||||
|
||||
|
||||
private String opInt(String first, String last, char op) {
|
||||
int firstValue = 0;
|
||||
int lastValue = 0;
|
||||
@@ -36,7 +36,7 @@ options {
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String opFloat(String first, String last, char op) {
|
||||
double firstValue = 0.0;
|
||||
double lastValue = 0.0;
|
||||
@@ -54,7 +54,7 @@ options {
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
/* **********************************************
|
||||
* Duale Hochschule Baden-Württemberg Karlsruhe
|
||||
* Prof. Dr. Jörn Eisenbiegler
|
||||
*
|
||||
* Vorlesung Übersetzerbau
|
||||
* Praxis ANTLR-Übersetzer für X
|
||||
* - Typ-Prüfung
|
||||
*
|
||||
* **********************************************
|
||||
*/
|
||||
|
||||
tree grammar XTypeCheck;
|
||||
|
||||
options {
|
||||
@@ -23,108 +12,105 @@ tokens{
|
||||
}
|
||||
|
||||
@header {
|
||||
package de.dhbw.compiler.antlrxcompiler;
|
||||
package de.dhbw.compiler.antlrxcompiler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashMap;
|
||||
}
|
||||
|
||||
@members {
|
||||
|
||||
private SymbolTable symbols = SymbolTable.getInstance();
|
||||
private SymbolTable symbols = SymbolTable.getInstance();
|
||||
|
||||
private void error(XTree tree, String message) {
|
||||
System.err.println("Error at "+tree.getLine()+","+tree.getCharPositionInLine()+": "+message);
|
||||
}
|
||||
private void logError(XTree tree, String message) {
|
||||
System.err.println(message + "\n\t" + tree);
|
||||
}
|
||||
}
|
||||
|
||||
// Deklarationen
|
||||
decl:
|
||||
^(DECL ID 'int' r='read'? p='print'?)
|
||||
{ symbols.put($ID.text, new Symbol($ID.text, XType.IntType, $r!=null, $p!=null)); }
|
||||
| ^(DECL ID 'float' r='read'? p='print'?)
|
||||
{ symbols.put($ID.text, new Symbol($ID.text, XType.FloatType, $r!=null, $p!=null)); }
|
||||
| ^(DECL ID 'string' r='read'? p='print'?)
|
||||
{ symbols.put($ID.text, new Symbol($ID.text, XType.StringType, $r!=null, $p!=null)); } ;
|
||||
^(DECL ID type='int' read='read'? print='print'?)
|
||||
{ symbols.put($ID.text, new Symbol($ID.text, XType.IntType, ($read != null), ($print != null))); }
|
||||
| ^(DECL ID type='float' read='read'? print='print'?)
|
||||
{ symbols.put($ID.text, new Symbol($ID.text, XType.FloatType, ($read != null), ($print != null))); }
|
||||
| ^(DECL ID type='string' read='read'? print='print'?)
|
||||
{ symbols.put($ID.text, new Symbol($ID.text, XType.StringType, ($read != null), ($print != null))); }
|
||||
;
|
||||
|
||||
decllist: ^(DECLLIST decl*);
|
||||
decllist: ^(DECLLIST decl*);
|
||||
|
||||
// Expr und Cond!!
|
||||
expr:
|
||||
|
||||
^(op=('+' | '-' | '/' | '*') l=expr r=expr)
|
||||
{
|
||||
if ($l.tree.exprType==XType.IntType && $r.tree.exprType==XType.IntType) {
|
||||
$op.tree.exprType=XType.IntType;
|
||||
} else if (($l.tree.exprType==XType.IntType || $l.tree.exprType==XType.FloatType) &&
|
||||
($r.tree.exprType==XType.IntType || $r.tree.exprType==XType.FloatType)) {
|
||||
$op.tree.exprType=XType.FloatType;
|
||||
} else if ($l.tree.exprType==XType.StringType && $r.tree.exprType==XType.StringType && $op.type==PLUS) {
|
||||
$op.tree.exprType=XType.StringType;
|
||||
} else {
|
||||
$op.tree.exprType=XType.InvalidType;
|
||||
error($op,$op.text+" is not valid for operands "+$l.tree.exprType+" and "+$r.tree.exprType+".");
|
||||
^(op=('+' | '-' | '/' | '*') left=expr right=expr)
|
||||
{
|
||||
if ($left.tree.exprType == XType.IntType && $right.tree.exprType == XType.IntType) {
|
||||
$op.tree.exprType = XType.IntType;
|
||||
} else if (($left.tree.exprType == XType.FloatType || $left.tree.exprType == XType.IntType) &&
|
||||
($right.tree.exprType == XType.FloatType || $right.tree.exprType == XType.IntType)) {
|
||||
$op.tree.exprType = XType.FloatType;
|
||||
} else if ($left.tree.exprType == XType.StringType && $right.tree.exprType == XType.StringType && $op.type == PLUS) {
|
||||
$op.tree.exprType = XType.StringType;
|
||||
} else {
|
||||
$op.tree.exprType = XType.InvalidType;
|
||||
logError($op, "Invalid operator '" + $op.text + "' for '" + $left.tree.exprType + "' and '" + $right.tree.exprType + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
| ^(op=UMINUS e=expr) { $op.tree.exprType = $e.tree.exprType; }
|
||||
| INTCONST { $INTCONST.tree.exprType = XType.IntType; }
|
||||
| FLOATCONST { $FLOATCONST.tree.exprType = XType.FloatType; }
|
||||
| STRINGCONST { $STRINGCONST.tree.exprType = XType.StringType; }
|
||||
| ID {
|
||||
if (symbols.containsKey($ID.text)) {
|
||||
$ID.tree.exprType = symbols.get($ID.text).type;
|
||||
} else {
|
||||
$ID.tree.exprType = XType.InvalidType;
|
||||
logError($ID, "'" + $ID.text + "' is not defined.");
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
| ^(op=UMINUS e=expr)
|
||||
{
|
||||
$op.tree.exprType=$e.tree.exprType;
|
||||
}
|
||||
assignstat:
|
||||
^(op=':=' ID e=expr)
|
||||
{
|
||||
if (!symbols.containsKey($ID.text)) {
|
||||
$ID.tree.exprType = XType.InvalidType;
|
||||
$op.tree.exprType = XType.InvalidType;
|
||||
logError($ID, "Undeclared var '" + $ID.text + "'");
|
||||
} else {
|
||||
$ID.tree.exprType = symbols.get($ID.text).type;
|
||||
|
||||
| INTCONST { $INTCONST.tree.exprType=XType.IntType; }
|
||||
| FLOATCONST { $FLOATCONST.tree.exprType=XType.FloatType; }
|
||||
| STRINGCONST { $STRINGCONST.tree.exprType=XType.StringType; }
|
||||
| ID { if (!symbols.containsKey($ID.text)) {
|
||||
$ID.tree.exprType=XType.InvalidType;
|
||||
error($ID,"Variable "+$ID.text+" is not defined.");
|
||||
} else {
|
||||
$ID.tree.exprType=symbols.get($ID.text).type;
|
||||
}
|
||||
};
|
||||
|
||||
// Zuweisungen
|
||||
assignstat: ^(op=':=' ID expr)
|
||||
{ if (!symbols.containsKey($ID.text)) {
|
||||
$ID.tree.exprType=XType.InvalidType;
|
||||
$op.tree.exprType=XType.InvalidType;
|
||||
error($ID,"Variable "+$ID.text+" is not defined.");
|
||||
} else {
|
||||
$ID.tree.exprType=symbols.get($ID.text).type;
|
||||
if ($ID.tree.exprType==XType.FloatType && $expr.tree.exprType==XType.IntType) {
|
||||
$op.tree.exprType=XType.FloatType;
|
||||
} else if ($ID.tree.exprType!=$expr.tree.exprType) {
|
||||
$op.tree.exprType=XType.InvalidType;
|
||||
error($op,"An expression of type "+$expr.tree.exprType+
|
||||
" cannot be assigned to a variable of type "+$ID.tree.exprType+".");
|
||||
} else {
|
||||
$op.tree.exprType=$ID.tree.exprType;
|
||||
}
|
||||
// float <- int
|
||||
if ($ID.tree.exprType == XType.FloatType && $e.tree.exprType == XType.IntType) {
|
||||
$op.tree.exprType = XType.FloatType;
|
||||
} else if ($ID.tree.exprType != $expr.tree.exprType) {
|
||||
$op.tree.exprType = XType.InvalidType;
|
||||
logError($op, "Cannot assign <" + $expr.tree.exprType + "> to <" + $ID.tree.exprType + ">");
|
||||
} else {
|
||||
$op.tree.exprType = $ID.tree.exprType;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
;
|
||||
|
||||
// Bedingungen
|
||||
cond: ^(op=('<' |'>' |'=') l=expr r=expr)
|
||||
{ if ($l.tree.exprType==XType.StringType || $r.tree.exprType==XType.StringType) {
|
||||
error($op,$op.text+" is not valid for string operands.");
|
||||
} else if ($l.tree.exprType==XType.IntType && $r.tree.exprType==XType.IntType) {
|
||||
$op.tree.exprType=XType.IntType;
|
||||
} else {
|
||||
$op.tree.exprType=XType.FloatType;
|
||||
cond:
|
||||
^(op=('<' | '>' | '=') left=expr right=expr)
|
||||
{
|
||||
if ($left.tree.exprType == XType.StringType || $right.tree.exprType == XType.StringType) {
|
||||
$op.tree.exprType = XType.InvalidType;
|
||||
logError($op, "Cannot use operator '" + $op.text + "' on '" + $left.text + "' and '" + $right.text + "'");
|
||||
} else if ($left.tree.exprType == XType.IntType && $right.tree.exprType == XType.IntType) {
|
||||
$op.tree.exprType = XType.IntType;
|
||||
} else {
|
||||
$op.tree.exprType = XType.FloatType;
|
||||
}
|
||||
}
|
||||
};
|
||||
;
|
||||
|
||||
// Bedingte Zuweisung
|
||||
condstat: ^('if' cond stat stat?);
|
||||
condstat: ^(op='if' cond stat stat?);
|
||||
|
||||
// Schleifen
|
||||
whilestat: ^('while' cond stat);
|
||||
forstat: ^('for' assignstat cond assignstat stat);
|
||||
whilestat: ^('while' cond stat);
|
||||
forstat: ^('for' assignstat cond assignstat stat);
|
||||
|
||||
// Anweisungen
|
||||
stat: assignstat | condstat | whilestat | forstat | statlist;
|
||||
stat: assignstat | condstat | whilestat | forstat | statlist;
|
||||
|
||||
statlist: ^(STATLIST stat*);
|
||||
statlist: ^(STATLIST stat*);
|
||||
|
||||
// Programme
|
||||
program: { symbols.clear(); } ^('program' ID decllist statlist);
|
||||
program: { symbols.clear(); } ^('program' ID decllist statlist);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,7 +40,6 @@ STRINGCONST=16
|
||||
UMINUS=17
|
||||
WS=18
|
||||
ZERO=19
|
||||
T__46=46
|
||||
PLUS=23
|
||||
'('=20
|
||||
')'=21
|
||||
@@ -68,4 +67,3 @@ PLUS=23
|
||||
'string'=43
|
||||
'then'=44
|
||||
'while'=45
|
||||
'todo'=46
|
||||
|
||||
@@ -16,21 +16,15 @@ import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import de.dhbw.compiler.antlrxcompiler.*;
|
||||
import org.antlr.runtime.ANTLRInputStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
||||
|
||||
import de.dhbw.compiler.antlrxcompiler.XLexer;
|
||||
import de.dhbw.compiler.antlrxcompiler.XOptimizer;
|
||||
import de.dhbw.compiler.antlrxcompiler.XParser;
|
||||
import de.dhbw.compiler.antlrxcompiler.XTree;
|
||||
import de.dhbw.compiler.antlrxcompiler.XTreeAdaptor;
|
||||
import de.dhbw.compiler.antlrxcompiler.XTypeCheck;
|
||||
|
||||
public abstract class OptimizerTest {
|
||||
|
||||
protected void testTypeCheckTree(String in, String expected) throws Exception {
|
||||
XTreeAdaptor xTreeAdaptor = new XTreeAdaptor();
|
||||
XTreeAdaptor xTreeAdaptor = new XTreeAdaptor();
|
||||
ANTLRInputStream input = new ANTLRInputStream(new ByteArrayInputStream(in.getBytes()));
|
||||
XLexer scanner = new XLexer(input);
|
||||
CommonTokenStream tokens = new CommonTokenStream(scanner);
|
||||
|
||||
@@ -16,6 +16,7 @@ import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import de.dhbw.compiler.antlrxcompiler.XTreeAdaptor;
|
||||
import org.antlr.runtime.ANTLRInputStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.runtime.ParserRuleReturnScope;
|
||||
@@ -23,7 +24,6 @@ import org.antlr.runtime.tree.CommonTree;
|
||||
|
||||
import de.dhbw.compiler.antlrxcompiler.XLexer;
|
||||
import de.dhbw.compiler.antlrxcompiler.XParser;
|
||||
import de.dhbw.compiler.antlrxcompiler.XTreeAdaptor;
|
||||
|
||||
public abstract class ParseTreeTest {
|
||||
|
||||
|
||||
@@ -16,20 +16,15 @@ import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import de.dhbw.compiler.antlrxcompiler.*;
|
||||
import org.antlr.runtime.ANTLRInputStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
||||
|
||||
import de.dhbw.compiler.antlrxcompiler.XLexer;
|
||||
import de.dhbw.compiler.antlrxcompiler.XParser;
|
||||
import de.dhbw.compiler.antlrxcompiler.XTree;
|
||||
import de.dhbw.compiler.antlrxcompiler.XTreeAdaptor;
|
||||
import de.dhbw.compiler.antlrxcompiler.XTypeCheck;
|
||||
|
||||
public abstract class TypeCheckTest {
|
||||
|
||||
protected void testTypeCheckTree(String in, String expected) throws Exception {
|
||||
XTreeAdaptor xTreeAdaptor = new XTreeAdaptor();
|
||||
XTreeAdaptor xTreeAdaptor = new XTreeAdaptor();
|
||||
ANTLRInputStream input = new ANTLRInputStream(new ByteArrayInputStream(in.getBytes()));
|
||||
XLexer scanner = new XLexer(input);
|
||||
CommonTokenStream tokens = new CommonTokenStream(scanner);
|
||||
|
||||
Reference in New Issue
Block a user