Repository: Great-Li-Xin/LiXinCompiler
Branch: master
Commit: d1f816745f33
Files: 45
Total size: 93.2 KB
Directory structure:
gitextract_mfeb4nvw/
├── .idea/
│ ├── inspectionProfiles/
│ │ └── Project_Default.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── uiDesigner.xml
│ ├── vcs.xml
│ └── workspace.xml
├── LICENSE
├── LiXinCompiler.iml
├── README.md
└── src/
└── com/
└── lixin/
├── interpreter/
│ ├── Access.java
│ ├── And.java
│ ├── Arithmetic.java
│ ├── Break.java
│ ├── Constant.java
│ ├── Do.java
│ ├── Else.java
│ ├── Expression.java
│ ├── Identifier.java
│ ├── If.java
│ ├── Logical.java
│ ├── Node.java
│ ├── Not.java
│ ├── Operator.java
│ ├── Or.java
│ ├── Relation.java
│ ├── Sequence.java
│ ├── Set.java
│ ├── SetElem.java
│ ├── Statement.java
│ ├── Temp.java
│ ├── Unary.java
│ └── While.java
├── lexer/
│ ├── Lexer.java
│ ├── Numeric.java
│ ├── Real.java
│ ├── Tag.java
│ ├── Token.java
│ └── Word.java
├── main/
│ ├── Compiler.java
│ ├── CompilerTestDriver.java
│ └── Main.java
├── parser/
│ └── Parser.java
└── symbols/
├── Array.java
├── Environment.java
└── Type.java
================================================
FILE CONTENTS
================================================
================================================
FILE: .idea/inspectionProfiles/Project_Default.xml
================================================
================================================
FILE: .idea/misc.xml
================================================
================================================
FILE: .idea/modules.xml
================================================
================================================
FILE: .idea/uiDesigner.xml
================================================
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
================================================
FILE: .idea/vcs.xml
================================================
================================================
FILE: .idea/workspace.xml
================================================
Temp
\n
\r\n
1527577851234
1527577851234
No facets are configured
1.8
LiXinCompiler
11
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 李欣
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: LiXinCompiler.iml
================================================
================================================
FILE: README.md
================================================
# LiXinCompiler
Referenced from the dragon-book, just a little implementation of the dragon-book language.
参考自龙书上的语言,自己实现了一个编译器的前端。
## GitHub链接
- [LiXinCompiler](https://github.com/realJustinLee/LiXinCompiler)
## 源语言
这个语言由一个程序和一个块组成,该块中包含可选的声名和语句。语法符号```basic```表示基本类型。
```
program -> block
block -> { declause statemets }
declause -> decaluse debracket | ϵ
debrcket -> type identity ;
type -> type [ num ] | basic
statements -> statements statement | ϵ
```
为了简化翻译工作,我们把赋值当成了一个语句.
```
statement -> location = bool ;
| if ( bool ) statement
| if ( bool ) stetement else statement
| while ( bool ) statement
| do statement while ( bool ) ;
| break ;
| block
location -> location [ bool ] | identity
```
表达式的产生式处理了运算符的结合性和优先级。它们对每个优先级都使用了一个非终结符号,而非终结符号```factor```用来表示括号中的表达式、标识符、数组引用和常量.
```
bool -> bool || join | join
join -> join && equality | equality
equality -> equality == relation | equality != relation | relation
relation -> expression < expression | expressoion <= expression |
expressoion >= expression | expressoion > expression | expression
expression -> expression + term | expression - term | term
term -> term * unary | term / unary | unary
factor -> ( bool ) | location | numeric | real | true | false
```
## 测试样例
### block:
输入
```
lxc>
{
int a; int b; a = 0; b = 0;
{
int b; b = 1;
{
int a; a = 2;
}
{
int b; b = 3;
}
a = a + 1; b = b + 1;
}
a = a + 1; b = b + 1;
}
```
输出
```
L1: a = 0
L3: b = 0
L4: b = 1
L6: a = 2
L7: b = 3
L8: a = a + 1
L9: b = b + 1
L5: a = a + 1
L10: b = b + 1
L2:
```
### expression:
输入
```
lxc>
{
int i; float x; bool b;
i = 0;
i = 365;
x = 0.0;
x = 3.14159;
b = true;
b = false;
i = x;
x = i;
}
```
输出
```
L1: i = 0
L3: i = 365
L4: x = 0.0
L5: x = 3.1415896
L6: b = true
L7: b = false
L8: i = x
L9: x = i
L2:
```
### identity:
输入
```
lxc>
{
int i; int j; float[10][10] a;
i = 0;
while ( i < 10 ) {
j = 0;
while ( j < 10 ) {
a[i][j] = 0.0;
j = j + 1;
}
i = i + 1;
}
i = 0;
while ( i < 10 ) {
a[i][i] = 1.0;
i = i + 1;
}
}
```
输出
```
L1: i = 0
L3: if not i < 10 goto L4
L5: j = 0
L6: if not j < 10 goto L7
L8: t1 = i * 80
t2 = j * 8
t3 = t1 + t2
a [ t3 ] = 0.0
L9: j = j + 1
goto L6
L7: i = i + 1
goto L3
L4: i = 0
L10: if not i < 10 goto L2
L11: t4 = i * 80
t5 = i * 8
t6 = t4 + t5
a [ t6 ] = 1.0
L12: i = i + 1
goto L10
L2:
```
### jump:
输入
```
lxc>
{
int x; int y; int a; int b;
if( true ) a = 0;
if( false ) x = 0;
if ( a < b ) a = b;
if ( x <= y ) x = y;
if ( a == b ) a = b;
if ( x != y ) x = y;
if ( a >= b ) b = a;
if ( x > y ) y = x;
if ( a == b );
if( x < 100 || x > 200 ) x = 0;
if( a < 100 && a > 200 ) b = 0;
if( x < 100 || (x > 200 && x != y) ) x = 0;
if( a < 100 || (a > 200 && a != 150) || a != 0 ) a = 0;
if( x > 200 && x != b || x < 100 ) x = 0;
if( a < 100 || a > 200 && a != b ) a = 0;
}
```
输出
```
L1:L4: a = 0
L3: goto L5
L6: x = 0
L5: if not a < b goto L7
L8: a = b
L7: if not x <= y goto L9
L10: x = y
L9: if not a == b goto L11
L12: a = b
L11: if not x != y goto L13
L14: x = y
L13: if not a >= b goto L15
L16: b = a
L15: if not x > y goto L17
L18: y = x
L17: if not a == b goto L19
L20:L19: if x < 100 goto L23
if not x > 200 goto L21
L23:L22: x = 0
L21: if not a < 100 goto L24
if not a > 200 goto L24
L25: b = 0
L24: if x < 100 goto L28
if not x > 200 goto L26
if not x != y goto L26
L28:L27: x = 0
L26: if a < 100 goto L31
if a != 150 goto L31
L32: if not a != 0 goto L29
L31:L30: a = 0
L29: if x != b goto L35
L36: if not x < 100 goto L33
L35:L34: x = 0
L33: if a < 100 goto L38
if not a > 200 goto L2
if not a != b goto L2
L38:L37: a = 0
L2:
```
### program:
输入
```
lxc>
{
int i; int j; float v; float x; float[100] a;
while( true ) {
do i = i+1; while( a[i] < v);
do j = j-1; while( a[j] > v);
if( i >= j ) break;
x = a[i]; a[i] = a[j]; a[j] = x;
}
}
```
输出
```
L1:L3: i = i + 1
L5: t1 = i * 8
t2 = a [ t1 ]
if t2 < v goto L3
L4: j = j - 1
L7: t3 = j * 8
t4 = a [ t3 ]
if t4 > v goto L4
L6: if not i >= j goto L8
L9: goto L2
L8: t5 = i * 8
x = a [ t5 ]
L10: t6 = i * 8
t7 = j * 8
t8 = a [ t7 ]
a [ t6 ] = t8
L11: t9 = j * 8
a [ t9 ] = x
goto L1
L2:
```
# 关于BUG、建议与意见
请在[GitHub](https://github.com/realJustinLee/LiXinCompiler)中提[issue](https://github.com/realJustinLee/LiXinCompiler/issues/new)
我会尽快回答
================================================
FILE: src/com/lixin/interpreter/Access.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Tag;
import com.lixin.lexer.Word;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Access extends Operator {
Identifier array;
Expression index;
/**
* @param array 数组
* @param index 下标
* @param type 数组元素类型
*/
public Access(Identifier array, Expression index, Type type) {
super(new Word("[]", Tag.INDEX), type);
this.array = array;
this.index = index;
}
@Override
public Expression generate() {
return new Access(array, index.reduce(), type);
}
@Override
public void jumping(int positive, int negative) {
emitJumps(reduce().toString(), positive, negative);
}
@Override
public String toString() {
return array.toString() + " [ " + index.toString() + " ]";
}
}
================================================
FILE: src/com/lixin/interpreter/And.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Token;
/**
* @author lixin
*/
public class And extends Logical {
public And(Token token, Expression expression1, Expression expression2) {
super(token, expression1, expression2);
}
@Override
public void jumping(int positive, int negative) {
int label = negative != 0 ? negative : newLabel();
expression1.jumping(0, negative);
expression2.jumping(positive, negative);
if (negative == 0) {
emitLabel(label);
}
}
}
================================================
FILE: src/com/lixin/interpreter/Arithmetic.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Token;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Arithmetic extends Operator {
private Expression expression1, expression2;
public Arithmetic(Token token, Expression expression1, Expression expression2) {
super(token, null);
this.expression1 = expression1;
this.expression2 = expression2;
type = Type.max(expression1.type, expression2.type);
if (type == null) {
error("type error");
}
}
@Override
public Expression generate() {
return new Arithmetic(operator, expression1.reduce(), expression2.reduce());
}
@Override
public String toString() {
return expression1.toString() + " " + operator.toString() + " " + expression2.toString();
}
}
================================================
FILE: src/com/lixin/interpreter/Break.java
================================================
package com.lixin.interpreter;
/**
* @author lixin
*/
public class Break extends Statement {
private Statement statement;
public Break() {
if (Statement.ENCLOSING == Statement.NULL) {
error("unenclosed break");
}
statement = Statement.ENCLOSING;
}
@Override
public void generate(int begin, int first) {
emit("goto L" + statement.after);
}
}
================================================
FILE: src/com/lixin/interpreter/Constant.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Numeric;
import com.lixin.lexer.Token;
import com.lixin.lexer.Word;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Constant extends Expression {
public Constant(Token token, Type type) {
super(token, type);
}
public Constant(int input) {
super(new Numeric(input), Type.INT);
}
public static final Constant
TRUE = new Constant(Word.TRUE, Type.BOOL),
FALSE = new Constant(Word.FALSE, Type.BOOL);
@Override
public void jumping(int positive, int negative) {
if (this == TRUE && positive != 0) {
emit("goto L" + positive);
} else if (this == FALSE && negative != 0) {
emit("goto L" + negative);
}
}
}
================================================
FILE: src/com/lixin/interpreter/Do.java
================================================
package com.lixin.interpreter;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Do extends Statement {
private Expression expression;
private Statement statement;
public Do() {
expression = null;
statement = null;
}
// public void init(Expression expression1, Statement statement)
public void init(Statement statement, Expression expression) {
this.statement = statement;
this.expression = expression;
if (expression.type != Type.BOOL) {
expression.error("boolean required in do");
}
}
@Override
public void generate(int begin, int first) {
after = first;
int label = newLabel();
statement.generate(begin, label);
emitLabel(label);
expression.jumping(begin, 0);
}
}
================================================
FILE: src/com/lixin/interpreter/Else.java
================================================
package com.lixin.interpreter;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Else extends Statement {
private Expression expression;
private Statement statement1;
private Statement statement2;
public Else(Expression expression, Statement statement1, Statement statement2) {
this.expression = expression;
this.statement1 = statement1;
this.statement2 = statement2;
if (expression.type != Type.BOOL) {
expression.error("boolean required in if");
}
}
@Override
public void generate(int begin, int first) {
int label1 = newLabel();
int label2 = newLabel();
expression.jumping(0, label2);
emitLabel(label1);
statement1.generate(label1, first);
emit("goto L" + first);
emitLabel(label2);
statement2.generate(label2, first);
}
}
================================================
FILE: src/com/lixin/interpreter/Expression.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Token;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Expression extends Node {
Token operator;
public Type type;
Expression(Token operator, Type type) {
this.operator = operator;
this.type = type;
}
public Expression generate() {
return this;
}
public Expression reduce() {
return this;
}
public void jumping(int positive, int negative) {
emitJumps(toString(), positive, negative);
}
void emitJumps(String condition, int positive, int negative) {
if (positive != 0 && negative != 0) {
emit("if " + condition + " goto L" + positive);
emit("goto L" + negative);
} else if (positive != 0) {
emit("if " + condition + " goto L" + positive);
} else if (negative != 0) {
emit("if not " + condition + " goto L" + negative);
}
}
@Override
public String toString() {
return operator.toString();
}
}
================================================
FILE: src/com/lixin/interpreter/Identifier.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Word;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Identifier extends Expression {
private int offset;
public Identifier(Word identifier, Type type, int offset) {
super(identifier, type);
this.offset = offset;
}
}
================================================
FILE: src/com/lixin/interpreter/If.java
================================================
package com.lixin.interpreter;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class If extends Statement {
private Expression expression;
private Statement statement;
public If(Expression expression, Statement statement) {
this.expression = expression;
this.statement = statement;
if (expression.type != Type.BOOL) {
expression.error("boolean required in if");
}
}
@Override
public void generate(int begin, int first) {
// statement 的代码标号
int label = newLabel();
expression.jumping(0, first);
emitLabel(label);
statement.generate(label, first);
}
}
================================================
FILE: src/com/lixin/interpreter/Logical.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Token;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Logical extends Expression {
Expression expression1, expression2;
Logical(Token token, Expression expression1, Expression expression2) {
super(token, null);
this.expression1 = expression1;
this.expression2 = expression2;
type = check(expression1.type, expression2.type);
if (type == null) {
error("type error");
}
}
public Type check(Type type1, Type type2) {
return type1 == Type.BOOL && type2 == Type.BOOL ? Type.BOOL : null;
}
@Override
public Expression generate() {
int negative = newLabel();
int after = newLabel();
Temp temp = new Temp(type);
this.jumping(0, negative);
emit(temp.toString() + " = true");
emit("goto L" + after);
emitLabel(negative);
emit(temp.toString() + " = false");
emitLabel(after);
return temp;
}
@Override
public String toString() {
return expression1.toString() + " " + operator.toString() + " " + expression2.toString();
}
}
================================================
FILE: src/com/lixin/interpreter/Node.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Lexer;
/**
* @author lixin
*/
public class Node {
private int lexLine;
Node() {
lexLine = Lexer.line;
}
void error(String message) {
throw new Error("near line " + lexLine + ": " + message);
}
private static int labels = 0;
public int newLabel() {
return ++labels;
}
public void emitLabel(int i) {
System.out.print("L" + i + ":");
}
public void emit(String string) {
System.out.println("\t" + string);
}
}
================================================
FILE: src/com/lixin/interpreter/Not.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Token;
/**
* @author lixin
*/
public class Not extends Logical {
public Not(Token token, Expression expression2) {
super(token, expression2, expression2);
}
@Override
public void jumping(int positive, int negative) {
expression2.jumping(negative, positive);
}
@Override
public String toString() {
return operator.toString() + " " + expression2.toString();
}
}
================================================
FILE: src/com/lixin/interpreter/Operator.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Token;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Operator extends Expression {
Operator(Token token, Type type) {
super(token, type);
}
@Override
public Expression reduce() {
Expression expression = generate();
Temp temp = new Temp(type);
emit(temp.toString() + " = " + expression.toString());
return temp;
}
}
================================================
FILE: src/com/lixin/interpreter/Or.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Token;
/**
* @author lixin
*/
public class Or extends Logical {
public Or(Token token, Expression expression1, Expression expression2) {
super(token, expression1, expression2);
}
@Override
public void jumping(int positive, int negative) {
int label = positive != 0 ? positive : newLabel();
expression1.jumping(label, 0);
expression2.jumping(positive, negative);
if (positive == 0) {
emitLabel(label);
}
}
}
================================================
FILE: src/com/lixin/interpreter/Relation.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Token;
import com.lixin.symbols.Array;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Relation extends Logical {
public Relation(Token token, Expression expression1, Expression expression2) {
super(token, expression1, expression2);
}
@Override
public Type check(Type type1, Type type2) {
/*if (type1 instanceof Array || type2 instanceof Array) {
return null;
} else if (type1 == type2) {
return Type.BOOL;
} else {
return null;
}*/
return type1 instanceof Array || type2 instanceof Array ? null : type1 == type2 ? Type.BOOL : null;
}
@Override
public void jumping(int positive, int negative) {
Expression expressionA = expression1.reduce();
Expression expressionB = expression2.reduce();
String condition = expressionA.toString() + " " + operator.toString() + " " + expressionB.toString();
emitJumps(condition, positive, negative);
}
}
================================================
FILE: src/com/lixin/interpreter/Sequence.java
================================================
package com.lixin.interpreter;
/**
* @author lixin
*/
public class Sequence extends Statement {
private Statement statement1;
private Statement statement2;
public Sequence(Statement statement1, Statement statement2) {
this.statement1 = statement1;
this.statement2 = statement2;
}
@Override
public void generate(int begin, int first) {
if (statement1 == Statement.NULL) {
statement2.generate(begin, first);
} else if (statement2 == Statement.NULL) {
statement1.generate(begin, first);
} else {
int label = newLabel();
statement1.generate(begin, label);
emitLabel(label);
statement2.generate(label, first);
}
}
}
================================================
FILE: src/com/lixin/interpreter/Set.java
================================================
package com.lixin.interpreter;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Set extends Statement {
private Identifier identifier;
private Expression expression;
public Set(Identifier identifier, Expression expression) {
this.identifier = identifier;
this.expression = expression;
if (check(identifier.type, expression.type) == null) {
error("type error");
}
}
private Type check(Type type1, Type type2) {
/*if (Type.numeric(type1) && Type.numeric(type2)) {
return type2;
} else if (type1 == Type.BOOL && type2 == Type.BOOL) {
return type2;
} else {
return null;
}*/
return Type.numeric(type1) && Type.numeric(type2) || type1 == Type.BOOL && type2 == Type.BOOL ? type2 : null;
}
@Override
public void generate(int begin, int first) {
emit(identifier.toString() + " = " + expression.generate().toString());
}
}
================================================
FILE: src/com/lixin/interpreter/SetElem.java
================================================
package com.lixin.interpreter;
import com.lixin.symbols.Array;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class SetElem extends Statement {
private Identifier array;
private Expression index;
private Expression expression;
public SetElem(Access access, Expression expression) {
array = access.array;
index = access.index;
this.expression = expression;
if (check(access.type, expression.type) == null) {
error("type error");
}
}
private Type check(Type type1, Type type2) {
/*if (type1 instanceof Array || type2 instanceof Array) {
return null;
} else if (type1 == type2) {
return type2;
} else if (Type.numeric(type1) && Type.numeric(type2)) {
return type2;
} else {
return null;
}*/
return type1 instanceof Array || type2 instanceof Array ? null : (type1 == type2) || (Type.numeric(type1) && Type.numeric(type2)) ? type2 : null;
}
@Override
public void generate(int begin, int first) {
String stringIndex = index.reduce().toString();
String stringExpression = expression.reduce().toString();
emit(array.toString() + " [ " + stringIndex + " ] = " + stringExpression);
}
}
================================================
FILE: src/com/lixin/interpreter/Statement.java
================================================
package com.lixin.interpreter;
/**
* @author lixin
*/
public class Statement extends Node {
public Statement() {
}
public static Statement NULL = new Statement();
/**
* @param begin 语句代码的开始处
* @param first 语句代码之后的第一条指令
*/
public void generate(int begin, int first) {
}
/**
* 保存语句的下一条指令的标号
*/
int after = 0;
/**
* 用于 break 语句
*/
public static Statement ENCLOSING = Statement.NULL;
}
================================================
FILE: src/com/lixin/interpreter/Temp.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Word;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Temp extends Expression {
private static int count = 0;
private int number;
Temp(Type type) {
super(Word.TEMP, type);
number = ++count;
}
@Override
public String toString() {
return "t" + number;
}
}
================================================
FILE: src/com/lixin/interpreter/Unary.java
================================================
package com.lixin.interpreter;
import com.lixin.lexer.Token;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class Unary extends Operator {
public Expression expression;
public Unary(Token token, Expression expression) {
super(token, null);
this.expression = expression;
type = Type.max(Type.INT, expression.type);
if (type == null) {
error("type error");
}
}
@Override
public Expression generate() {
return new Unary(operator, expression.reduce());
}
@Override
public String toString() {
return operator.toString() + " " + expression.toString();
}
}
================================================
FILE: src/com/lixin/interpreter/While.java
================================================
package com.lixin.interpreter;
import com.lixin.symbols.Type;
/**
* @author lixin
*/
public class While extends Statement {
private Expression expression;
private Statement statement;
public While() {
expression = null;
statement = null;
}
public void init(Expression expression, Statement statement) {
this.expression = expression;
this.statement = statement;
if (expression.type != Type.BOOL) {
expression.error("boolean required in while");
}
}
@Override
public void generate(int begin, int first) {
after = first;
expression.jumping(0, first);
int label = newLabel();
emitLabel(label);
statement.generate(label, begin);
emit("goto L" + begin);
}
}
================================================
FILE: src/com/lixin/lexer/Lexer.java
================================================
package com.lixin.lexer;
import com.lixin.symbols.Type;
import java.io.IOException;
import java.util.Hashtable;
/**
* @author lixin
*/
public class Lexer {
public static int line = 1;
private char peek = ' ';
private Hashtable words = new Hashtable<>();
private void reserve(Word word) {
words.put(word.lexeme, word);
}
public Lexer() {
reserve(new Word("if", Tag.IF));
reserve(new Word("else", Tag.ELSE));
reserve(new Word("while", Tag.WHILE));
reserve(new Word("do", Tag.DO));
reserve(new Word("break", Tag.BREAK));
reserve(Word.TRUE);
reserve(Word.FALSE);
reserve(Type.INT);
reserve(Type.CHAR);
reserve(Type.BOOL);
reserve(Type.FLOAT);
}
private void readChar() throws IOException {
peek = (char) System.in.read();
}
private boolean readChar(char c) throws IOException {
readChar();
if (peek != c) {
return false;
} else {
peek = ' ';
return true;
}
}
public Token scan() throws IOException {
/*
for (; ; readChar()) {
if (peek == ' ' || peek == '\t'|| peek == '\r') {
continue;
} else if (peek == '\n') {
line++;
} else {
break;
}
}
*/
outerLoop:
while (true) {
switch (peek) {
case ' ':
case '\t':
case '\r':
readChar();
continue;
case '\n':
line++;
break;
default:
break outerLoop;
}
readChar();
}
switch (peek) {
case '&':
return readChar('&') ? Word.AND : new Token('&');
case '|':
return readChar('|') ? Word.OR : new Token('|');
case '=':
return readChar('=') ? Word.EQUAL : new Token('=');
case '!':
return readChar('=') ? Word.NOT_EQUAL : new Token('!');
case '<':
return readChar('=') ? Word.LESS_EQUAL : new Token('<');
case '>':
return readChar('=') ? Word.GREATER_EQUAL : new Token('>');
default:
break;
}
if (Character.isDigit(peek)) {
int value = 0;
do {
value = 10 * value + Character.digit(peek, 10);
readChar();
} while (Character.isDigit(peek));
if (peek != '.') {
return new Numeric(value);
}
// float preciseValue = value;
float preciseValue;
// Base Multiplier 默认 Decimal
float baseMultiplier = 10;
/*
while (true) {
readChar();
if (!Character.isDigit(peek)) {
break;
}
preciseValue += Character.digit(peek, 10) / baseMultiplier;
baseMultiplier *= 10;
}
*/
// 若删除下句则float会解析错误
readChar();
for (preciseValue = value; Character.isDigit(peek); readChar()) {
preciseValue += Character.digit(peek, 10) / baseMultiplier;
baseMultiplier *= 10;
}
return new Real(preciseValue);
}
if (Character.isLetter(peek)) {
StringBuilder builder = new StringBuilder();
do {
builder.append(peek);
readChar();
} while (Character.isLetterOrDigit(peek));
String string = builder.toString();
Word word = words.get(string);
if (word != null) {
return word;
}
word = new Word(string, Tag.IDENTIFIER);
words.put(string, word);
return word;
}
Token token = new Token(peek);
peek = ' ';
return token;
}
}
================================================
FILE: src/com/lixin/lexer/Numeric.java
================================================
package com.lixin.lexer;
/**
* @author lixin
*/
public class Numeric extends Token {
public final int value;
public Numeric(int value) {
super(Tag.NUM);
this.value = value;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
================================================
FILE: src/com/lixin/lexer/Real.java
================================================
package com.lixin.lexer;
/**
* @author lixin
*/
public class Real extends Token {
private final float value;
public Real(float value) {
super(Tag.REAL);
this.value = value;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
================================================
FILE: src/com/lixin/lexer/Tag.java
================================================
package com.lixin.lexer;
/**
* @author lixin
*/
public class Tag {
public final static int
AND = 256,
BASIC = 257,
BREAK = 258,
DO = 259,
ELSE = 260,
EQUAL = 261,
FALSE = 262,
GREATER_EQUAL = 263,
IDENTIFIER = 264,
IF = 265,
INDEX = 266,
LESS_EQUAL = 267,
MINUS = 268,
NOT_EQUAL = 269,
NUM = 270,
OR = 271,
REAL = 272,
TEMP = 273,
TRUE = 274,
WHILE = 275;
}
================================================
FILE: src/com/lixin/lexer/Token.java
================================================
package com.lixin.lexer;
/**
* @author lixin
*/
public class Token {
public final int tag;
public Token(int tag) {
this.tag = tag;
}
@Override
public String toString() {
return String.valueOf((char) tag);
}
}
================================================
FILE: src/com/lixin/lexer/Word.java
================================================
package com.lixin.lexer;
/**
* @author lixin
*/
public class Word extends Token {
String lexeme;
public Word(String lexeme, int tag) {
super(tag);
this.lexeme = lexeme;
}
@Override
public String toString() {
return lexeme;
}
public static final Word
AND = new Word("&&", Tag.AND),
OR = new Word("||", Tag.OR),
EQUAL = new Word("==", Tag.EQUAL),
NOT_EQUAL = new Word("!=", Tag.NOT_EQUAL),
LESS_EQUAL = new Word("<=", Tag.LESS_EQUAL),
GREATER_EQUAL = new Word(">=", Tag.GREATER_EQUAL),
MINUS = new Word("-", Tag.MINUS),
TRUE = new Word("true", Tag.TRUE),
FALSE = new Word("false", Tag.FALSE),
TEMP = new Word("t", Tag.TEMP);
}
================================================
FILE: src/com/lixin/main/Compiler.java
================================================
package com.lixin.main;
import com.lixin.lexer.Lexer;
import com.lixin.parser.Parser;
import java.io.*;
/**
* @author lixin
*/
class Compiler {
void compile(File in, File out) {
InputStream sysIn = System.in;
PrintStream sysOut = System.out;
try {
FileInputStream fileInputStream = new FileInputStream(in);
System.setIn(fileInputStream);
FileOutputStream fileOutputStream = new FileOutputStream(out);
PrintStream printStream = new PrintStream(fileOutputStream);
System.setOut(printStream);
System.out.println("lxc>");
Lexer lexer = new Lexer();
Parser parser = new Parser(lexer);
parser.program();
System.out.println();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.setIn(sysIn);
System.setOut(sysOut);
}
}
String compile(String in) {
InputStream sysIn = System.in;
PrintStream sysOut = System.out;
try {
ByteArrayInputStream inputStream = new ByteArrayInputStream(in.getBytes());
System.setIn(inputStream);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(outputStream);
System.setOut(printStream);
System.out.println("lxc>");
Lexer lexer = new Lexer();
Parser parser = new Parser(lexer);
parser.program();
System.out.println();
return outputStream.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
System.setIn(sysIn);
System.setOut(sysOut);
}
}
}
================================================
FILE: src/com/lixin/main/CompilerTestDriver.java
================================================
package com.lixin.main;
import java.io.File;
/**
* @author lixin
*/
public class CompilerTestDriver {
public static void main(String[] args) {
Compiler compiler = new Compiler();
// 文件方法
File fileIn = new File("/Users/lixin/Downloads/in.txt");
File fileOut = new File("/Users/lixin/Downloads/out.txt");
compiler.compile(fileIn, fileOut);
// String 参数方法
String in = "{" +
"\tint i; int j; float v; float x; float[100] a;\r\n" +
"\twhile( true ) {\r\n" +
"\t\tdo i = i+1; while( a[i] < v);\r\n" +
"\t\tdo j = j-1; while( a[j] > v);\r\n" +
"\t\tif( i >= j ) break;\r\n" +
"\t\tx = a[i]; a[i] = a[j]; a[j] = x;\r\n" +
"\t}\r\n" +
"}\r\n" +
"{}";
String out = compiler.compile(in);
System.out.print(out);
}
}
================================================
FILE: src/com/lixin/main/Main.java
================================================
package com.lixin.main;
import com.lixin.lexer.Lexer;
import com.lixin.parser.Parser;
import java.io.IOException;
/**
* @author lixin
*/
public class Main {
public static void main(String[] args) throws IOException {
System.out.print("lxc>");
Lexer lexer = new Lexer();
Parser parser = new Parser(lexer);
parser.program();
System.out.println();
}
}
================================================
FILE: src/com/lixin/parser/Parser.java
================================================
package com.lixin.parser;
import com.lixin.interpreter.*;
import com.lixin.lexer.*;
import com.lixin.symbols.Array;
import com.lixin.symbols.Environment;
import com.lixin.symbols.Type;
import java.io.IOException;
/**
* @author lixin
*/
public class Parser {
private Lexer lexer;
private Token look;
private Environment top = null;
private int used = 0;
public Parser(Lexer lexer) throws IOException {
this.lexer = lexer;
move();
}
private void move() throws IOException {
look = lexer.scan();
}
private void error(String message) {
throw new Error("near line " + Lexer.line + ": " + message);
}
private void match(int tag) throws IOException {
if (look.tag == tag) {
move();
} else {
error("syntax error");
}
}
public void program() throws IOException {
Statement statement = block();
int begin = statement.newLabel();
int after = statement.newLabel();
statement.emitLabel(begin);
statement.generate(begin, after);
statement.emitLabel(after);
}
private Statement block() throws IOException {
match('{');
Environment savedEnvironment = top;
top = new Environment(top);
deClause();
Statement statement = statements();
match('}');
top = savedEnvironment;
return statement;
}
private void deClause() throws IOException {
while (look.tag == Tag.BASIC) {
Type type = type();
Token token = look;
match(Tag.IDENTIFIER);
match(';');
Identifier identifier = new Identifier((Word) token, type, used);
top.put(token, identifier);
used += type.width;
}
}
private Type type() throws IOException {
Type type = (Type) look;
match(Tag.BASIC);
if (look.tag != '[') {
return type;
} else {
return deBracket(type);
}
}
/**
* Original Name: dims
*/
private Type deBracket(Type type) throws IOException {
match('[');
Token token = look;
match(Tag.NUM);
match(']');
if (look.tag == '[') {
type = deBracket(type);
}
return new Array(((Numeric) token).value, type);
}
private Statement statements() throws IOException {
if (look.tag == '}') {
return Statement.NULL;
} else {
return new Sequence(statement(), statements());
}
}
private Statement statement() throws IOException {
Expression expression;
// Statement statement;
Statement statement1, statement2;
Statement savedStatement;
switch (look.tag) {
case ';':
move();
return Statement.NULL;
case Tag.IF:
match(Tag.IF);
match('(');
expression = bool();
match(')');
statement1 = statement();
if (look.tag != Tag.FALSE) {
return new If(expression, statement1);
}
match(Tag.FALSE);
statement2 = statement();
return new Else(expression, statement1, statement2);
case Tag.WHILE:
While whileNode = new While();
savedStatement = Statement.ENCLOSING;
Statement.ENCLOSING = whileNode;
match(Tag.WHILE);
match('(');
expression = bool();
match(')');
statement1 = statement();
whileNode.init(expression, statement1);
Statement.ENCLOSING = savedStatement;
return whileNode;
case Tag.DO:
Do doNode = new Do();
savedStatement = Statement.ENCLOSING;
Statement.ENCLOSING = doNode;
match(Tag.DO);
statement1 = statement();
match(Tag.WHILE);
match('(');
expression = bool();
match(')');
match(';');
doNode.init(statement1, expression);
Statement.ENCLOSING = savedStatement;
return doNode;
case Tag.BREAK:
match(Tag.BREAK);
match(';');
return new Break();
case '{':
return block();
default:
return assign();
}
}
private Statement assign() throws IOException {
Statement statement;
Token token = look;
match(Tag.IDENTIFIER);
Identifier identifier = top.get(token);
if (identifier == null) {
error(token.toString() + " undeclared");
}
if (look.tag == '=') {
move();
statement = new Set(identifier, bool());
} else {
Access access = offset(identifier);
match('=');
statement = new SetElem(access, bool());
}
match(';');
return statement;
}
private Expression bool() throws IOException {
Expression expression = join();
while (look.tag == Tag.OR) {
Token token = look;
move();
expression = new Or(token, expression, join());
}
return expression;
}
private Expression join() throws IOException {
Expression expression = equality();
while (look.tag == Tag.AND) {
Token token = look;
move();
expression = new And(token, expression, equality());
}
return expression;
}
private Expression equality() throws IOException {
Expression expression = relation();
while (look.tag == Tag.EQUAL || look.tag == Tag.NOT_EQUAL) {
Token token = look;
move();
return new Relation(token, expression, relation());
}
return expression;
}
private Expression relation() throws IOException {
Expression expression = expression();
switch (look.tag) {
case '<':
case Tag.LESS_EQUAL:
case Tag.GREATER_EQUAL:
case '>':
Token token = look;
move();
return new Relation(token, expression, expression());
default:
return expression;
}
}
private Expression expression() throws IOException {
Expression expression = term();
while (look.tag == '+' || look.tag == '-') {
Token token = look;
move();
return new Arithmetic(token, expression, term());
}
return expression;
}
private Expression term() throws IOException {
Expression expression = unary();
while (look.tag == '*' || look.tag == '/') {
Token token = look;
move();
return new Arithmetic(token, expression, unary());
}
return expression;
}
private Expression unary() throws IOException {
if (look.tag == '-') {
move();
return new Unary(Word.MINUS, unary());
} else if (look.tag == '!') {
Token token = look;
move();
return new Not(token, unary());
} else {
return factor();
}
}
private Expression factor() throws IOException {
Expression expression = null;
switch (look.tag) {
case '(':
move();
expression = bool();
match(')');
return expression;
case Tag.NUM:
expression = new Constant(look, Type.INT);
move();
return expression;
case Tag.REAL:
expression = new Constant(look, Type.FLOAT);
move();
return expression;
case Tag.TRUE:
expression = Constant.TRUE;
move();
return expression;
case Tag.FALSE:
expression = Constant.FALSE;
move();
return expression;
case Tag.IDENTIFIER:
// String stringLook = look.toString(); 没用
Identifier identifier = top.get(look);
if (identifier == null) {
error(look.toString() + " undeclared");
}
move();
if (look.tag != '[') {
return identifier;
} else {
return offset(identifier);
}
default:
error("syntax error");
return expression;
}
}
private Access offset(Identifier array) throws IOException {
Expression index;
Expression width;
Expression token1, token2;
Expression location;
Type type = array.type;
match('[');
index = bool();
match(']');
type = ((Array) type).of;
width = new Constant(type.width);
token1 = new Arithmetic(new Token('*'), index, width);
location = token1;
while (look.tag == '[') {
match('[');
index = bool();
match(']');
type = ((Array) type).of;
width = new Constant(type.width);
token1 = new Arithmetic(new Token('*'), index, width);
token2 = new Arithmetic(new Token('+'), location, token1);
location = token2;
}
return new Access(array, location, type);
}
}
================================================
FILE: src/com/lixin/symbols/Array.java
================================================
package com.lixin.symbols;
import com.lixin.lexer.Tag;
/**
* @author lixin
*/
public class Array extends Type {
public Type of;
private int size;
public Array(int size, Type type) {
super("[]", Tag.INDEX, size * type.width);
this.size = size;
of = type;
}
@Override
public String toString() {
return "[" + size + "]" + of.toString();
}
}
================================================
FILE: src/com/lixin/symbols/Environment.java
================================================
package com.lixin.symbols;
import com.lixin.interpreter.Identifier;
import com.lixin.lexer.Token;
import java.util.Hashtable;
/**
* @author lixin
*/
public class Environment {
private Hashtable table;
private Environment previousEnvironment;
public Environment(Environment environment) {
table = new Hashtable<>();
previousEnvironment = environment;
}
public void put(Token word, Identifier identifier) {
table.put(word, identifier);
}
public Identifier get(Token word) {
for (Environment environment = this; environment != null; environment = environment.previousEnvironment) {
Identifier found = (environment.table.get(word));
if (found != null) {
return found;
}
}
return null;
}
}
================================================
FILE: src/com/lixin/symbols/Type.java
================================================
package com.lixin.symbols;
import com.lixin.lexer.Tag;
import com.lixin.lexer.Word;
import java.util.Arrays;
/**
* @author lixin
*/
public class Type extends Word {
public int width;
public Type(String lexeme, int tag, int width) {
super(lexeme, tag);
this.width = width;
}
public static final Type
INT = new Type("int", Tag.BASIC, 4),
FLOAT = new Type("float", Tag.BASIC, 8),
CHAR = new Type("char", Tag.BASIC, 1),
BOOL = new Type("bool", Tag.BASIC, 1);
public static boolean numeric(Type type) {
return Arrays.asList(new Type[]{FLOAT, INT, FLOAT}).contains(type);
}
public static Type max(Type type1, Type type2) {
/*The explanation of the working codes.
if (!numeric(type1) || !numeric(type2)) {
return null;
} else if (type1 == Type.FLOAT || type2 == FLOAT) {
return Type.FLOAT;
} else if (type1 == Type.INT || type2 == Type.INT) {
return Type.INT;
} else {
return Type.CHAR;
}*/
return numeric(type1) && numeric(type2) ? type1 == FLOAT || type2 == FLOAT ? FLOAT : type1 == INT || type2 == INT ? INT : CHAR : null;
}
}