Commit da8d5c80 by Tianqi Yang

init(global): Initial commit

parent 94895969
/bin/
/result/
/.settings/
/src/decaf/frontend/Lexer.java
/src/decaf/frontend/Parser.java
/src/decaf/frontend/Parser.output
/unittest/*/output/*
!/unittest/*/output/.gitkeep
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
Ant build file for Decaf Compiler.
author: Zhang Duo
date: Aug 23, 2007
DCST, Tsinghua University
-->
<project name="decaf" default="4 pack">
<!-- 设置各种属性 -->
<property name="src.dir" value="src" />
<property name="result.dir" value="result" />
<property name="bin.dir" value="${result.dir}/bin" />
<property name="doc.dir" value="${result.dir}/doc" />
<property name="jflex.jar" value="tools/jflex/JFlex.jar" />
<condition property="byacc" value="tools/byacc/byacc.exe">
<or>
<os family="windows" arch="x86" />
<os family="windows" arch="amd64" />
</or>
</condition>
<condition property="byacc" value="${basedir}/tools/byacc/byacc.linux">
<or>
<os family="unix" arch="x86" />
<os family="unix" arch="i386" />
<os family="unix" arch="i486" />
<os family="unix" arch="i586" />
<os family="unix" arch="i686" />
</or>
</condition>
<condition property="byacc" value="${basedir}/tools/byacc/byacc.linux.amd64">
<or>
<os family="unix" arch="amd64" />
</or>
</condition>
<condition property="byacc" value="${basedir}/tools/byacc/byacc.mac">
<or>
<os family="mac" />
</or>
</condition>
<target name="prepare" description="Preparing...">
<mkdir dir="${bin.dir}" />
<mkdir dir="${doc.dir}" />
</target>
<!-- 生成Lex和YACC结果 -->
<target name="1 jflex" description="Running JFlex...">
<java jar="${jflex.jar}" fork="true" maxmemory="128m" failonerror="true">
<sysproperty key="file.encoding" value="UTF-8" />
<arg value="${src.dir}/decaf/frontend/Lexer.l" />
</java>
<delete file="${src.dir}/decaf/frontend/Lexer.java~" />
</target>
<target name="2 byacc" description="Running BYACC/J...">
<chmod file="${byacc}" perm="+rx" />
<!-- for unix -->
<exec dir="${src.dir}/decaf/frontend" executable="${byacc}" failonerror="true">
<arg line="-v -J Parser.y" />
</exec>
<move file="${src.dir}/decaf/frontend/y" tofile="${src.dir}/decaf/frontend/Parser.output" />
</target>
<!-- 编译 -->
<target name="3 compile" depends="prepare,1 jflex,2 byacc" description="Compiling all...">
<javac srcdir="${src.dir}" destdir="${bin.dir}" encoding="UTF8" debug="on" optimize="off" />
</target>
<!-- 打包 -->
<target name="4 pack" depends="3 compile" description="Packaging...">
<jar destfile="${result.dir}/decaf.jar">
<fileset dir="${basedir}" includes="src/**" />
<fileset dir="${bin.dir}" />
<manifest>
<attribute name="Signature-Version" value="3.141592" />
<attribute name="Main-Class" value="decaf.Driver" />
</manifest>
</jar>
</target>
<!-- 生成JavaDoc -->
<target name="5 javadoc" depends="3 compile">
<javadoc access="private" encoding="UTF8" author="false" classpath="." destdir="${doc.dir}" doctitle="Decaf Compiler Documentation" nodeprecated="true" nodeprecatedlist="true" packagenames="*" sourcepath="${basedir}/src" use="true" version="false">
<link href="." />
</javadoc>
</target>
<target name="clean" description="Clean...">
<delete dir="${result.dir}" />
</target>
</project>
package decaf;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import decaf.tree.Tree;
import decaf.error.DecafError;
import decaf.frontend.Lexer;
import decaf.frontend.Parser;
import decaf.scope.ScopeStack;
import decaf.translate.Translater;
import decaf.typecheck.BuildSym;
import decaf.typecheck.TypeCheck;
import decaf.utils.IndentPrintWriter;
public final class Driver {
private static Driver driver;
private Option option;
private List<DecafError> errors;
private ScopeStack table;
private Lexer lexer;
private Parser parser;
public ScopeStack getTable() {
return table;
}
public static Driver getDriver() {
return driver;
}
public Option getOption() {
return option;
}
public void issueError(DecafError error) {
errors.add(error);
}
// Only allow construction by Driver.main
private Driver() {
}
/**
* 如果有错误,输出错误并退出
*/
private void checkPoint() {
if (errors.size() > 0) {
Collections.sort(errors, new Comparator<DecafError>() {
@Override
public int compare(DecafError o1, DecafError o2) {
return o1.getLocation().compareTo(o2.getLocation());
}
});
for (DecafError error : errors) {
option.getErr().println(error);
}
System.exit(1);
}
}
private void init() {
lexer = new Lexer(option.getInput());
parser = new Parser();
lexer.setParser(parser);
parser.setLexer(lexer);
errors = new ArrayList<DecafError>();
table = new ScopeStack();
}
private void compile() {
Tree.TopLevel tree = parser.parseFile();
checkPoint();
if (option.getLevel() == Option.Level.LEVEL0) {
IndentPrintWriter pw = new IndentPrintWriter(option.getOutput(), 4);
tree.printTo(pw);
pw.close();
return;
}
BuildSym.buildSymbol(tree);
checkPoint();
TypeCheck.checkType(tree);
checkPoint();
if (option.getLevel() == Option.Level.LEVEL1) {
IndentPrintWriter pw = new IndentPrintWriter(option.getOutput(), 4);
tree.globalScope.printTo(pw);
pw.close();
return;
}
PrintWriter pw = new PrintWriter(option.getOutput());
Translater tr = Translater.translate(tree);
checkPoint();
if (option.getLevel() == Option.Level.LEVEL2) {
tr.printTo(pw);
pw.close();
return;
}
}
public static void main(String[] args) throws IOException {
driver = new Driver();
driver.option = new Option(args);
driver.init();
driver.compile();
}
}
package decaf;
/**
* 语法符号在源代码中的位置<br>
*/
public class Location implements Comparable<Location> {
public static final Location NO_LOCATION = new Location(-1, -1);
/**
* 该符号第一个字符所在的行号
*/
private int line;
/**
* 该符号第一个字符所在的列号
*/
private int column;
/**
* 构造一个位置记录
*
* @param lin
* 行号
* @param col
* 列号
*/
public Location(int lin, int col) {
line = lin;
column = col;
}
/**
* 转换成(x,y)形式的字符串
*/
@Override
public String toString() {
return "(" + line + "," + column + ")";
}
@Override
public int compareTo(Location o) {
if (line > o.line) {
return 1;
}
if (line < o.line) {
return -1;
}
if (column > o.column) {
return 1;
}
if (column < o.column) {
return -1;
}
return 0;
}
}
package decaf;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.PrintStream;
public final class Option {
public enum Level {
LEVEL0, LEVEL1, LEVEL2, LEVEL3, LEVEL4
}
private String srcFileName;
private String dstFileName;
private InputStream input = System.in;
private PrintStream output = System.out;
private PrintStream err = System.err;
private Level level = Level.LEVEL4;
private static final String mainClassName = "Main";
private static final String mainFuncName = "main";
public String getMainFuncName() {
return mainFuncName;
}
public String getMainClassName() {
return mainClassName;
}
public Option(String[] args) {
if (args.length == 0) {
output.println(usage());
System.exit(0);
}
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-o")) {
dstFileName = args[++i];
try {
output = new PrintStream(new FileOutputStream(dstFileName));
} catch (FileNotFoundException e) {
err.println("Can not open file " + dstFileName
+ " for write");
System.exit(1);
}
} else if (args[i].equals("-l")) {
level = Level.valueOf("LEVEL" + args[++i]);
} else {
srcFileName = args[i];
try {
input = new BufferedInputStream(new FileInputStream(
srcFileName));
} catch (FileNotFoundException e) {
err.println("File " + srcFileName + " not found");
System.exit(1);
}
}
}
}
private String usage() {
return ("\n"
+ "Usage: java -jar decaf.jar [-l LEVEL] [-o OUTPUT] SOURCE\n"
+ "Options:\n"
+ " -l Developing level of the compiler, values of LEVEL are: \n"
+ " 0 AST Construction \n"
+ " 1 Type Check \n"
+ " 2 TAC Generation \n"
+ " 3 Dataflow Analysis \n"
+ " 4 Final Ouput (Mips Assembly, default) \n"
+ " \n"
+ " -o Specifying the output file name. stdout if omitted. \n"
+ " \n"
+ "\n");
}
public String getSrcFileName() {
return srcFileName;
}
public String getDstFileName() {
return dstFileName;
}
public InputStream getInput() {
return input;
}
public Level getLevel() {
return level;
}
public PrintStream getOutput() {
return output;
}
public PrintStream getErr() {
return err;
}
}
package decaf.backend;
public final class OffsetCounter {
public enum Kind {
LOCAL, PARAMETER, VARFIELD
}
public static final int POINTER_SIZE = 4;
public static final int WORD_SIZE = 4;
public static final int DOUBLE_SIZE = 8;
private static final int[] initValue = new int[] { -2 * WORD_SIZE,
WORD_SIZE, POINTER_SIZE };
private static final int[] direction = new int[] { -1, 1, 1 };
public static final OffsetCounter LOCAL_OFFSET_COUNTER = new OffsetCounter(
Kind.LOCAL);
public static final OffsetCounter PARAMETER_OFFSET_COUNTER = new OffsetCounter(
Kind.PARAMETER);
public static final OffsetCounter VARFIELD_OFFSET_COUNTER = new OffsetCounter(
Kind.VARFIELD);
private Kind kind;
private int value;
private OffsetCounter(Kind kind) {
this.kind = kind;
reset();
}
public void reset() {
value = initValue[kind.ordinal()];
}
public int next(int value) {
int ret = this.value;
this.value += direction[kind.ordinal()] * value;
return ret;
}
public void set(int offset) {
value = offset;
}
}
package decaf.error;
import decaf.Location;
/**
* example:function 'gotoMars' expects 1 argument(s) but 3 given<br>
* PA2
*/
public class BadArgCountError extends DecafError {
private String method;
private int expect;
private int count;
public BadArgCountError(Location location, String method, int expect,
int count) {
super(location);
this.method = method;
this.expect = expect;
this.count = count;
}
@Override
protected String getErrMsg() {
return "function '" + method + "' expects " + expect
+ " argument(s) but " + count + " given";
}
}
package decaf.error;
import decaf.Location;
/**
* example:incompatible argument 3: int given, bool expected<br>
* 3表示发生错误的是第三个参数<br>
* PA2
*/
public class BadArgTypeError extends DecafError {
private int count;
private String given;
private String expect;
public BadArgTypeError(Location location, int count, String given,
String expect) {
super(location);
this.count = count;
this.given = given;
this.expect = expect;
}
@Override
protected String getErrMsg() {
return "incompatible argument " + count + ": " + given + " given, "
+ expect + " expected";
}
}
package decaf.error;
import decaf.Location;
/**
* example:array base type must be non-void type<br>
* PA2
*/
public class BadArrCompArgTypeError extends DecafError {
String arrtype;
String vartype;
public BadArrCompArgTypeError (Location location, String arrtype, String vartype) {
super(location);
this.arrtype = arrtype;
this.vartype = vartype;
}
@Override
protected String getErrMsg() {
return "Array has Element type "+ arrtype + " but holder has type " + vartype;
}
}
package decaf.error;
import decaf.Location;
/**
* example:array base type must be non-void type<br>
* PA2
*/
public class BadArrElementError extends DecafError {
public BadArrElementError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "array element type must be non-void known type";
}
}
package decaf.error;
import decaf.Location;
/**
* example:array base type must be non-void type<br>
* PA2
*/
public class BadArrIndexError extends DecafError {
public BadArrIndexError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "array index must be int type";
}
}
package decaf.error;
import decaf.Location;
/**
* example:incompatible argument 3: int[] given, int/bool/string expected<br>
* 3表示发生错误的是第三个参数<br>
* PA2
*/
public class BadArrOperArgError extends DecafError {
public BadArrOperArgError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "Array Operation on non-array type" ;
}
}
package decaf.error;
import decaf.Location;
/**
* example:array base type must be non-void type<br>
* PA2
*/
public class BadArrTimesError extends DecafError {
public BadArrTimesError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "array repeats time type must be int type";
}
}
package decaf.error;
import decaf.Location;
/**
* example:array base type must be non-void type<br>
* PA2
*/
public class BadDefError extends DecafError {
String arrtype;
String deftype;
public BadDefError(Location location, String arrtype, String deftype) {
super(location);
this.arrtype = arrtype;
this.deftype = deftype;
}
@Override
protected String getErrMsg() {
return "Array has Element type "+ arrtype + " but default has type " + deftype;
}
}
package decaf.error;
import decaf.Location;
/**
* example:incompatible argument 3: int given, bool expected<br>
* 3表示发生错误的是第三个参数<br>
* PA2
*/
public class BadForeachTypeError extends DecafError {
private String given;
private String expect;
public BadForeachTypeError(Location location, String given,
String expect) {
super(location);
this.given = given;
this.expect = expect;
}
@Override
protected String getErrMsg() {
return given + " is incompatible with " + expect ;
}
}
package decaf.error;
import decaf.Location;
/**
* example:illegal class inheritance (should be a cyclic)<br>
* PA2
*/
public class BadInheritanceError extends DecafError {
public BadInheritanceError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "illegal class inheritance (should be a cyclic)";
}
}
package decaf.error;
import decaf.Location;
/**
* example:function 'length' expects 0 argument(s) but 2 given<br>
* PA2
*/
public class BadLengthArgError extends DecafError {
private int count;
public BadLengthArgError(Location location, int count) {
super(location);
this.count = count;
}
@Override
protected String getErrMsg() {
return "function 'length' expects 0 argument(s) but " + count
+ " given";
}
}
package decaf.error;
import decaf.Location;
/**
* example:'length' can only be applied to arrays<br>
* PA2
*/
public class BadLengthError extends DecafError {
public BadLengthError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "'length' can only be applied to arrays";
}
}
package decaf.error;
import decaf.Location;
/**
* example:new array length must be an integer<br>
* PA2
*/
public class BadNewArrayLength extends DecafError {
public BadNewArrayLength(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "new array length must be an integer";
}
}
package decaf.error;
import decaf.Location;
/**
* example:overriding method 'tooold' doesn't match the type signature in class
* 'duckyaya'<br>
* PA2
*/
public class BadOverrideError extends DecafError {
private String funcName;
private String parentName;
public BadOverrideError(Location location, String funcName,
String parentName) {
super(location);
this.funcName = funcName;
this.parentName = parentName;
}
@Override
protected String getErrMsg() {
return "overriding method '" + funcName
+ "' doesn't match the type signature in class '" + parentName
+ "'";
}
}
package decaf.error;
import decaf.Location;
/**
* example:incompatible argument 3: int[] given, int/bool/string expected<br>
* 3表示发生错误的是第三个参数<br>
* PA2
*/
public class BadPrintArgError extends DecafError {
private String count;
private String type;
public BadPrintArgError(Location location, String count, String type) {
super(location);
this.count = count;
this.type = type;
}
@Override
protected String getErrMsg() {
return "incompatible argument " + count + ": " + type
+ " given, int/bool/string expected";
}
}
package decaf.error;
import decaf.Location;
/**
* example:incompatible return: int[] given, int expected<br>
* PA2
*/
public class BadReturnTypeError extends DecafError {
private String expect;
private String given;
public BadReturnTypeError(Location location, String expect, String given) {
super(location);
this.expect = expect;
this.given = given;
}
@Override
protected String getErrMsg() {
return "incompatible return: " + given + " given, " + expect
+ " expected";
}
}
package decaf.error;
import decaf.Location;
/**
* example:incompatible argument 3: int[] given, int/bool/string expected<br>
* 3表示发生错误的是第三个参数<br>
* PA2
*/
public class BadScopyArgError extends DecafError {
private String count;
private String type;
public BadScopyArgError(Location location, String count, String type) {
super(location);
this.count = count;
this.type = type;
}
@Override
protected String getErrMsg() {
return "incompatible argument " + count + ": " + type
+ " given, class expected";
}
}
package decaf.error;
import decaf.Location;
/**
* example:incompatible argument 3: int[] given, int/bool/string expected<br>
* 3表示发生错误的是第三个参数<br>
* PA2
*/
public class BadScopySrcError extends DecafError {
private String count;
private String dsttype;
private String srctype;
public BadScopySrcError(Location location, String dsttype, String srctype) {
super(location);
this.count = count;
this.dsttype = dsttype;
this.srctype = srctype;
}
@Override
protected String getErrMsg() {
return "incompatible dst type: " + dsttype+ " and src type: " + srctype;
}
}
package decaf.error;
import decaf.Location;
/**
* example:illegal class inheritance (should be a cyclic)<br>
* PA2
*/
public class BadSealedInherError extends DecafError {
public BadSealedInherError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "illegal class inheritance from sealed class";
}
}
package decaf.error;
import decaf.Location;
/**
* example:test expression must have bool type<br>
* PA2
*/
public class BadTestExpr extends DecafError {
public BadTestExpr(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "test expression must have bool type";
}
}
package decaf.error;
import decaf.Location;
/**
* example:cannot declare identifier 'boost' as void type<br>
* PA2
*/
public class BadVarTypeError extends DecafError {
private String name;
public BadVarTypeError(Location location, String name) {
super(location);
this.name = name;
}
@Override
protected String getErrMsg() {
return "cannot declare identifier '" + name + "' as void type";
}
}
package decaf.error;
import decaf.Location;
/**
* example:'break' is only allowed inside a loop<br>
* PA2
*/
public class BreakOutOfLoopError extends DecafError {
public BreakOutOfLoopError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "'break' is only allowed inside a loop";
}
}
package decaf.error;
import decaf.Location;
/**
* example:class 'zig' not found<br>
* PA2
*/
public class ClassNotFoundError extends DecafError {
private String name;
public ClassNotFoundError(Location location, String name) {
super(location);
this.name = name;
}
@Override
protected String getErrMsg() {
return "class '" + name + "' not found";
}
}
package decaf.error;
import decaf.Location;
/**
* decaf中所有编译错误的基类
*/
public abstract class DecafError {
/**
* 编译错误所在的位置
*/
protected Location location;
/**
* @return 返回错误的具体描述
*/
protected abstract String getErrMsg();
public DecafError(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
/**
* 返回包含位置信息在内的完整错误信息
*/
@Override
public String toString() {
if (location.equals(Location.NO_LOCATION)) {
return "*** Error: " + getErrMsg();
} else {
return "*** Error at " + location + ": " + getErrMsg();
}
}
}
package decaf.error;
import decaf.Location;
/**
* example:declaration of 'abcde' here conflicts with earlier declaration at (3,2)<br>
* PA2
*/
public class DeclConflictError extends DecafError {
private Location earlier;
private String name;
public DeclConflictError(Location location, String name, Location earlier) {
super(location);
this.name = name;
this.earlier = earlier;
}
@Override
protected String getErrMsg() {
return "declaration of '" + name
+ "' here conflicts with earlier declaration at " + earlier;
}
}
package decaf.error;
import decaf.Location;
/**
* example:field 'homework' of 'Others' not accessible here<br>
* PA2
*/
public class FieldNotAccessError extends DecafError {
private String name;
private String owner;
public FieldNotAccessError(Location location, String name, String owner) {
super(location);
this.name = name;
this.owner = owner;
}
@Override
protected String getErrMsg() {
return "field '" + name + "' of '" + owner + "' not accessible here";
}
}
package decaf.error;
import decaf.Location;
/**
* example:field 'money' not found in 'Student'<br>
* PA2
*/
public class FieldNotFoundError extends DecafError {
private String name;
private String owner;
public FieldNotFoundError(Location location, String name, String owner) {
super(location);
this.name = name;
this.owner = owner;
}
@Override
protected String getErrMsg() {
return "field '" + name + "' not found in '" + owner + "'";
}
}
package decaf.error;
import decaf.Location;
/**
* example:incompatible operands: int + bool<br>
* PA2
*/
public class IncompatBinOpError extends DecafError {
private String left;
private String right;
private String op;
public IncompatBinOpError(Location location, String left, String op,
String right) {
super(location);
this.left = left;
this.right = right;
this.op = op;
}
@Override
protected String getErrMsg() {
return "incompatible operands: " + left + " " + op + " " + right;
}
}
package decaf.error;
import decaf.Location;
/**
* example:incompatible operand: - int[]<br>
* PA2
*/
public class IncompatUnOpError extends DecafError {
private String op;
private String expr;
public IncompatUnOpError(Location location, String op, String expr) {
super(location);
this.op = op;
this.expr = expr;
}
@Override
protected String getErrMsg() {
return "incompatible operand: " + op + " " + expr;
}
}
package decaf.error;
import decaf.Location;
/**
* example:integer literal 112233445566778899 is too large<br>
* PA1
*/
public class IntTooLargeError extends DecafError {
private String val;
public IntTooLargeError(Location location, String val) {
super(location);
this.val = val;
}
@Override
protected String getErrMsg() {
return "integer literal " + val + " is too large";
}
}
package decaf.error;
import decaf.Location;
/**
* 仅供Parser的yyerror函数使用
*/
public class MsgError extends DecafError {
private String msg;
public MsgError(Location location, String msg) {
super(location);
this.msg = msg;
}
@Override
protected String getErrMsg() {
return msg;
}
}
package decaf.error;
import decaf.Location;
/**
* example:illegal newline in string constant "this is stri"<br>
* PA1
*/
public class NewlineInStrError extends DecafError {
private String str;
public NewlineInStrError(Location location, String str) {
super(location);
this.str = str;
}
@Override
protected String getErrMsg() {
return "illegal newline in string constant " + str;
}
}
package decaf.error;
import decaf.Location;
/**
* example:no legal Main class named 'Main' was found<br>
* PA2
*/
public class NoMainClassError extends DecafError {
private String name;
public NoMainClassError(String name) {
super(Location.NO_LOCATION);
this.name = name;
}
@Override
protected String getErrMsg() {
return "no legal Main class named '" + name + "' was found";
}
}
package decaf.error;
import decaf.Location;
/**
* example:[] can only be applied to arrays<br>
* PA2
*/
public class NotArrayError extends DecafError {
public NotArrayError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "[] can only be applied to arrays";
}
}
package decaf.error;
import decaf.Location;
/**
* string is not a class type.
*/
public class NotClassError extends DecafError {
private String type;
public NotClassError(String type, Location location) {
super(location);
this.type = type;
}
@Override
protected String getErrMsg() {
return type + " is not a class type";
}
}
package decaf.error;
import decaf.Location;
/**
* example:cannot access field 'homework' from 'Others'<br>
* 指通过类名来访问类成员,Others是类名<br>
* example:cannot access field 'homework' from 'int[]'<br>
* 指通过非类成员变量来访问类成员,int[]是该变量的类型名字<br>
* PA2
*/
public class NotClassFieldError extends DecafError {
private String name;
private String owner;
public NotClassFieldError(Location location, String name, String owner) {
super(location);
this.name = name;
this.owner = owner;
}
@Override
protected String getErrMsg() {
return "cannot access field '" + name + "' from '" + owner + "'";
}
}
package decaf.error;
import decaf.Location;
/**
* example:'orz' is not a method in class 'Person'<br>
* PA2
*/
public class NotClassMethodError extends DecafError {
private String name;
private String owner;
public NotClassMethodError(Location location, String name, String owner) {
super(location);
this.name = name;
this.owner = owner;
}
@Override
protected String getErrMsg() {
return "'" + name + "' is not a method in class '" + owner + "'";
}
}
package decaf.error;
import decaf.Location;
/**
* example:overriding variable is not allowed for var 'kittyboy'<br>
* PA2
*/
public class OverridingVarError extends DecafError {
private String name;
public OverridingVarError(Location location, String name) {
super(location);
this.name = name;
}
@Override
protected String getErrMsg() {
return "overriding variable is not allowed for var '" + name + "'";
}
}
package decaf.error;
import decaf.Location;
/**
* can not reference a non-static field 'kylin' from static method from 'dove'
* PA2
*/
public class RefNonStaticError extends DecafError {
private String from;
private String ref;
public RefNonStaticError(Location location, String from, String ref) {
super(location);
this.from = from;
this.ref = ref;
}
@Override
protected String getErrMsg() {
return "can not reference a non-static field '" + ref
+ "' from static method '" + from + "'";
}
}
package decaf.error;
/**
* 运行期的错误
*/
public final class RuntimeError {
private RuntimeError() {
}
public static final String ARRAY_INDEX_OUT_OF_BOUND = "Decaf runtime error: Array subscript out of bounds\n";
public static final String NEGATIVE_ARR_SIZE = "Decaf runtime error: Cannot create negative-sized array\n";
public static final String CLASS_CAST_ERROR1 = "Decaf runtime error: ";
public static final String CLASS_CAST_ERROR2 = " cannot be cast to ";
public static final String CLASS_CAST_ERROR3 = "\n";
}
package decaf.error;
import decaf.Location;
/**
* example:declaration of 'abcde' here conflicts with earlier declaration at (3,2)<br>
* PA2
*/
public class SealedClassNotExtendError extends DecafError {
private String name;
public SealedClassNotExtendError(Location location, String name) {
super(location);
this.name = name;
}
@Override
protected String getErrMsg() {
return "sealed class '" + name + " cannot be extended. ";
}
}
package decaf.error;
import decaf.Location;
/**
* example:array subscript must be an integer<br>
* PA2
*/
public class SubNotIntError extends DecafError {
public SubNotIntError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "array subscript must be an integer";
}
}
package decaf.error;
import decaf.Location;
/**
* can not use this in static function
* PA2
*/
public class ThisInStaticFuncError extends DecafError {
public ThisInStaticFuncError(Location location) {
super(location);
}
@Override
protected String getErrMsg() {
return "can not use this in static function";
}
}
package decaf.error;
import decaf.Location;
/**
* example:undeclared variable 'python'<br>
* PA2
*/
public class UndeclVarError extends DecafError {
private String name;
public UndeclVarError(Location location, String name) {
super(location);
this.name = name;
}
@Override
protected String getErrMsg() {
return "undeclared variable '" + name + "'";
}
}
package decaf.error;
import decaf.Location;
/**
* example:unrecognized char: '@'<br>
* PA1
*/
public class UnrecogCharError extends DecafError {
private char c;
public UnrecogCharError(Location location, char c) {
super(location);
this.c = c;
}
@Override
protected String getErrMsg() {
return "unrecognized character '" + c + "'";
}
}
package decaf.error;
import decaf.Location;
/**
* example:unterminated string constant: "this is str"<br>
* PA1
*/
public class UntermStrError extends DecafError {
private String str;
public UntermStrError(Location location, String str) {
super(location);
this.str = str;
}
@Override
protected String getErrMsg() {
return "unterminated string constant " + str;
}
}
package decaf.frontend;
import java.io.IOException;
import decaf.Driver;
import decaf.Location;
import decaf.error.DecafError;
import decaf.error.IntTooLargeError;
import decaf.tree.Tree;
public abstract class BaseLexer {
private Parser parser;
public void setParser(Parser parser) {
this.parser = parser;
}
abstract int yylex() throws IOException;
abstract Location getLocation();
protected void issueError(DecafError error) {
Driver.getDriver().issueError(error);
}
protected void setSemantic(Location where, SemValue v) {
v.loc = where;
parser.yylval = v;
}
protected int keyword(int code) {
setSemantic(getLocation(), SemValue.createKeyword(code));
return code;
}
protected int operator(int code) {
setSemantic(getLocation(), SemValue.createOperator(code));
return code;
}
protected int boolConst(boolean bval) {
setSemantic(getLocation(), SemValue.createLiteral(Tree.BOOL, bval));
return Parser.LITERAL;
}
protected int StringConst(String sval, Location loc) {
setSemantic(loc, SemValue.createLiteral(Tree.STRING, sval));
return Parser.LITERAL;
}
protected int intConst(String ival) {
try {
setSemantic(getLocation(), SemValue.createLiteral(
Tree.INT, Integer.decode(ival)));
} catch (NumberFormatException e) {
Driver.getDriver().issueError(
new IntTooLargeError(getLocation(), ival));
}
return Parser.LITERAL;
}
protected int identifier(String name) {
setSemantic(getLocation(), SemValue.createIdentifier(name));
return Parser.IDENTIFIER;
}
public void diagnose() throws IOException {
while (yylex() != 0) {
System.out.println(parser.yylval);
}
}
}
package decaf.frontend;
import decaf.Driver;
import decaf.tree.Tree;
import decaf.error.DecafError;
import decaf.error.MsgError;
public abstract class BaseParser {
private Lexer lexer;
protected Tree.TopLevel tree;
public void setLexer(Lexer lexer) {
this.lexer = lexer;
}
public Tree.TopLevel getTree() {
return tree;
}
protected void issueError(DecafError error) {
Driver.getDriver().issueError(error);
}
void yyerror(String msg) {
Driver.getDriver().issueError(
new MsgError(lexer.getLocation(), msg));
}
int yylex() {
int token = -1;
try {
token = lexer.yylex();
} catch (Exception e) {
yyerror("lexer error: " + e.getMessage());
}
return token;
}
abstract int yyparse();
public Tree.TopLevel parseFile() {
yyparse();
return tree;
}
/**
* 获得操作符的字符串表示
*
* @param opCode
* 操作符的符号码
* @return 该操作符的字符串形式
*/
public static String opStr(int opCode) {
switch (opCode) {
case Tree.AND:
return "&&";
case Tree.EQ:
return "==";
case Tree.GE:
return ">=";
case Tree.LE:
return "<=";
case Tree.NE:
return "!=";
case Tree.OR:
return "||";
case Tree.PLUS:
return "+";
case Tree.MINUS:
case Tree.NEG:
return "-";
case Tree.MUL:
return "*";
case Tree.DIV:
return "/";
case Tree.MOD:
return "%";
case Tree.GT:
return ">";
case Tree.LT:
return "<";
default:
return "unknow";
}
}
}
/*
* 本文件是构造Decaf编译器所需要的JFlex输入脚本。
* 在第一阶段,你需要完成这个脚本的内容,请参考"JFlex Manual"中关于如何编写JFlex脚本的说明。
*
* 注意:在UNIX系统下你需要保证这个文件使用UNIX文本格式,可使用dos2unix命令进行文本各式转换。
*/
package decaf.frontend;
import decaf.Location;
import decaf.error.*;
import decaf.utils.MiscUtils;
%%
%public
%class Lexer
%extends BaseLexer
%byaccj
%line
%column
%switch
%unicode
%{
private Location sloc = null;
private StringBuilder buffer = new StringBuilder();
public Location getLocation() {
return new decaf.Location(yyline + 1, yycolumn + 1);
}
%}
NEWLINE = (\r|\n|\r\n)
DIGIT = ([0-9])
HEX_DIGIT = ([0-9A-Fa-f])
HEX_INTEGER = (0[Xx]{HEX_DIGIT}+)
DEC_INTEGER = ({DIGIT}+)
INTEGER = ({HEX_INTEGER}|{DEC_INTEGER})
IDENTIFIER = ([A-Za-z][_0-9A-Za-z]*)
SIMPLE_OPERATOR = ("+"|"-"|"*"|"/"|"%"|"="|"<"|">"|"."|","|";"|"!"|"("|")"|"["|"]"|"{"|"}")
S_COMMENT = ("//"[^\r\n]*{NEWLINE})
WHITESPACE = ([ \t]+)
// 开始条件S表示字符串
%x S
%%
// 识别注释和空白字符的规则
{WHITESPACE} { /* Just ignore */ }
{NEWLINE} { /* Just ignore */ }
{S_COMMENT} { /* Just ignore */ }
// 识别关键字的规则
"void" { return keyword(Parser.VOID); }
"int" { return keyword(Parser.INT); }
"bool" { return keyword(Parser.BOOL); }
"string" { return keyword(Parser.STRING); }
"new" { return keyword(Parser.NEW); }
"null" { return keyword(Parser.NULL); }
"class" { return keyword(Parser.CLASS); }
"extends" { return keyword(Parser.EXTENDS); }
"this" { return keyword(Parser.THIS); }
"while" { return keyword(Parser.WHILE); }
"for" { return keyword(Parser.FOR); }
"if" { return keyword(Parser.IF); }
"else" { return keyword(Parser.ELSE); }
"return" { return keyword(Parser.RETURN); }
"break" { return keyword(Parser.BREAK); }
"Print" { return keyword(Parser.PRINT); }
"ReadInteger" { return keyword(Parser.READ_INTEGER); }
"ReadLine" { return keyword(Parser.READ_LINE); }
"static" { return keyword(Parser.STATIC); }
"instanceof" { return keyword(Parser.INSTANCEOF); }
// 识别操作符的规则
"<=" { return operator(Parser.LESS_EQUAL); }
">=" { return operator(Parser.GREATER_EQUAL);}
"==" { return operator(Parser.EQUAL); }
"!=" { return operator(Parser.NOT_EQUAL); }
"&&" { return operator(Parser.AND); }
"||" { return operator(Parser.OR); }
{SIMPLE_OPERATOR} { return operator((int)yycharat(0)); }
// 识别常数的规则
"true" { return boolConst(true); }
"false" { return boolConst(false); }
{INTEGER} { return intConst(yytext()); }
<YYINITIAL>\" { sloc = getLocation();
yybegin(S);
buffer = new StringBuilder(); }
<S>{NEWLINE} { issueError(new NewlineInStrError(sloc, MiscUtils.quote(buffer.toString())));}
<S><<EOF>> { issueError(new UntermStrError(sloc, MiscUtils.quote(buffer.toString())));
yybegin(YYINITIAL); }
<S>\" { yybegin(YYINITIAL);
return StringConst(buffer.toString(), sloc); }
<S>"\\n" { buffer.append('\n'); }
<S>"\\t" { buffer.append('\t'); }
<S>"\\\"" { buffer.append('"'); }
<S>"\\\\" { buffer.append('\\'); }
<S>. { buffer.append(yytext()); }
// 识别标识符的规则
{IDENTIFIER} { return identifier(yytext()); }
// 上面规则不能识别的字符怎么处理
. { issueError(new UnrecogCharError(getLocation(), yycharat(0))); }
package decaf.frontend;
public class ParserHelper extends Parser {
/**
* 辅助模版(切勿直接调用)
*
* @param $$
* 对应 YACC 语义动作中的 $$
* @param $1
* 对应 YACC 语义动作中的 $1
* @param $2
* 对应 YACC 语义动作中的 $2
* @param $3
* 对应 YACC 语义动作中的 $3
* @param $4
* 对应 YACC 语义动作中的 $4
* @param $5
* 对应 YACC 语义动作中的 $5
* @param $6
* 对应 YACC 语义动作中的 $6
*/
void UserAction(SemValue $$, SemValue $1, SemValue $2, SemValue $3,
SemValue $4, SemValue $5, SemValue $6) {
/*
* 这个函数作用是提供一个模版给你编写你的 YACC 语义动作。 因为在一般编辑器中编写 YACC 脚本的时候没法充分调用 IDE
* 的各种编辑功能, 因此专门开辟一个函数。使用的时候你只需要把语义动作写在下面的花括号中, 然后连同花括号一起复制-粘贴到 YACC
* 脚本对应位置即可。
*/
{
}
}
}
package decaf.frontend;
import java.util.List;
import decaf.Location;
import decaf.tree.Tree;
import decaf.tree.Tree.ClassDef;
import decaf.tree.Tree.Expr;
import decaf.tree.Tree.MethodDef;
import decaf.tree.Tree.LValue;
import decaf.tree.Tree.TopLevel;
import decaf.tree.Tree.VarDef;
import decaf.tree.Tree.TypeLiteral;
import decaf.utils.MiscUtils;
public class SemValue {
public int code;
public Location loc;
public int typeTag;
public Object literal;
public String ident;
public List<ClassDef> clist;
/**
* field list
*/
public List<Tree> flist;
public List<VarDef> vlist;
/**
* statement list
*/
public List<Tree> slist;
public List<Expr> elist;
public TopLevel prog;
public ClassDef cdef;
public VarDef vdef;
public MethodDef fdef;
public TypeLiteral type;
public Tree stmt;
public Expr expr;
public LValue lvalue;
/**
* 创建一个关键字的语义值
*
* @param code
* 关键字的代表码
* @return 对应关键字的语义值
*/
public static SemValue createKeyword(int code) {
SemValue v = new SemValue();
v.code = code;
return v;
}
/**
* 创建一个操作符的语义值
*
* @param code
* 操作符的代表码
* @return 对应操作符的语义值
*/
public static SemValue createOperator(int code) {
SemValue v = new SemValue();
v.code = code;
return v;
}
/**
* 创建一个常量的语义值
*
* @param value
* 常量的值
* @return 对应的语义值
*/
public static SemValue createLiteral(int tag, Object value) {
SemValue v = new SemValue();
v.code = Parser.LITERAL;
v.typeTag = tag;
v.literal = value;
return v;
}
/**
* 创建一个标识符的语义值
*
* @param name
* 标识符的名字
* @return 对应的语义值(标识符名字存放在sval域)
*/
public static SemValue createIdentifier(String name) {
SemValue v = new SemValue();
v.code = Parser.IDENTIFIER;
v.ident = name;
return v;
}
/**
* 获取这个语义值的字符串表示<br>
*
* 我们建议你在构造词法分析器之前先阅读一下这个函数。
*/
public String toString() {
String msg;
switch (code) {
// 关键字
case Parser.BOOL:
msg = "keyword : bool";
break;
case Parser.BREAK:
msg = "keyword : break";
break;
case Parser.CLASS:
msg = "keyword : class";
break;
case Parser.ELSE:
msg = "keyword : else";
break;
case Parser.EXTENDS:
msg = "keyword : extends";
break;
case Parser.FOR:
msg = "keyword : for";
break;
case Parser.IF:
msg = "keyword : if";
break;
case Parser.INT:
msg = "keyword : int";
break;
case Parser.INSTANCEOF:
msg = "keyword : instanceof";
break;
case Parser.NEW:
msg = "keyword : new";
break;
case Parser.NULL:
msg = "keyword : null";
break;
case Parser.PRINT:
msg = "keyword : Print";
break;
case Parser.READ_INTEGER:
msg = "keyword : ReadInteger";
break;
case Parser.READ_LINE:
msg = "keyword : ReadLine";
break;
case Parser.RETURN:
msg = "keyword : return";
break;
case Parser.STRING:
msg = "keyword : string";
break;
case Parser.THIS:
msg = "keyword : this";
break;
case Parser.VOID:
msg = "keyword : void";
break;
case Parser.WHILE:
msg = "keyword : while";
break;
case Parser.STATIC:
msg = "keyword : static";
break;
// 常量
case Parser.LITERAL:
switch (typeTag) {
case Tree.INT:
case Tree.BOOL:
msg = "constant : " + literal;
break;
default:
msg = "constant : " + MiscUtils.quote((String)literal);
}
break;
// 标识符
case Parser.IDENTIFIER:
msg = "identifier: " + ident;
break;
// 操作符
case Parser.AND:
msg = "operator : &&";
break;
case Parser.EQUAL:
msg = "operator : ==";
break;
case Parser.GREATER_EQUAL:
msg = "operator : >=";
break;
case Parser.LESS_EQUAL:
msg = "operator : <=";
break;
case Parser.NOT_EQUAL:
msg = "operator : !=";
break;
case Parser.OR:
msg = "operator : ||";
break;
default:
msg = "operator : " + (char) code;
break;
}
return (String.format("%-15s%s", loc, msg));
}
}
package decaf.machdesc;
import decaf.tac.Label;
import decaf.type.BaseType;
public final class Intrinsic {
/**
* 分配内存,如果失败则自动退出程序<br>
* 参数: 为要分配的内存块大小(单位为字节)<br>
* 返回: 该内存块的首地址<br>
* 返回类型: 指针,需要用VarDecl的changeTypeTo()函数更改类型
*/
public static final Intrinsic ALLOCATE = new Intrinsic("_Alloc", 1,
BaseType.INT);
/**
* 读取一行字符串(最大63个字符)<br>
* 返回: 读到的字符串首地址<br>
* 返回类型: string
*/
public static final Intrinsic READ_LINE = new Intrinsic("_ReadLine", 0,
BaseType.STRING);
/**
* 读取一个整数<br>
* 返回: 读到的整数<br>
* 返回类型: int
*/
public static final Intrinsic READ_INT = new Intrinsic("_ReadInteger", 0,
BaseType.INT);
/**
* 比较两个字符串<br>
* 参数: 要比较的两个字符串的首地址<br>
* 返回: 若相等则返回true,否则返回false<br>
* 返回类型: bool
*/
public static final Intrinsic STRING_EQUAL = new Intrinsic("_StringEqual",
2, BaseType.BOOL);
/**
* 打印一个整数<br>
* 参数: 要打印的数字
*/
public static final Intrinsic PRINT_INT = new Intrinsic("_PrintInt", 1,
BaseType.VOID);
/**
* 打印一个字符串<br>
* 参数: 要打印的字符串
*/
public static final Intrinsic PRINT_STRING = new Intrinsic("_PrintString",
1, BaseType.VOID);
/**
* 打印一个布尔值<br>
* 参数: 要打印的布尔变量
*/
public static final Intrinsic PRINT_BOOL = new Intrinsic("_PrintBool", 1,
BaseType.VOID);
/**
* 结束程序<br>
* 可以作为子程序调用,也可以直接Goto
*/
public static final Intrinsic HALT = new Intrinsic("_Halt", 0,
BaseType.VOID);
/**
* 函数名字
*/
public final Label label;
/**
* 函数的参数个数
*/
public final int numArgs;
/**
* 函数返回值类型
*/
public final BaseType type;
/**
* 构造一个预定义函数的信息
*
* @param name
* 函数名字
* @param argc
* 参数个数
* @param type
* 返回类型
*/
private Intrinsic(String name, int numArgs, BaseType type) {
this.label = Label.createLabel(name, false);
this.numArgs = numArgs;
this.type = type;
}
}
package decaf.scope;
import java.util.TreeSet;
import decaf.symbol.Class;
import decaf.symbol.Function;
import decaf.symbol.Symbol;
import decaf.utils.IndentPrintWriter;
public class ClassScope extends Scope {
private Class owner;
public ClassScope(Class owner) {
super();
this.owner = owner;
}
@Override
public boolean isClassScope() {
return true;
}
public ClassScope getParentScope() {
Class p = owner.getParent();
return p == null ? null : p.getAssociatedScope();
}
@Override
public Kind getKind() {
return Kind.CLASS;
}
public Class getOwner() {
return owner;
}
@Override
public void printTo(IndentPrintWriter pw) {
TreeSet<Symbol> ss = new TreeSet<Symbol>(Symbol.LOCATION_COMPARATOR);
for (Symbol symbol : symbols.values()) {
ss.add(symbol);
}
pw.println("CLASS SCOPE OF '" + owner.getName() + "':");
pw.incIndent();
for (Symbol symbol : ss) {
pw.println(symbol);
}
for (Symbol symbol : ss) {
if (symbol.isFunction()) {
((Function) symbol).getAssociatedScope().printTo(pw);
}
}
pw.decIndent();
}
public boolean isInherited(Symbol symbol) {
Scope scope = symbol.getScope();
if (scope == null || scope == this || !scope.isClassScope()) {
return false;
}
for (ClassScope p = getParentScope(); p != null; p = p.getParentScope()) {
if (scope == p) {
return true;
}
}
return false;
}
public Symbol lookupVisible(String name) {
for (ClassScope cs = this; cs != null; cs = cs.getParentScope()) {
Symbol symbol = cs.lookup(name);
if (symbol != null) {
return symbol;
}
}
return null;
}
}
package decaf.scope;
import decaf.tree.Tree.Block;
import decaf.symbol.Function;
import decaf.symbol.Symbol;
import decaf.utils.IndentPrintWriter;
public class FormalScope extends Scope {
private Function owner;
private Block astNode;
public FormalScope(Function owner, Block astNode) {
this.owner = owner;
this.astNode = astNode;
}
@Override
public Kind getKind() {
return Kind.FORMAL;
}
public Function getOwner() {
return owner;
}
@Override
public boolean isFormalScope() {
return true;
}
@Override
public void printTo(IndentPrintWriter pw) {
pw.println("FORMAL SCOPE OF '" + owner.getName() + "':");
pw.incIndent();
for (Symbol symbol : symbols.values()) {
pw.println(symbol);
}
astNode.associatedScope.printTo(pw);
pw.decIndent();
}
}
package decaf.scope;
import decaf.symbol.Class;
import decaf.symbol.Symbol;
import decaf.utils.IndentPrintWriter;
public class GlobalScope extends Scope {
@Override
public boolean isGlobalScope() {
return true;
}
@Override
public Kind getKind() {
return Kind.GLOBAL;
}
@Override
public void printTo(IndentPrintWriter pw) {
pw.println("GLOBAL SCOPE:");
pw.incIndent();
for (Symbol symbol : symbols.values()) {
pw.println(symbol);
}
for (Symbol symbol : symbols.values()) {
((Class) symbol).getAssociatedScope().printTo(pw);
}
pw.decIndent();
}
}
package decaf.scope;
import decaf.tree.Tree;
import decaf.tree.Tree.Block;
import decaf.symbol.Symbol;
import decaf.utils.IndentPrintWriter;
public class LocalScope extends Scope {
private Block node;
public LocalScope(Block node) {
this.node = node;
}
@Override
public Kind getKind() {
return Kind.LOCAL;
}
@Override
public void printTo(IndentPrintWriter pw) {
pw.println("LOCAL SCOPE:");
pw.incIndent();
for (Symbol symbol : symbols.values()) {
pw.println(symbol);
}
for (Tree s : node.block) {
if (s instanceof Block) {
((Block) s).associatedScope.printTo(pw);
}
}
pw.decIndent();
}
@Override
public boolean isLocalScope() {
return true;
}
}
package decaf.scope;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import decaf.symbol.Symbol;
import decaf.utils.IndentPrintWriter;
public abstract class Scope {
public enum Kind {
GLOBAL, CLASS, FORMAL, LOCAL
}
protected Map<String, Symbol> symbols = new LinkedHashMap<String, Symbol>();
public abstract Kind getKind();
public abstract void printTo(IndentPrintWriter pw);
public boolean isGlobalScope() {
return false;
}
public boolean isClassScope() {
return false;
}
public boolean isLocalScope() {
return false;
}
public boolean isFormalScope() {
return false;
}
public Symbol lookup(String name) {
return symbols.get(name);
}
public void declare(Symbol symbol) {
symbols.put(symbol.getName(), symbol);
symbol.setScope(this);
}
public void cancel(Symbol symbol) {
symbols.remove(symbol.getName());
}
public Iterator<Symbol> iterator() {
return symbols.values().iterator();
}
}
package decaf.scope;
import java.util.ListIterator;
import java.util.Stack;
import decaf.Location;
import decaf.scope.Scope.Kind;
import decaf.symbol.Class;
import decaf.symbol.Symbol;
public class ScopeStack {
private Stack<Scope> scopeStack = new Stack<Scope>();
private GlobalScope globalScope;
public Symbol lookup(String name, boolean through) {
if (through) {
ListIterator<Scope> iter = scopeStack.listIterator(scopeStack
.size());
while (iter.hasPrevious()) {
Symbol symbol = iter.previous().lookup(name);
if (symbol != null) {
return symbol;
}
}
return null;
} else {
return scopeStack.peek().lookup(name);
}
}
public Symbol lookupBeforeLocation(String name, Location loc) {
ListIterator<Scope> iter = scopeStack.listIterator(scopeStack.size());
while (iter.hasPrevious()) {
Scope scope = iter.previous();
Symbol symbol = scope.lookup(name);
if (symbol != null) {
if (scope.isLocalScope()
&& symbol.getLocation().compareTo(loc) > 0) {
continue;
}
return symbol;
}
}
return null;
}
public void declare(Symbol symbol) {
scopeStack.peek().declare(symbol);
}
public void open(Scope scope) {
switch (scope.getKind()) {
case GLOBAL:
globalScope = (GlobalScope)scope;
break;
case CLASS:
ClassScope cs = ((ClassScope) scope).getParentScope();
if (cs != null) {
open(cs);
}
break;
}
scopeStack.push(scope);
}
public void close() {
Scope scope = scopeStack.pop();
if (scope.isClassScope()) {
for (int n = scopeStack.size() - 1; n > 0; n--) {
scopeStack.pop();
}
}
}
public Scope lookForScope(Kind kind) {
ListIterator<Scope> iter = scopeStack.listIterator(scopeStack.size());
while (iter.hasPrevious()) {
Scope scope = iter.previous();
if (scope.getKind() == kind) {
return scope;
}
}
return null;
}
public Scope getCurrentScope() {
return scopeStack.peek();
}
public Class lookupClass(String name) {
return (Class) globalScope.lookup(name);
}
}
package decaf.symbol;
import java.util.Iterator;
import decaf.Driver;
import decaf.Location;
import decaf.backend.OffsetCounter;
import decaf.scope.ClassScope;
import decaf.scope.GlobalScope;
import decaf.tac.Label;
import decaf.tac.VTable;
import decaf.type.ClassType;
public class Class extends Symbol {
private String parentName;
private ClassScope associatedScope;
private int order;
private boolean check;
private int numNonStaticFunc;
private int numVar;
private int size;
private VTable vtable;
private Label newFuncLabel;
public Label getNewFuncLabel() {
return newFuncLabel;
}
public void setNewFuncLabel(Label newFuncLabel) {
this.newFuncLabel = newFuncLabel;
}
public VTable getVtable() {
return vtable;
}
public void setVtable(VTable vtable) {
this.vtable = vtable;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getNumNonStaticFunc() {
return numNonStaticFunc;
}
public void setNumNonStaticFunc(int numNonStaticFunc) {
this.numNonStaticFunc = numNonStaticFunc;
}
public int getNumVar() {
return numVar;
}
public void setNumVar(int numVar) {
this.numVar = numVar;
}
public Class(String name, String parentName, Location location) {
this.name = name;
this.parentName = parentName;
this.location = location;
this.order = -1;
this.check = false;
this.numNonStaticFunc = -1;
this.numVar = -1;
this.associatedScope = new ClassScope(this);
}
public void createType() {
Class p = getParent();
if (p == null) {
type = new ClassType(this, null);
} else {
if (p.getType() == null) {
p.createType();
}
type = new ClassType(this, (ClassType) p.getType());
}
}
@Override
public ClassType getType() {
if (type == null) {
createType();
}
return (ClassType) type;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(location + " -> class " + name);
if (parentName != null) {
sb.append(" : " + parentName);
}
return sb.toString();
}
public ClassScope getAssociatedScope() {
return associatedScope;
}
public Class getParent() {
return Driver.getDriver().getTable().lookupClass(parentName);
}
@Override
public boolean isClass() {
return true;
}
@Override
public GlobalScope getScope() {
return (GlobalScope) definedIn;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public void dettachParent() {
parentName = null;
}
public boolean isCheck() {
return check;
}
public void setCheck(boolean check) {
this.check = check;
}
public void resolveFieldOrder() {
if (numNonStaticFunc >= 0 && numVar >= 0) {
return;
}
if (parentName != null) {
Class parent = getParent();
parent.resolveFieldOrder();
numNonStaticFunc = parent.numNonStaticFunc;
numVar = parent.numVar;
size = parent.size;
} else {
numNonStaticFunc = 0;
numVar = 0;
size = OffsetCounter.POINTER_SIZE;
}
ClassScope ps = associatedScope.getParentScope();
Iterator<Symbol> iter = associatedScope.iterator();
while (iter.hasNext()) {
Symbol sym = iter.next();
if (sym.isVariable()) {
sym.setOrder(numVar++);
size += OffsetCounter.WORD_SIZE;
} else if (!((Function) sym).isStatik()) {
if (ps == null) {
sym.setOrder(numNonStaticFunc++);
} else {
Symbol s = ps.lookupVisible(sym.name);
if (s == null) {
sym.setOrder(numNonStaticFunc++);
} else {
sym.setOrder(s.getOrder());
}
}
}
}
}
@Override
public boolean isFunction() {
return false;
}
@Override
public boolean isVariable() {
return false;
}
}
package decaf.symbol;
import decaf.Driver;
import decaf.Location;
import decaf.tree.Tree.Block;
import decaf.scope.ClassScope;
import decaf.scope.FormalScope;
import decaf.scope.Scope;
import decaf.tac.Functy;
import decaf.type.FuncType;
import decaf.type.Type;
public class Function extends Symbol {
private FormalScope associatedScope;
private Functy functy;
private boolean statik;
private boolean isMain;
public boolean isMain() {
return isMain;
}
public void setMain(boolean isMain) {
this.isMain = isMain;
}
public boolean isStatik() {
return statik;
}
public void setStatik(boolean statik) {
this.statik = statik;
}
private int offset;
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public Functy getFuncty() {
return functy;
}
public void setFuncty(Functy functy) {
this.functy = functy;
}
public Function(boolean statik, String name, Type returnType,
Block node, Location location) {
this.name = name;
this.location = location;
type = new FuncType(returnType);
associatedScope = new FormalScope(this, node);
ClassScope cs = (ClassScope) Driver.getDriver().getTable()
.lookForScope(Scope.Kind.CLASS);
this.statik = statik;
if (!statik) {
Variable _this = new Variable("this", cs.getOwner().getType(),
location);
associatedScope.declare(_this);
appendParam(_this);
}
}
public FormalScope getAssociatedScope() {
return associatedScope;
}
public Type getReturnType() {
return getType().getReturnType();
}
public void appendParam(Variable arg) {
arg.setOrder(getType().numOfParams());
getType().appendParam(arg.getType());
}
@Override
public ClassScope getScope() {
return (ClassScope) definedIn;
}
@Override
public FuncType getType() {
return (FuncType) type;
}
@Override
public boolean isFunction() {
return true;
}
@Override
public String toString() {
return location + " -> " + (statik ? "static " : "") + "function "
+ name + " : " + type;
}
@Override
public boolean isClass() {
return false;
}
@Override
public boolean isVariable() {
return false;
}
}
package decaf.symbol;
import java.util.Comparator;
import decaf.Location;
import decaf.scope.Scope;
import decaf.type.Type;
public abstract class Symbol {
protected String name;
protected Scope definedIn;
protected Type type;
protected int order;
protected Location location;
public static final Comparator<Symbol> LOCATION_COMPARATOR = new Comparator<Symbol>() {
@Override
public int compare(Symbol o1, Symbol o2) {
return o1.location.compareTo(o2.location);
}
};
public static final Comparator<Symbol> ORDER_COMPARATOR = new Comparator<Symbol>() {
@Override
public int compare(Symbol o1, Symbol o2) {
return o1.order > o2.order ? 1 : o1.order == o2.order ? 0 : -1;
}
};
public Scope getScope() {
return definedIn;
}
public void setScope(Scope definedIn) {
this.definedIn = definedIn;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public Type getType() {
return type;
}
public String getName() {
return name;
}
public abstract boolean isVariable();
public abstract boolean isClass();
public abstract boolean isFunction();
public abstract String toString();
}
package decaf.symbol;
import decaf.Location;
import decaf.tac.Temp;
import decaf.type.Type;
public class Variable extends Symbol {
private int offset;
private Temp temp;
public Temp getTemp() {
return temp;
}
public void setTemp(Temp temp) {
this.temp = temp;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public Variable(String name, Type type, Location location) {
this.name = name;
this.type = type;
this.location = location;
}
public boolean isLocalVar() {
return definedIn.isLocalScope();
}
public boolean isMemberVar() {
return definedIn.isClassScope();
}
@Override
public boolean isVariable() {
return true;
}
@Override
public String toString() {
return location + " -> variable " + (isParam() ? "@" : "") + name
+ " : " + type;
}
public boolean isParam() {
return definedIn.isFormalScope();
}
@Override
public boolean isClass() {
return false;
}
@Override
public boolean isFunction() {
return false;
}
}
package decaf.tac;
import decaf.symbol.Function;
public class Functy {
public Label label;
public Tac paramMemo;
public Tac head;
public Tac tail;
public Function sym;
}
package decaf.tac;
public class Label {
public int id;
public String name;
public boolean target;
public Tac where;
private static int labelCount = 0;
public Label() {
}
public Label(int id, String name, boolean target) {
this.id = id;
this.name = name;
this.target = target;
}
public static Label createLabel() {
return createLabel(false);
}
public static Label createLabel(boolean target) {
int id = labelCount++;
return new Label(id, "_L" + id, target);
}
public static Label createLabel(String name, boolean target) {
int id = labelCount++;
return new Label(id, name, target);
}
@Override
public String toString() {
return name;
}
}
package decaf.tac;
import java.util.Set;
import decaf.utils.MiscUtils;
public class Tac {
public enum Kind {
ADD, SUB, MUL, DIV, MOD, NEG, LAND, LOR, LNOT, GTR, GEQ, EQU, NEQ, LEQ,
LES, ASSIGN, LOAD_VTBL, INDIRECT_CALL, DIRECT_CALL, RETURN, BRANCH,
BEQZ, BNEZ, LOAD, STORE, LOAD_IMM4, LOAD_STR_CONST, MEMO, MARK, PARM
}
public Kind opc;
public boolean mark;
public Tac prev;
public Tac next;
public Temp op0;
public Temp op1;
public Temp op2;
public Label label;
public VTable vt;
public String str;
public int bbNum;
public Set<Temp> liveOut;
public Set<Temp> saves;
private Tac(Kind opc, Temp op0) {
this(opc, op0, null, null);
}
private Tac(Kind opc, Temp op0, Temp op1) {
this(opc, op0, op1, null);
}
private Tac(Kind opc, Temp op0, Temp op1, Temp op2) {
this.opc = opc;
this.op0 = op0;
this.op1 = op1;
this.op2 = op2;
}
private Tac(Kind opc, String str) {
this.opc = opc;
this.str = str;
}
private Tac(Kind opc, Temp op0, String str) {
this.opc = opc;
this.op0 = op0;
this.str = str;
}
private Tac(Kind opc, Temp op0, VTable vt) {
this.opc = opc;
this.op0 = op0;
this.vt = vt;
}
private Tac(Kind opc, Label label) {
this.opc = opc;
this.label = label;
}
private Tac(Kind opc, Temp op0, Label label) {
this.opc = opc;
this.op0 = op0;
this.label = label;
}
public static Tac genAdd(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.ADD, dst, src1, src2);
}
public static Tac genSub(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.SUB, dst, src1, src2);
}
public static Tac genMul(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.MUL, dst, src1, src2);
}
public static Tac genDiv(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.DIV, dst, src1, src2);
}
public static Tac genMod(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.MOD, dst, src1, src2);
}
public static Tac genNeg(Temp dst, Temp src) {
return new Tac(Kind.NEG, dst, src);
}
public static Tac genLAnd(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.LAND, dst, src1, src2);
}
public static Tac genLOr(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.LOR, dst, src1, src2);
}
public static Tac genLNot(Temp dst, Temp src) {
return new Tac(Kind.LNOT, dst, src);
}
public static Tac genGtr(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.GTR, dst, src1, src2);
}
public static Tac genGeq(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.GEQ, dst, src1, src2);
}
public static Tac genEqu(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.EQU, dst, src1, src2);
}
public static Tac genNeq(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.NEQ, dst, src1, src2);
}
public static Tac genLeq(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.LEQ, dst, src1, src2);
}
public static Tac genLes(Temp dst, Temp src1, Temp src2) {
return new Tac(Kind.LES, dst, src1, src2);
}
public static Tac genAssign(Temp dst, Temp src) {
return new Tac(Kind.ASSIGN, dst, src);
}
public static Tac genLoadVtbl(Temp dst, VTable vt) {
return new Tac(Kind.LOAD_VTBL, dst, vt);
}
public static Tac genIndirectCall(Temp dst, Temp func) {
return new Tac(Kind.INDIRECT_CALL, dst, func);
}
public static Tac genDirectCall(Temp dst, Label func) {
return new Tac(Kind.DIRECT_CALL, dst, func);
}
public static Tac genReturn(Temp src) {
return new Tac(Kind.RETURN, src);
}
public static Tac genBranch(Label label) {
label.target = true;
return new Tac(Kind.BRANCH, label);
}
public static Tac genBeqz(Temp cond, Label label) {
label.target = true;
return new Tac(Kind.BEQZ, cond, label);
}
public static Tac genBnez(Temp cond, Label label) {
label.target = true;
return new Tac(Kind.BNEZ, cond, label);
}
public static Tac genLoad(Temp dst, Temp base, Temp offset) {
if (!offset.isConst) {
throw new IllegalArgumentException("offset must be const temp");
}
return new Tac(Kind.LOAD, dst, base, offset);
}
public static Tac genStore(Temp src, Temp base, Temp offset) {
if (!offset.isConst) {
throw new IllegalArgumentException("offset must be const temp");
}
return new Tac(Kind.STORE, src, base, offset);
}
public static Tac genLoadImm4(Temp dst, Temp val) {
if (!val.isConst) {
throw new IllegalArgumentException("val must be const temp");
}
return new Tac(Kind.LOAD_IMM4, dst, val);
}
public static Tac genLoadStrConst(Temp dst, String str) {
return new Tac(Kind.LOAD_STR_CONST, dst, str);
}
public static Tac genMemo(String memo) {
return new Tac(Kind.MEMO, memo);
}
public static Tac genMark(Label label) {
Tac mark = new Tac(Kind.MARK, label);
label.where = mark;
return mark;
}
public static Tac genParm(Temp src) {
return new Tac(Kind.PARM, src);
}
private String binanyOpToString(String op) {
return op0.name + " = (" + op1.name + " " + op + " " + op2.name + ")";
}
private String unaryOpToString(String op) {
return op0.name + " = " + op + " " + op1.name;
}
public String toString() {
switch (opc) {
case ADD:
return binanyOpToString("+");
case SUB:
return binanyOpToString("-");
case MUL:
return binanyOpToString("*");
case DIV:
return binanyOpToString("/");
case MOD:
return binanyOpToString("%");
case NEG:
return unaryOpToString("-");
case LAND:
return binanyOpToString("&&");
case LOR:
return binanyOpToString("||");
case LNOT:
return unaryOpToString("!");
case GTR:
return binanyOpToString(">");
case GEQ:
return binanyOpToString(">=");
case EQU:
return binanyOpToString("==");
case NEQ:
return binanyOpToString("!=");
case LEQ:
return binanyOpToString("<=");
case LES:
return binanyOpToString("<");
case ASSIGN:
return op0.name + " = " + op1.name;
case LOAD_VTBL:
return op0.name + " = VTBL <" + vt.name + ">";
case INDIRECT_CALL:
if (op0 != null) {
return op0.name + " = " + " call " + op1.name;
} else {
return "call " + op1.name;
}
case DIRECT_CALL:
if (op0 != null) {
return op0.name + " = " + " call " + label.name;
} else {
return "call " + label.name;
}
case RETURN:
if (op0 != null) {
return "return " + op0.name;
} else {
return "return <empty>";
}
case BRANCH:
return "branch " + label.name;
case BEQZ:
return "if (" + op0.name + " == 0) branch " + label.name;
case BNEZ:
return "if (" + op0.name + " != 0) branch " + label.name;
case LOAD:
if (op2.value >= 0) {
return op0.name + " = *(" + op1.name + " + " + op2.value + ")";
} else {
return op0.name + " = *(" + op1.name + " - " + (-op2.value)
+ ")";
}
case STORE:
if (op2.value >= 0) {
return "*(" + op1.name + " + " + op2.value + ") = " + op0.name;
} else {
return "*(" + op1.name + " - " + (-op2.value) + ") = "
+ op0.name;
}
case LOAD_IMM4:
return op0.name + " = " + op1.value;
case LOAD_STR_CONST:
return op0.name + " = " + MiscUtils.quote(str);
case MEMO:
return "memo '" + str + "'";
case MARK:
return label.name + ":";
case PARM:
return "parm " + op0.name;
default:
throw new RuntimeException("unknown opc");
}
}
}
package decaf.tac;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import decaf.symbol.Variable;
public class Temp {
public int id;
public String name;
public int offset = Integer.MAX_VALUE;
public int size;
public Variable sym;
public boolean isConst;
public int value;
public boolean isParam;
public boolean isLoaded;
private static int tempCount = 0;
public static final Comparator<Temp> ID_COMPARATOR = new Comparator<Temp>() {
@Override
public int compare(Temp o1, Temp o2) {
return o1.id > o2.id ? 1 : o1.id == o2.id ? 0 : -1;
}
};
public Temp() {
}
public Temp(int id, String name, int size, int offset) {
this.id = id;
this.name = name;
this.size = size;
this.offset = offset;
}
public static Temp createTempI4() {
int id = tempCount++;
return new Temp(id, "_T" + id, 4, Integer.MAX_VALUE);
}
private static Map<Integer, Temp> constTempPool = new HashMap<Integer, Temp>();
public static Temp createConstTemp(int value) {
Temp temp = constTempPool.get(value);
if (temp == null) {
temp = new Temp();
temp.isConst = true;
temp.value = value;
temp.name = Integer.toString(value);
constTempPool.put(value, temp);
}
return temp;
}
public boolean isOffsetFixed() {
return offset != Integer.MAX_VALUE;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Temp) {
return id == ((Temp) obj).id;
}
return false;
}
@Override
public int hashCode() {
return id;
}
@Override
public String toString() {
return name;
}
}
package decaf.tac;
public class VTable {
public String name;
public VTable parent;
public String className;
public Label[] entries;
}
package decaf.translate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import decaf.tree.Tree;
import decaf.backend.OffsetCounter;
import decaf.symbol.Class;
import decaf.symbol.Function;
import decaf.symbol.Symbol;
import decaf.symbol.Variable;
import decaf.tac.Temp;
public class TransPass1 extends Tree.Visitor {
private Translater tr;
private int objectSize;
private List<Variable> vars;
public TransPass1(Translater tr) {
this.tr = tr;
vars = new ArrayList<Variable>();
}
@Override
public void visitTopLevel(Tree.TopLevel program) {
for (Tree.ClassDef cd : program.classes) {
cd.accept(this);
}
for (Tree.ClassDef cd : program.classes) {
tr.createVTable(cd.symbol);
tr.genNewForClass(cd.symbol);
}
for (Tree.ClassDef cd : program.classes) {
if (cd.parent != null) {
cd.symbol.getVtable().parent = cd.symbol.getParent()
.getVtable();
}
}
}
@Override
public void visitClassDef(Tree.ClassDef classDef) {
classDef.symbol.resolveFieldOrder();
objectSize = 0;
vars.clear();
for (Tree f : classDef.fields) {
f.accept(this);
}
Collections.sort(vars, Symbol.ORDER_COMPARATOR);
OffsetCounter oc = OffsetCounter.VARFIELD_OFFSET_COUNTER;
Class c = classDef.symbol.getParent();
if (c != null) {
oc.set(c.getSize());
} else {
oc.reset();
}
for (Variable v : vars) {
v.setOffset(oc.next(OffsetCounter.WORD_SIZE));
}
}
@Override
public void visitMethodDef(Tree.MethodDef funcDef) {
Function func = funcDef.symbol;
if (!func.isStatik()) {
func.setOffset(2 * OffsetCounter.POINTER_SIZE + func.getOrder()
* OffsetCounter.POINTER_SIZE);
}
tr.createFuncty(func);
OffsetCounter oc = OffsetCounter.PARAMETER_OFFSET_COUNTER;
oc.reset();
int order;
if (!func.isStatik()) {
Variable v = (Variable) func.getAssociatedScope().lookup("this");
v.setOrder(0);
Temp t = Temp.createTempI4();
t.sym = v;
t.isParam = true;
v.setTemp(t);
v.setOffset(oc.next(OffsetCounter.POINTER_SIZE));
order = 1;
} else {
order = 0;
}
for (Tree.VarDef vd : funcDef.formals) {
vd.symbol.setOrder(order++);
Temp t = Temp.createTempI4();
t.sym = vd.symbol;
t.isParam = true;
vd.symbol.setTemp(t);
vd.symbol.setOffset(oc.next(vd.symbol.getTemp().size));
}
}
@Override
public void visitVarDef(Tree.VarDef varDef) {
vars.add(varDef.symbol);
objectSize += OffsetCounter.WORD_SIZE;
}
}
package decaf.translate;
import java.util.Stack;
import decaf.tree.Tree;
import decaf.backend.OffsetCounter;
import decaf.machdesc.Intrinsic;
import decaf.symbol.Variable;
import decaf.tac.Label;
import decaf.tac.Temp;
import decaf.type.BaseType;
public class TransPass2 extends Tree.Visitor {
private Translater tr;
private Temp currentThis;
private Stack<Label> loopExits;
public TransPass2(Translater tr) {
this.tr = tr;
loopExits = new Stack<Label>();
}
@Override
public void visitClassDef(Tree.ClassDef classDef) {
for (Tree f : classDef.fields) {
f.accept(this);
}
}
@Override
public void visitMethodDef(Tree.MethodDef funcDefn) {
if (!funcDefn.statik) {
currentThis = ((Variable) funcDefn.symbol.getAssociatedScope()
.lookup("this")).getTemp();
}
tr.beginFunc(funcDefn.symbol);
funcDefn.body.accept(this);
tr.endFunc();
currentThis = null;
}
@Override
public void visitTopLevel(Tree.TopLevel program) {
for (Tree.ClassDef cd : program.classes) {
cd.accept(this);
}
}
@Override
public void visitVarDef(Tree.VarDef varDef) {
if (varDef.symbol.isLocalVar()) {
Temp t = Temp.createTempI4();
t.sym = varDef.symbol;
varDef.symbol.setTemp(t);
}
}
@Override
public void visitBinary(Tree.Binary expr) {
expr.left.accept(this);
expr.right.accept(this);
switch (expr.tag) {
case Tree.PLUS:
expr.val = tr.genAdd(expr.left.val, expr.right.val);
break;
case Tree.MINUS:
expr.val = tr.genSub(expr.left.val, expr.right.val);
break;
case Tree.MUL:
expr.val = tr.genMul(expr.left.val, expr.right.val);
break;
case Tree.DIV:
expr.val = tr.genDiv(expr.left.val, expr.right.val);
break;
case Tree.MOD:
expr.val = tr.genMod(expr.left.val, expr.right.val);
break;
case Tree.AND:
expr.val = tr.genLAnd(expr.left.val, expr.right.val);
break;
case Tree.OR:
expr.val = tr.genLOr(expr.left.val, expr.right.val);
break;
case Tree.LT:
expr.val = tr.genLes(expr.left.val, expr.right.val);
break;
case Tree.LE:
expr.val = tr.genLeq(expr.left.val, expr.right.val);
break;
case Tree.GT:
expr.val = tr.genGtr(expr.left.val, expr.right.val);
break;
case Tree.GE:
expr.val = tr.genGeq(expr.left.val, expr.right.val);
break;
case Tree.EQ:
case Tree.NE:
genEquNeq(expr);
break;
}
}
private void genEquNeq(Tree.Binary expr) {
if (expr.left.type.equal(BaseType.STRING)
|| expr.right.type.equal(BaseType.STRING)) {
tr.genParm(expr.left.val);
tr.genParm(expr.right.val);
expr.val = tr.genDirectCall(Intrinsic.STRING_EQUAL.label,
BaseType.BOOL);
if(expr.tag == Tree.NE){
expr.val = tr.genLNot(expr.val);
}
} else {
if(expr.tag == Tree.EQ)
expr.val = tr.genEqu(expr.left.val, expr.right.val);
else
expr.val = tr.genNeq(expr.left.val, expr.right.val);
}
}
@Override
public void visitAssign(Tree.Assign assign) {
assign.left.accept(this);
assign.expr.accept(this);
switch (assign.left.lvKind) {
case ARRAY_ELEMENT:
Tree.Indexed arrayRef = (Tree.Indexed) assign.left;
Temp esz = tr.genLoadImm4(OffsetCounter.WORD_SIZE);
Temp t = tr.genMul(arrayRef.index.val, esz);
Temp base = tr.genAdd(arrayRef.array.val, t);
tr.genStore(assign.expr.val, base, 0);
break;
case MEMBER_VAR:
Tree.Ident varRef = (Tree.Ident) assign.left;
tr.genStore(assign.expr.val, varRef.owner.val, varRef.symbol
.getOffset());
break;
case PARAM_VAR:
case LOCAL_VAR:
tr.genAssign(((Tree.Ident) assign.left).symbol.getTemp(),
assign.expr.val);
break;
}
}
@Override
public void visitLiteral(Tree.Literal literal) {
switch (literal.typeTag) {
case Tree.INT:
literal.val = tr.genLoadImm4(((Integer)literal.value).intValue());
break;
case Tree.BOOL:
literal.val = tr.genLoadImm4((Boolean)(literal.value) ? 1 : 0);
break;
default:
literal.val = tr.genLoadStrConst((String)literal.value);
}
}
@Override
public void visitExec(Tree.Exec exec) {
exec.expr.accept(this);
}
@Override
public void visitUnary(Tree.Unary expr) {
expr.expr.accept(this);
switch (expr.tag){
case Tree.NEG:
expr.val = tr.genNeg(expr.expr.val);
break;
default:
expr.val = tr.genLNot(expr.expr.val);
}
}
@Override
public void visitNull(Tree.Null nullExpr) {
nullExpr.val = tr.genLoadImm4(0);
}
@Override
public void visitBlock(Tree.Block block) {
for (Tree s : block.block) {
s.accept(this);
}
}
@Override
public void visitThisExpr(Tree.ThisExpr thisExpr) {
thisExpr.val = currentThis;
}
@Override
public void visitReadIntExpr(Tree.ReadIntExpr readIntExpr) {
readIntExpr.val = tr.genIntrinsicCall(Intrinsic.READ_INT);
}
@Override
public void visitReadLineExpr(Tree.ReadLineExpr readStringExpr) {
readStringExpr.val = tr.genIntrinsicCall(Intrinsic.READ_LINE);
}
@Override
public void visitReturn(Tree.Return returnStmt) {
if (returnStmt.expr != null) {
returnStmt.expr.accept(this);
tr.genReturn(returnStmt.expr.val);
} else {
tr.genReturn(null);
}
}
@Override
public void visitPrint(Tree.Print printStmt) {
for (Tree.Expr r : printStmt.exprs) {
r.accept(this);
tr.genParm(r.val);
if (r.type.equal(BaseType.BOOL)) {
tr.genIntrinsicCall(Intrinsic.PRINT_BOOL);
} else if (r.type.equal(BaseType.INT)) {
tr.genIntrinsicCall(Intrinsic.PRINT_INT);
} else if (r.type.equal(BaseType.STRING)) {
tr.genIntrinsicCall(Intrinsic.PRINT_STRING);
}
}
}
@Override
public void visitIndexed(Tree.Indexed indexed) {
indexed.array.accept(this);
indexed.index.accept(this);
tr.genCheckArrayIndex(indexed.array.val, indexed.index.val);
Temp esz = tr.genLoadImm4(OffsetCounter.WORD_SIZE);
Temp t = tr.genMul(indexed.index.val, esz);
Temp base = tr.genAdd(indexed.array.val, t);
indexed.val = tr.genLoad(base, 0);
}
@Override
public void visitIdent(Tree.Ident ident) {
if(ident.lvKind == Tree.LValue.Kind.MEMBER_VAR){
ident.owner.accept(this);
}
switch (ident.lvKind) {
case MEMBER_VAR:
ident.val = tr.genLoad(ident.owner.val, ident.symbol.getOffset());
break;
default:
ident.val = ident.symbol.getTemp();
break;
}
}
@Override
public void visitBreak(Tree.Break breakStmt) {
tr.genBranch(loopExits.peek());
}
@Override
public void visitCallExpr(Tree.CallExpr callExpr) {
if (callExpr.isArrayLength) {
callExpr.receiver.accept(this);
callExpr.val = tr.genLoad(callExpr.receiver.val,
-OffsetCounter.WORD_SIZE);
} else {
if (callExpr.receiver != null) {
callExpr.receiver.accept(this);
}
for (Tree.Expr expr : callExpr.actuals) {
expr.accept(this);
}
if (callExpr.receiver != null) {
tr.genParm(callExpr.receiver.val);
}
for (Tree.Expr expr : callExpr.actuals) {
tr.genParm(expr.val);
}
if (callExpr.receiver == null) {
callExpr.val = tr.genDirectCall(
callExpr.symbol.getFuncty().label, callExpr.symbol
.getReturnType());
} else {
Temp vt = tr.genLoad(callExpr.receiver.val, 0);
Temp func = tr.genLoad(vt, callExpr.symbol.getOffset());
callExpr.val = tr.genIndirectCall(func, callExpr.symbol
.getReturnType());
}
}
}
@Override
public void visitForLoop(Tree.ForLoop forLoop) {
if (forLoop.init != null) {
forLoop.init.accept(this);
}
Label cond = Label.createLabel();
Label loop = Label.createLabel();
tr.genBranch(cond);
tr.genMark(loop);
if (forLoop.update != null) {
forLoop.update.accept(this);
}
tr.genMark(cond);
forLoop.condition.accept(this);
Label exit = Label.createLabel();
tr.genBeqz(forLoop.condition.val, exit);
loopExits.push(exit);
if (forLoop.loopBody != null) {
forLoop.loopBody.accept(this);
}
tr.genBranch(loop);
loopExits.pop();
tr.genMark(exit);
}
@Override
public void visitIf(Tree.If ifStmt) {
ifStmt.condition.accept(this);
if (ifStmt.falseBranch != null) {
Label falseLabel = Label.createLabel();
tr.genBeqz(ifStmt.condition.val, falseLabel);
ifStmt.trueBranch.accept(this);
Label exit = Label.createLabel();
tr.genBranch(exit);
tr.genMark(falseLabel);
ifStmt.falseBranch.accept(this);
tr.genMark(exit);
} else if (ifStmt.trueBranch != null) {
Label exit = Label.createLabel();
tr.genBeqz(ifStmt.condition.val, exit);
if (ifStmt.trueBranch != null) {
ifStmt.trueBranch.accept(this);
}
tr.genMark(exit);
}
}
@Override
public void visitNewArray(Tree.NewArray newArray) {
newArray.length.accept(this);
newArray.val = tr.genNewArray(newArray.length.val);
}
@Override
public void visitNewClass(Tree.NewClass newClass) {
newClass.val = tr.genDirectCall(newClass.symbol.getNewFuncLabel(),
BaseType.INT);
}
@Override
public void visitWhileLoop(Tree.WhileLoop whileLoop) {
Label loop = Label.createLabel();
tr.genMark(loop);
whileLoop.condition.accept(this);
Label exit = Label.createLabel();
tr.genBeqz(whileLoop.condition.val, exit);
loopExits.push(exit);
if (whileLoop.loopBody != null) {
whileLoop.loopBody.accept(this);
}
tr.genBranch(loop);
loopExits.pop();
tr.genMark(exit);
}
@Override
public void visitTypeTest(Tree.TypeTest typeTest) {
typeTest.instance.accept(this);
typeTest.val = tr.genInstanceof(typeTest.instance.val,
typeTest.symbol);
}
@Override
public void visitTypeCast(Tree.TypeCast typeCast) {
typeCast.expr.accept(this);
if (!typeCast.expr.type.compatible(typeCast.symbol.getType())) {
tr.genClassCast(typeCast.expr.val, typeCast.symbol);
}
typeCast.val = typeCast.expr.val;
}
}
package decaf.type;
public class ArrayType extends Type {
private Type elementType;
public Type getElementType() {
return elementType;
}
public ArrayType(Type elementType) {
this.elementType = elementType;
}
@Override
public boolean compatible(Type type) {
if (type.equal(BaseType.ERROR)) {
return true;
}
return equal(type);
}
@Override
public boolean equal(Type type) {
if (!type.isArrayType()) {
return false;
}
return elementType.equal(((ArrayType) type).elementType);
}
@Override
public String toString() {
return elementType + "[]";
}
@Override
public boolean isArrayType() {
return true;
}
}
package decaf.type;
public class BaseType extends Type {
private final String typeName;
private BaseType(String typeName) {
this.typeName = typeName;
}
public static final BaseType INT = new BaseType("int");
public static final BaseType BOOL = new BaseType("bool");
public static final BaseType NULL = new BaseType("null");
public static final BaseType ERROR = new BaseType("Error");
public static final BaseType STRING = new BaseType("string");
public static final BaseType VOID = new BaseType("void");
@Override
public boolean isBaseType() {
return true;
}
@Override
public boolean compatible(Type type) {
if (equal(ERROR) || type.equal(ERROR)) {
return true;
}
if (equal(NULL) && type.isClassType()) {
return true;
}
return equal(type);
}
@Override
public boolean equal(Type type) {
return this == type;
}
@Override
public String toString() {
return typeName;
}
}
package decaf.type;
import decaf.scope.ClassScope;
import decaf.symbol.Class;
public class ClassType extends Type {
private Class symbol;
private ClassType parent;
public ClassType(Class symbol, ClassType parent) {
this.symbol = symbol;
this.parent = parent;
}
@Override
public boolean compatible(Type type) {
if (type.equal(BaseType.ERROR)) {
return true;
}
if (!type.isClassType()) {
return false;
}
for (ClassType t = this; t != null; t = t.parent) {
if (t.equal(type)) {
return true;
}
}
return false;
}
@Override
public boolean equal(Type type) {
return type.isClassType() && symbol == ((ClassType) type).symbol;
}
@Override
public boolean isClassType() {
return true;
}
@Override
public String toString() {
return "class : " + symbol.getName();
}
public Class getSymbol() {
return symbol;
}
public ClassType getParentType() {
return parent;
}
public ClassScope getClassScope() {
return symbol.getAssociatedScope();
}
}
package decaf.type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class FuncType extends Type {
private Type returnType;
private List<Type> argList;
public FuncType(Type returnType) {
this.returnType = returnType;
argList = new ArrayList<Type>();
}
public int numOfParams() {
return argList.size();
}
public void appendParam(Type type) {
argList.add(type);
}
@Override
public boolean compatible(Type type) {
if (type.equal(BaseType.ERROR)) {
return true;
}
if (!type.isFuncType()) {
return false;
}
FuncType ft = (FuncType) type;
if (!returnType.compatible(ft.returnType)
|| argList.size() != ft.argList.size()) {
return false;
}
Iterator<Type> iter1 = argList.iterator();
iter1.next();
Iterator<Type> iter2 = ft.argList.iterator();
iter2.next();
while (iter1.hasNext()) {
if (!iter2.next().compatible(iter1.next())) {
return false;
}
}
return true;
}
@Override
public boolean equal(Type type) {
return equals(type);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Type type : argList) {
sb.append(type + "->");
}
sb.append(returnType);
return sb.toString();
}
public Type getReturnType() {
return returnType;
}
@Override
public boolean isFuncType() {
return true;
}
public List<Type> getArgList() {
return argList;
}
}
package decaf.type;
public abstract class Type {
public boolean isBaseType() {
return false;
}
public boolean isArrayType() {
return false;
}
public boolean isClassType() {
return false;
}
public boolean isFuncType() {
return false;
}
public abstract boolean compatible(Type type);
public abstract boolean equal(Type type);
public abstract String toString();
}
package decaf.typecheck;
import java.util.Iterator;
import decaf.Driver;
import decaf.tree.Tree;
import decaf.error.BadArrElementError;
import decaf.error.BadInheritanceError;
import decaf.error.BadOverrideError;
import decaf.error.BadVarTypeError;
import decaf.error.ClassNotFoundError;
import decaf.error.DecafError;
import decaf.error.DeclConflictError;
import decaf.error.NoMainClassError;
import decaf.error.OverridingVarError;
import decaf.scope.ClassScope;
import decaf.scope.GlobalScope;
import decaf.scope.LocalScope;
import decaf.scope.ScopeStack;
import decaf.symbol.Class;
import decaf.symbol.Function;
import decaf.symbol.Symbol;
import decaf.symbol.Variable;
import decaf.type.BaseType;
import decaf.type.FuncType;
public class BuildSym extends Tree.Visitor {
private ScopeStack table;
private void issueError(DecafError error) {
Driver.getDriver().issueError(error);
}
public BuildSym(ScopeStack table) {
this.table = table;
}
public static void buildSymbol(Tree.TopLevel tree) {
new BuildSym(Driver.getDriver().getTable()).visitTopLevel(tree);
}
// root
@Override
public void visitTopLevel(Tree.TopLevel program) {
program.globalScope = new GlobalScope();
table.open(program.globalScope);
for (Tree.ClassDef cd : program.classes) {
Class c = new Class(cd.name, cd.parent, cd.getLocation());
Class earlier = table.lookupClass(cd.name);
if (earlier != null) {
issueError(new DeclConflictError(cd.getLocation(), cd.name,
earlier.getLocation()));
} else {
table.declare(c);
}
cd.symbol = c;
}
for (Tree.ClassDef cd : program.classes) {
Class c = cd.symbol;
if (cd.parent != null && c.getParent() == null) {
issueError(new ClassNotFoundError(cd.getLocation(), cd.parent));
c.dettachParent();
}
if (calcOrder(c) <= calcOrder(c.getParent())) {
issueError(new BadInheritanceError(cd.getLocation()));
c.dettachParent();
}
}
for (Tree.ClassDef cd : program.classes) {
cd.symbol.createType();
}
for (Tree.ClassDef cd : program.classes) {
cd.accept(this);
if (Driver.getDriver().getOption().getMainClassName().equals(
cd.name)) {
program.main = cd.symbol;
}
}
for (Tree.ClassDef cd : program.classes) {
checkOverride(cd.symbol);
}
if (!isMainClass(program.main)) {
issueError(new NoMainClassError(Driver.getDriver().getOption()
.getMainClassName()));
}
table.close();
}
// visiting declarations
@Override
public void visitClassDef(Tree.ClassDef classDef) {
table.open(classDef.symbol.getAssociatedScope());
for (Tree f : classDef.fields) {
f.accept(this);
}
table.close();
}
@Override
public void visitVarDef(Tree.VarDef varDef) {
varDef.type.accept(this);
if (varDef.type.type.equal(BaseType.VOID)) {
issueError(new BadVarTypeError(varDef.getLocation(), varDef.name));
// for argList
varDef.symbol = new Variable(".error", BaseType.ERROR, varDef
.getLocation());
return;
}
Variable v = new Variable(varDef.name, varDef.type.type,
varDef.getLocation());
Symbol sym = table.lookup(varDef.name, true);
if (sym != null) {
if (table.getCurrentScope().equals(sym.getScope())) {
issueError(new DeclConflictError(v.getLocation(), v.getName(),
sym.getLocation()));
} else if ((sym.getScope().isFormalScope() || sym.getScope()
.isLocalScope())) {
issueError(new DeclConflictError(v.getLocation(), v.getName(),
sym.getLocation()));
} else {
table.declare(v);
}
} else {
table.declare(v);
}
varDef.symbol = v;
}
@Override
public void visitMethodDef(Tree.MethodDef funcDef) {
funcDef.returnType.accept(this);
Function f = new Function(funcDef.statik, funcDef.name,
funcDef.returnType.type, funcDef.body, funcDef.getLocation());
funcDef.symbol = f;
Symbol sym = table.lookup(funcDef.name, false);
if (sym != null) {
issueError(new DeclConflictError(funcDef.getLocation(),
funcDef.name, sym.getLocation()));
} else {
table.declare(f);
}
table.open(f.getAssociatedScope());
for (Tree.VarDef d : funcDef.formals) {
d.accept(this);
f.appendParam(d.symbol);
}
funcDef.body.accept(this);
table.close();
}
// visiting types
@Override
public void visitTypeIdent(Tree.TypeIdent type) {
switch (type.typeTag) {
case Tree.VOID:
type.type = BaseType.VOID;
break;
case Tree.INT:
type.type = BaseType.INT;
break;
case Tree.BOOL:
type.type = BaseType.BOOL;
break;
default:
type.type = BaseType.STRING;
}
}
@Override
public void visitTypeClass(Tree.TypeClass typeClass) {
Class c = table.lookupClass(typeClass.name);
if (c == null) {
issueError(new ClassNotFoundError(typeClass.getLocation(),
typeClass.name));
typeClass.type = BaseType.ERROR;
} else {
typeClass.type = c.getType();
}
}
@Override
public void visitTypeArray(Tree.TypeArray typeArray) {
typeArray.elementType.accept(this);
if (typeArray.elementType.type.equal(BaseType.ERROR)) {
typeArray.type = BaseType.ERROR;
} else if (typeArray.elementType.type.equal(BaseType.VOID)) {
issueError(new BadArrElementError(typeArray.getLocation()));
typeArray.type = BaseType.ERROR;
} else {
typeArray.type = new decaf.type.ArrayType(
typeArray.elementType.type);
}
}
// for VarDecl in LocalScope
@Override
public void visitBlock(Tree.Block block) {
block.associatedScope = new LocalScope(block);
table.open(block.associatedScope);
for (Tree s : block.block) {
s.accept(this);
}
table.close();
}
@Override
public void visitForLoop(Tree.ForLoop forLoop) {
if (forLoop.loopBody != null) {
forLoop.loopBody.accept(this);
}
}
@Override
public void visitIf(Tree.If ifStmt) {
if (ifStmt.trueBranch != null) {
ifStmt.trueBranch.accept(this);
}
if (ifStmt.falseBranch != null) {
ifStmt.falseBranch.accept(this);
}
}
@Override
public void visitWhileLoop(Tree.WhileLoop whileLoop) {
if (whileLoop.loopBody != null) {
whileLoop.loopBody.accept(this);
}
}
private int calcOrder(Class c) {
if (c == null) {
return -1;
}
if (c.getOrder() < 0) {
c.setOrder(0);
c.setOrder(calcOrder(c.getParent()) + 1);
}
return c.getOrder();
}
private void checkOverride(Class c) {
if (c.isCheck()) {
return;
}
Class parent = c.getParent();
if (parent == null) {
return;
}
checkOverride(parent);
ClassScope parentScope = parent.getAssociatedScope();
ClassScope subScope = c.getAssociatedScope();
table.open(parentScope);
Iterator<Symbol> iter = subScope.iterator();
while (iter.hasNext()) {
Symbol suspect = iter.next();
Symbol sym = table.lookup(suspect.getName(), true);
if (sym != null && !sym.isClass()) {
if ((suspect.isVariable() && sym.isFunction())
|| (suspect.isFunction() && sym.isVariable())) {
issueError(new DeclConflictError(suspect.getLocation(),
suspect.getName(), sym.getLocation()));
iter.remove();
} else if (suspect.isFunction()) {
if (((Function) suspect).isStatik()
|| ((Function) sym).isStatik()) {
issueError(new DeclConflictError(suspect.getLocation(),
suspect.getName(), sym.getLocation()));
iter.remove();
} else if (!suspect.getType().compatible(sym.getType())) {
issueError(new BadOverrideError(suspect.getLocation(),
suspect.getName(),
((ClassScope) sym.getScope()).getOwner()
.getName()));
iter.remove();
}
} else if (suspect.isVariable()) {
issueError(new OverridingVarError(suspect.getLocation(),
suspect.getName()));
iter.remove();
}
}
}
table.close();
c.setCheck(true);
}
private boolean isMainClass(Class c) {
if (c == null) {
return false;
}
table.open(c.getAssociatedScope());
Symbol main = table.lookup(Driver.getDriver().getOption()
.getMainFuncName(), false);
if (main == null || !main.isFunction()) {
return false;
}
((Function) main).setMain(true);
FuncType type = (FuncType) main.getType();
return type.getReturnType().equal(BaseType.VOID)
&& type.numOfParams() == 0 && ((Function) main).isStatik();
}
}
package decaf.utils;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
/**
* 用于缩进输出的类<br>
* 使用时注意不要自行输出"\r\n"或"\n"进行换行,而要使用该类的println系列函数进行换行<br>
*
*
*
*/
public class IndentPrintWriter extends PrintWriter {
private int step;
private StringBuilder indent;
private boolean newLineBegin;
/**
*
* @param out
* @param step
* 每次缩进变化的空格数
*/
public IndentPrintWriter(OutputStream out, int step) {
this(new OutputStreamWriter(out), step);
}
/**
*
* @param out
* @param step
* 每次缩进变化的空格数
*/
public IndentPrintWriter(Writer out, int step) {
super(out);
this.step = step;
indent = new StringBuilder();
newLineBegin = true;
}
/**
* 增加缩进
*/
public void incIndent() {
for (int i = 0; i < step; i++) {
indent.append(" ");
}
}
/**
* 减少缩进
*/
public void decIndent() {
indent.setLength(indent.length() - step);
}
@Override
public void println() {
super.println();
newLineBegin = true;
}
private void writeIndent() {
if (newLineBegin) {
newLineBegin = false;
print(indent);
}
}
@Override
public void write(char[] buf, int off, int len) {
writeIndent();
super.write(buf, off, len);
}
@Override
public void write(int c) {
writeIndent();
super.write(c);
}
@Override
public void write(String s, int off, int len) {
writeIndent();
super.write(s, off, len);
}
}
package decaf.utils;
public final class MiscUtils {
/**
* 返回带转义符格式的字符串
*
* @param str
* 不带转义符的字符串(即内部表示)
* @return 带转义符的字符串(并加上双引号)
*/
public static String quote(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); ++i) {
char c = str.charAt(i);
switch (c) {
case '"':
sb.append("\\\"");
break;
case '\n':
sb.append("\\n");
break;
case '\t':
sb.append("\\t");
break;
case '\\':
sb.append("\\\\");
break;
default:
sb.append(c);
}
}
return ('"' + sb.toString() + '"');
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
Ant build file for TAC Virtual Machine.
author: Zhang Duo
date: Oct 4, 2007
DCST, Tsinghua University
-->
<project name="TAC Virtual Machine" default="4 pack">
<!-- 设置各种属性 -->
<property name="src.dir" value="src" />
<property name="result.dir" value="result" />
<property name="bin.dir" value="${result.dir}/bin" />
<property name="jflex.jar" value="tools/jflex/JFlex.jar" />
<condition property="byacc" value="tools/byacc/byacc.exe">
<or>
<os family="windows" arch="x86" />
<os family="windows" arch="amd64" />
</or>
</condition>
<condition property="byacc" value="${basedir}/tools/byacc/byacc.linux">
<or>
<os family="unix" arch="x86" />
<os family="unix" arch="i386" />
<os family="unix" arch="i486" />
<os family="unix" arch="i586" />
<os family="unix" arch="i686" />
</or>
</condition>
<condition property="byacc" value="${basedir}/tools/byacc/byacc.linux.amd64">
<or>
<os family="unix" arch="amd64" />
</or>
</condition>
<condition property="byacc" value="${basedir}/tools/byacc/byacc.mac">
<or>
<os family="mac" />
</or>
</condition>
<!-- 生成Lex和YACC结果 -->
<target name="1 jflex" description="Run JFlex...">
<java jar="${jflex.jar}" fork="true" maxmemory="128m" failonerror="true">
<sysproperty key="file.encoding" value="UTF-8" />
<arg value="${src.dir}/decaf/tacvm/parser/Lexer.l" />
</java>
<delete file="${src.dir}/decaf/tacvm/parser/Lexer.java~" />
</target>
<target name="2 byacc" description="Run BYACC/J...">
<chmod file="${byacc}" perm="+rx" />
<!-- for unix -->
<exec dir="${src.dir}/decaf/tacvm/parser" executable="${byacc}" failonerror="true">
<arg line="-v -J Parser.y" />
</exec>
<move file="${src.dir}/decaf/tacvm/parser/y" tofile="${src.dir}/decaf/tacvm/parser/Parser.output" />
</target>
<!-- 编译 -->
<target name="3 compile" depends="1 jflex,2 byacc" description="Compile All...">
<mkdir dir="${bin.dir}" />
<javac srcdir="${src.dir}" destdir="${bin.dir}" encoding="UTF8" debug="off" optimize="on" />
</target>
<!-- 打包 -->
<target name="4 pack" depends="3 compile" description="Prepare package...">
<jar destfile="${result.dir}/tac.jar">
<fileset dir="${bin.dir}" />
<manifest>
<attribute name="Signature-Version" value="3.14159" />
<attribute name="Main-Class" value="decaf.tacvm.TacVM" />
</manifest>
</jar>
</target>
<target name="clean" description="Clean...">
<delete dir="${result.dir}" />
</target>
</project>
package decaf.tacvm;
public class Location implements Comparable<Location> {
private int line;
private int column;
public Location(int lin, int col) {
line = lin;
column = col;
}
public int getLine() {
return line;
}
public int getColumn() {
return column;
}
public String toString() {
return "(" + line + "," + column + ")";
}
@Override
public int compareTo(Location o) {
if (line > o.line) {
return 1;
}
if (line < o.line) {
return -1;
}
if (column > o.column) {
return 1;
}
if (column < o.column) {
return -1;
}
return 0;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment