├── .gitignore
├── LICENSE
├── README.md
├── design
└── README.md
├── src
├── META-INF
│ └── MANIFEST.MF
└── com
│ └── imudges
│ └── C0Compiler
│ ├── Compiler
│ ├── Lex.java
│ ├── Main.java
│ └── Syn.java
│ ├── Executer
│ ├── Error.java
│ ├── Exe.java
│ ├── Execute.java
│ └── Main.java
│ └── JavaCC
│ ├── Compiler.jj
│ ├── ExError.java
│ ├── MiddleCodeItem.java
│ ├── SymbolItem.java
│ └── package.json
└── testFile
├── main.c0
└── main.c0Target
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | /.idea/
3 | /out/
4 | /C0Compiler.iml
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 史安琪
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # C0Compiler
2 | Java实现的 c0 语言编译器,作者: shianqi@imudges.com
3 |
4 | 目录
5 | ---
6 | * [1.C0语言的语法结构定义](#1)
7 | * [2.假想栈式指令系统表](#2)
8 |
9 |
C0语言的语法结构定义
10 |
11 | ```
12 | <程序> -> [<变量定义部分>] {<自定义函数定义部分>} <主函数>
13 | <变量定义部分> -> int id {, id};
14 | <自定义函数定义部分> -> ( int id | void id) '(' ')' <分程序>
15 | <主函数> -> void main'(' ')' <分程序>
16 | <分程序> -> '{' [<变量定义部分>] <语句序列> '}'
17 | <语句序列> -> <语句> {<语句>}
18 | <语句> -> <条件语句> | <循环语句> | '{'<语句序列>'}' | <自定义函数调用语句> | <赋值语句> | <返回语句> | <读语句> | <写语句> | ;
19 | <条件语句> -> if '('<表达式>')' <语句> [else <语句> ]
20 | <循环语句> -> while '(' <表达式>')' <语句>
21 | <自定义函数调用语句> -> <自定义函数调用>;
22 | <赋值语句> -> id = <表达式>;
23 | <返回语句> -> return ['(' <表达式> ')'] ;
24 | <读语句> -> scanf '(' id ')';
25 | <写语句> -> printf '(' [ <表达式>] ')';
26 | <表达式> -> [+|-] <项> { (+|-) <项>}
27 | <项> -> <因子>{(*|/) <因子>}
28 | <因子> -> id|'(' <表达式>')' | num | <自定义函数调用>
29 | <自定义函数调用> -> id '(' ')'
30 | ```
31 |
32 | 编译
33 | ```
34 | java -cp C://javacc-6.0/bin/lib/javacc.jar javacc ./src/com/imudges.C0Compile/JavaCC/Compiler.jj
35 | ```
36 |
37 | 语法名称 | 标识符
38 | -----|----
39 | 程序 | A
40 | 变量定义部分 | B
41 | 自定义函数定义部分 | C
42 | 主函数 | D
43 | 分程序 | E
44 | 语句序列 | F
45 | 语句 | G
46 | 条件语句 | H
47 | 循环语句 | I
48 | 自定义函数调用语句 | J
49 | 赋值语句 | K
50 | 返回语句 | L
51 | 读语句 | M
52 | 写语句 | N
53 | 表达式 | O
54 | 项 | P
55 | 因子 | Q
56 | 自定义函数调用 | R
57 |
58 | ```
59 | A -> [B] {C} D
60 | B -> int id {, id};
61 | C -> ( int id | void id) '(' ')' E
62 | D -> void main'(' ')' E
63 | E -> '{' [B] F '}'
64 | F -> G {G}
65 | G -> H | I | '{'F'}' | J | K | L | M | N | ;
66 | H -> if '('O')' | G [else G ]
67 | I -> while '(' O')' G
68 | J -> R;
69 | K -> id = O;
70 | L -> return ['(' O ')'] ;
71 | M -> scanf '(' id ')';
72 | N -> printf '(' [ O] ')';
73 | O -> [+|-] P { (+|-) P}
74 | P -> Q{(*|/) Q}
75 | Q -> id|'(' O')' | num | R
76 | R -> id '(' ')'
77 | ```
78 |
79 | ```
80 | A -> BCD
81 | B -> int id J; | ε
82 | S -> , id S | , id | ε
83 | C -> HE | HEC | ε
84 | T -> int id '(' ')' | void id '(' ')'
85 | D -> void main'(' ')' E
86 | E -> '{' F '}' | '{' BF '}'
87 | F -> GU
88 | U -> G | GU | ε
89 | G -> H | I | '{'F'}' | J | K | L | M | N | ;
90 | H -> if '('O')' | GV
91 | V -> G | ε
92 | I -> while '(' O')' G
93 | J -> R;
94 | K -> id = O;
95 | L -> return W ;
96 | W -> '(' O ')' | ε
97 | M -> scanf '(' id ')';
98 | N -> printf '(' X ')';
99 | X -> O | ε
100 | O -> Y P Z
101 | Y = + | - | ε
102 | Z = +PZ | -PZ | ε
103 | P -> Q&
104 | & -> *Q& | /Q& | ε
105 | Q -> id|'(' O')' | num | R
106 | R -> id '(' ')'
107 | ```
108 |
109 | ```
110 | A -> BCD
111 | B -> int id J; | ε
112 | S -> , id S | , id | ε
113 | C -> HE | HEC | ε
114 | T -> int id '(' ')' | void id '(' ')'
115 | D -> void main'(' ')' E
116 | E -> '{' F '}' | '{' BF '}'
117 | -> '{' F '}' | '{' int id J;F '}' | '{' F '}'
118 |
119 | ```
120 |
121 |
122 |
123 |
124 | 其中,id代表标识符,num代表整数,其含义及构成方式与C语言相一致;C0源程序中的变量需先定义后使用,其作用域与生存期与C语言相一致;自定义函数可超前使用(调用在前,定义在后)。
125 | 根据上面给定的C0文法及其说明和下列定义的假想栈式指令系统,按递归下降分析法设计并实现该C0语言的编译器,生成栈式目标代码;编写栈式指令系统的解释执行程序,输出目标代码的解释执行结果。
126 | 假想的栈式指令系统表
127 |
128 |
129 | 假想栈式指令系统表
130 |
131 | dic | t | a | 解释
132 | ----|---|---|------------
133 | LIT | 0 | a | 将常数值取到栈顶,a为常数值
134 | LOD | t | a | 将变量值取到栈顶,a为相对地址,t为层数
135 | STO | t | a | 将栈顶内容送入某变量单元中,a为相对地址,t为层数
136 | CAL | 0 | a | 调用函数,a为函数地址
137 | INT | 0 | a | 在运行栈中为被调用的过程开辟a个单元的数据区
138 | JMP | 0 | a | 无条件跳转至a地址
139 | JPC | 0 | a | 条件跳转,当栈顶值为0,则跳转至a地址,否则顺序执行
140 | ADD | 0 | 0 | 次栈顶与栈顶相加,退两个栈元素,结果值进栈
141 | SUB | 0 | 0 | 次栈顶减去栈顶,退两个栈元素,结果值进栈
142 | MUL | 0 | 0 | 次栈顶乘以栈顶,退两个栈元素,结果值进栈
143 | DIV | 0 | 0 | 次栈顶除以栈顶,退两个栈元素,结果值进栈
144 | RED | 0 | 0 | 从命令行读入一个输入置于栈顶
145 | WRT | 0 | 0 | 栈顶值输出至屏幕并换行
146 | RET | 0 | 0 | 函数调用结束后,返回调用点并退栈
147 |
148 |
--------------------------------------------------------------------------------
/design/README.md:
--------------------------------------------------------------------------------
1 | # 词法分析模块
2 |
3 | * ### 过滤空字符
4 |
5 | 使用 `JavaCC` 的 `SKIP` 来过滤掉词法分析部分的空字符。
6 | 例如:
7 |
8 | ```
9 | SKIP:
10 | {
11 | " " | "\t" | "\n" | "\r"
12 | }
13 | ```
14 |
15 | * ### 定义符号
16 |
17 | 使用 `JavaCC` 的 `TOKEN` 来声明 `C0` 中的关键词。
18 | 例如:
19 |
20 | ```
21 | TOKEN:
22 | {
23 |
24 | |
25 |
26 | |
27 |
28 | }
29 | ```
30 |
31 | * ### 获取匹配的符号
32 |
33 | 如果想获取一个 `Token` 所代表的字符,则只需要调用其`image`变量。
34 | 例如:
35 | ```
36 | Token t =
37 | System.out.println(t.image);
38 | //main
39 | ```
40 |
41 | # 语法分析模块
42 |
43 | * ### 语法分析所用的方法
44 |
45 | 语法分析所用的主要是 `自顶向下` 的方法,在不会产生左递归的规则采用
46 | `递归向下子程序法` 的分析方法,在可能出现左递归时,在此处进行`超前搜索`。使用
47 | `LL(2)` 分析方法。来结果可能会导致回朔的情况。
48 |
49 | * ### 子程序定义
50 |
51 | 在子程序中,将相应的规则应该翻译成子程序的互相调用。则可以清楚的
52 | 描述出该程序的语法。
53 |
54 | ```
55 | <程序> -> [<变量定义部分>] {<自定义函数定义部分>} <主函数>
56 | <变量定义部分> -> int id {, id};
57 | <自定义函数定义部分> -> ( int id | void id) '(' ')' <分程序>
58 | <主函数> -> void main'(' ')' <分程序>
59 | <分程序> -> '{' [<变量定义部分>] <语句序列> '}'
60 | <语句序列> -> <语句> {<语句>}
61 | <语句> -> <条件语句> | <循环语句> | '{'<语句序列>'}' | <自定义函数调用语句> | <赋值语句> | <返回语句> | <读语句> | <写语句> | ;
62 | <条件语句> -> if '('<表达式>')' <语句> [else <语句> ]
63 | <循环语句> -> while '(' <表达式>')' <语句>
64 | <自定义函数调用语句> -> <自定义函数调用>;
65 | <赋值语句> -> id = <表达式>;
66 | <返回语句> -> return ['(' <表达式> ')'] ;
67 | <读语句> -> scanf '(' id ')';
68 | <写语句> -> printf '(' [ <表达式>] ')';
69 | <表达式> -> [+|-] <项> { (+|-) <项>}
70 | <项> -> <因子>{(*|/) <因子>}
71 | <因子> -> id|'(' <表达式>')' | num | <自定义函数调用>
72 | <自定义函数调用> -> id '(' ')'
73 | ```
74 |
75 | 例如规则
76 | ```
77 | <自定义函数调用> -> id '(' ')'
78 | ```
79 |
80 | 则可以在`JavaCC` 中翻译成如下的函数调用。
81 |
82 | ```
83 | /** 自定义函数调用 */
84 | void DefinitionFunction_CC():
85 | {
86 | Token t;
87 | }
88 | {
89 | //id '(' ')'
90 | t=
91 | }
92 | ```
93 |
94 | * ### 代码生成
95 |
96 | 当子程序全部编辑完成后,就可以进行代码生成测试了。
97 |
98 | 使用如下命令进行代码生成
99 |
100 | ```
101 | java -cp C://javacc-6.0//bin//lib//javacc.jar javacc Compiler.jj
102 | ```
103 |
104 | 之后就生成了相应的 `*.java` 文件。
105 | 还需要进行编译。
106 |
107 | ```
108 | javac Compiler.java
109 | ```
110 |
111 | 之后就得到了程序的二进制文件了
112 | 运行如下命令进行执行。
113 |
114 | ```
115 | java Compiler
116 | ```
117 |
118 | 当然,为了测试和编译的简单性,这里使用 [npm](https://www.npmjs.com/)
119 | 将上述的代码进行打包。
120 | 只需要运行如下代码
121 |
122 | ```
123 | npm start
124 | ```
125 |
126 | 注意:如果此命令不能运行,则请先安装最新的 `nodejs` 和 `npm`
127 |
128 | * ### 语法分析正确性测试
129 |
130 | 在执行上一步的函数后,可以先将 `Compiler.jj` 中 `16` 行的代码
131 |
132 | ```
133 | Compiler parser = new Compiler(inputstream);
134 | ```
135 |
136 | 替换为
137 |
138 | ```
139 | Compiler parser = new Compiler(System.in);
140 | ```
141 |
142 | 则可以进行一个符号一个符号的分析。检查验证语法分析程序的正确性。
143 |
144 | # 语义分析模块
145 |
146 | * ### 语义分析实现
147 |
148 | 此处语义分析是在上一步语法分析生成的语法树基础上进行的。在合适的地方插入
149 | 相应的处理代码进行语义分析
150 | 例如:
151 |
152 | ```
153 | /** 自定义函数调用 */
154 | void DefinitionFunction_CC():
155 | {
156 | Token t;
157 | }
158 | {
159 | //id '(' ')'
160 | t=
161 | {
162 | getFunctionById(t);
163 | }
164 | }
165 | ```
166 | * ### 变量的声明和使用:
167 |
168 | * 首先,全局变量声明的变量存在全局空间表中。函数中的变量存在分程序空间中。
169 |
170 | * 函数声明也存在分程序空间中,所以,对于一个函数里的变量,它在栈底一定是它的函数声明。
171 | 所以可以区分作用域。
172 |
173 | * 函数中定义变量时判断是在当前作用域下定义过,如果定义过,
174 | 报错,变量重复定义。
175 |
176 | * 在单词表中寻找变量时,先在当前作用域下寻找,如果没有,
177 | 则去全局空间寻找。如果还没有,则该函数未定义。
178 |
179 | * ### 函数的超前调用:
180 |
181 | * 首先先在分程序表中寻找是否有该函数,如果没有则进行超前调用。
182 |
183 | * 生成相应的调用中间码,在超前调用表中添加该函数,并且将中间码的地址记录下来。
184 |
185 | * 当函数声明的时候,检查这个函数是否在超前调用表中,如果在,就讲更改生成
186 | 中间代码的地址,并讲这个函数从超前调用表中删除,添加到分程序表中。
187 |
188 | * 程序扫描完成后,查看超前调用表,如果还有函数,则该函数没有声明。报出错误信息。
189 |
190 | * ### 函数的返回值:
191 | * 首先,在语法树函数开始的地方做上标记,记录该函数返回值类型。
192 |
193 | * 当函数最后没有返回值时,如果返回类型为int,则报错,错误信息:
194 | “此函数必须返回int值变量”。
195 |
196 | * 当函数最后没有返回值时,如果返回类型为void,则自动帮函数在末尾添加return语句。
197 |
198 | # 中间代码生成模块
199 |
200 | * ### 全局空间字母表
201 |
202 | 用于存放程序中全局变量信息的表格
203 |
204 | * ### 分程序空间字母表
205 |
206 | 用于存放函数和函数中的变量信息的表格
207 |
208 | * ### 超前调用字母表
209 |
210 | 用于存放超前调用的函数信息的表格
211 |
212 | * ### 中间代码表
213 |
214 | 用于存放中间码的表格
215 |
216 | # 目标代码生成模块
217 |
218 | * ### 检测超前调用表
219 |
220 | 如果超前调用表中仍然存在函数,则说明该函数被使用,但是
221 | 该函数并没有被初始化。所以要报出相应的错误信息。
222 |
223 | # 错误处理模块
224 |
225 | * ### 错误处理模块调用的接口为:
226 |
227 | ```
228 | @param errCode 错误号
229 | @param errMsg 错误信息
230 | public static void ShowErrMsg(int errCode,String errMsg)
231 | ```
232 |
--------------------------------------------------------------------------------
/src/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Main-Class: com.imudges.C0Compiler.Executer.Main
3 |
4 |
--------------------------------------------------------------------------------
/src/com/imudges/C0Compiler/Compiler/Lex.java:
--------------------------------------------------------------------------------
1 | package com.imudges.C0Compiler.Compiler;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.InputStreamReader;
6 | import java.io.Reader;
7 | import java.util.ArrayList;
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.Scanner;
11 |
12 | /**
13 | * Created by killer on 2016/10/18.
14 | * @author shianqi@imudges.com
15 | * c0编译器词法分析类
16 | */
17 | public class Lex {
18 | //源程序单词缓存
19 | private String sourceCodeTemp;
20 | //行数
21 | private int row;
22 | //缓存单词字符指针
23 | private int index;
24 | //变量最大长度
25 | private int symMaxLength = 20;
26 |
27 | public Lex(){
28 | sourceCodeTemp = "";
29 | row = 0;
30 | index = 0;
31 | getSym();
32 | }
33 |
34 | public String[] reservedWord = {
35 | "main",
36 | "void",
37 | "if",
38 | "while",
39 | "return",
40 | "int",
41 | };
42 |
43 | public enum symbol
44 | {
45 | //---------------------- 基本字
46 | mainsym, // 主程序
47 | voidsym, // 空类型
48 | ifstasym, // 如果语句
49 | whilestasym,// 循环语句
50 | resym, // return
51 | intsym, // 整型
52 | nul, // 未知
53 |
54 | ifsym, // if
55 | elsesym, // else
56 | whilesym, // while
57 |
58 | readstasym, // 读语句
59 | writestasym,// 写语句
60 | scanfsym, // 输入
61 | printfsym, // 输出
62 | //---------------------- 常数
63 | number, // 数字
64 | //---------------------- 界符
65 | leftsym, // (
66 | rightsym, // )
67 | beginsym, // {
68 | endsym, // }
69 | comma, // ,
70 | semicolon, // ;
71 | period, // .
72 | //---------------------- 标识符
73 | ident, // 自定义符号
74 | //---------------------- 运算符
75 | plu, // +
76 | sub, // -
77 | mul, // *
78 | dive, // /
79 | eqlsym, // =
80 | restasym, // 赋值语句
81 | }
82 |
83 | /**
84 | * 判断字符类型
85 | */
86 | public enum wordType{
87 | BasicWord, //基本字
88 | Number, //常数
89 | Delimiter, //界符
90 | Identifier, //标识符
91 | Operator //运算符
92 | }
93 |
94 | private enum charType{
95 | Nul, //空
96 | Letter, //字母
97 | Number, //数字类型
98 | }
99 |
100 | private charType getType(char ch){
101 | if(ch==' '||ch==10||ch==9){
102 | return charType.Nul;
103 | }else if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z'||ch=='_'){
104 | return charType.Letter;
105 | }else if(ch>='0'&&ch<='9'){
106 | return charType.Number;
107 | }
108 | return null;
109 | }
110 |
111 | /**
112 | * 获取下个字符
113 | * @return 下一个字符,当返回'.'时表示文档结束
114 | */
115 | private char getChar(){
116 | while(sourceCodeTemp.equals("")){
117 | if(row>=Main.sourceCode.size()){
118 | return '.';
119 | }else{
120 | sourceCodeTemp = Main.sourceCode.get(row);
121 | row++;
122 | index = 0;
123 | }
124 | }
125 | char temp = sourceCodeTemp.charAt(index);
126 | index++;
127 | if(index>=sourceCodeTemp.length()){
128 | sourceCodeTemp = "";
129 | }
130 | return temp;
131 | }
132 |
133 |
134 | /**
135 | * 获取下一个单词
136 | */
137 | private void getSym(){
138 |
139 | char ch = getChar();
140 | while(true){
141 | if(ch=='.'){
142 | System.out.println("文档结束!");
143 | break;
144 | }else{
145 | if(getType(ch)!=charType.Nul){
146 | //如果第一个单词是字母
147 | if(getType(ch)==charType.Letter){
148 | String stringTemp = "";
149 | stringTemp+=ch;
150 | ch = getChar();
151 | while(getType(ch)==charType.Number||getType(ch)==charType.Letter){
152 | stringTemp+=ch;
153 | ch = getChar();
154 | }
155 | if(Arrays.asList(reservedWord).contains(stringTemp)){
156 | System.out.println("保留字: "+stringTemp);
157 | }else{
158 | System.out.println("单词: "+stringTemp);
159 | }
160 | }else if(getType(ch)==charType.Number){
161 | //如果第一个字母是数字
162 | int numberTemp = ch - '0';
163 | ch = getChar();
164 | while(getType(ch)==charType.Number){
165 | numberTemp = numberTemp*10+(ch-'0');
166 | ch = getChar();
167 | }
168 | System.out.println("数字: "+numberTemp);
169 | }else if(ch=='('){
170 | System.out.println("符号: "+ch);
171 | ch = getChar();
172 | }else if(ch==')'){
173 | System.out.println("符号: "+ch);
174 | ch = getChar();
175 | }else if(ch=='{'){
176 | System.out.println("符号: "+ch);
177 | ch = getChar();
178 | }else if(ch=='}'){
179 | System.out.println("符号: "+ch);
180 | ch = getChar();
181 | }else{
182 | System.out.print(ch);
183 | ch = getChar();
184 | }
185 | }else{
186 | ch = getChar();
187 | }
188 | }
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/src/com/imudges/C0Compiler/Compiler/Main.java:
--------------------------------------------------------------------------------
1 | package com.imudges.C0Compiler.Compiler;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.File;
5 | import java.io.FileReader;
6 | import java.io.IOException;
7 | import java.util.ArrayList;
8 | import java.util.Scanner;
9 |
10 | /**
11 | * Created by shianqi on 2016/10/11.
12 | * @author shianqi@imudges.com
13 | */
14 | public class Main {
15 | private Lex lex;
16 | private Scanner scanner = new Scanner(System.in);
17 | public static ArrayList sourceCode;
18 |
19 | public static void main(String[] args) {
20 | Main main = new Main();
21 | main.init();
22 |
23 |
24 | }
25 |
26 | /**
27 | * 简单的程序介绍
28 | */
29 | private void outputInformation(){
30 | System.out.println("欢迎使用C0编译器");
31 | System.out.println("本编译器实现功能:");
32 | }
33 |
34 | /**
35 | * 初始化程序
36 | *
37 | */
38 | private void init(){
39 | outputInformation();
40 | sourceCode = new ArrayList<>();
41 | initFile();
42 | lex = new Lex();
43 | }
44 |
45 | /**
46 | * 初始化文件
47 | */
48 | private void initFile(){
49 | while (true){
50 | System.out.println("input the c0 file name");
51 | if(readC0File(scanner.next())){
52 | break;
53 | }else{
54 | System.out.println("c0 File read failed. Please try again!");
55 | }
56 | }
57 | }
58 |
59 | /**
60 | * 读取文件
61 | * @param fileName 文件名称
62 | * @return 读取成功返回true,否则返回false
63 | */
64 | private boolean readC0File(String fileName) {
65 | File file = new File(fileName);
66 | BufferedReader reader = null;
67 | try {
68 | reader = new BufferedReader(new FileReader(file));
69 | String tempString;
70 | while ((tempString = reader.readLine()) != null) {
71 | sourceCode.add(tempString);
72 | }
73 | reader.close();
74 | return true;
75 | } catch (IOException e) {
76 | e.printStackTrace();
77 | return false;
78 | } finally {
79 | if (reader != null) {
80 | try {
81 | reader.close();
82 | } catch (IOException e1) {
83 | System.out.println("document close failed!");
84 | }
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/com/imudges/C0Compiler/Compiler/Syn.java:
--------------------------------------------------------------------------------
1 | package com.imudges.C0Compiler.Compiler;
2 |
3 | /**
4 | * @author shianqi@imudges.com
5 | * Created by shianqi on 2016/11/29
6 | * 语法分析模块,采用递归下降子程序法。
7 | */
8 | public class Syn {
9 | /**
10 | * 程序
11 | */
12 | private void program(){
13 |
14 | }
15 |
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/com/imudges/C0Compiler/Executer/Error.java:
--------------------------------------------------------------------------------
1 | package com.imudges.C0Compiler.Executer;
2 |
3 | /**
4 | * 错误处理类
5 | * @author yuanyuan@imudges.com
6 | * Created by shianqi on 2016/11/1.
7 | */
8 | public class Error {
9 | public static enum ErrCode{
10 | ArithmeticException,//算数异常
11 | InputParamErrException,//输入参数错误
12 | AskMemoryTooBigException,//申请内存空间太大
13 | CrossBroderException,//越界
14 | StackOverflowException,//栈溢出
15 | }
16 | public static boolean errFlag=false;
17 |
18 | /**
19 | *
20 | * @param errCode
21 | * @param errMsg
22 | */
23 | public static void ShowErrMsg(int errCode,String errMsg){
24 | switch (errCode){
25 | case 1:{System.err.println("错误信息:"+ErrCode.ArithmeticException.toString()+" "+errMsg);errFlag=true;break;}
26 | case 2:{System.err.println("错误信息:"+ErrCode.InputParamErrException.toString()+" "+errMsg);errFlag=true;break;}
27 | case 3:{System.err.println("错误信息:"+ErrCode.AskMemoryTooBigException.toString()+" "+errMsg);errFlag=true;break;}
28 | case 4:{System.err.println("错误信息:"+ErrCode.CrossBroderException.toString()+" "+errMsg);errFlag=true;break;}
29 | case 5:{System.err.println("错误信息:"+ErrCode.StackOverflowException.toString()+" "+errMsg);errFlag=true;break;}
30 | default:{}
31 | }
32 |
33 | }
34 |
35 | /*public static void main(String[] args) {
36 | System.out.println(ErrCode.askMemoryTooBigException.toString());
37 | }*/
38 | }
39 |
--------------------------------------------------------------------------------
/src/com/imudges/C0Compiler/Executer/Exe.java:
--------------------------------------------------------------------------------
1 | package com.imudges.C0Compiler.Executer;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.File;
5 | import java.io.FileReader;
6 | import java.io.IOException;
7 | import java.util.ArrayList;
8 | import java.util.Scanner;
9 | import java.util.Stack;
10 |
11 | /**
12 | * 解释器
13 | * @author shianqi@imudges.com
14 | * Created by shianqi on 2016/11/1.
15 | */
16 | class Exe {
17 | //当前层数基地址
18 | private int origin = 0;
19 | //当前执行指令标号
20 | private int current = 0;
21 | private enum Dic{
22 | LIT, LOD, STO, CAL, INT, JMP, JPC,
23 | ADD, SUB, MUL, DIV, RED, WRT, RET
24 | }
25 | private class Dictate{
26 | private Dic dic;
27 | private int t;
28 | private int a;
29 | }
30 | private Scanner scanner = new Scanner(System.in);
31 | private ArrayList dictateList = new ArrayList<>();
32 | private Stack runStack = new Stack<>();
33 |
34 | /**
35 | * LIT 0 a
36 | * 将常数值取到栈顶
37 | * @param t 0
38 | * @param a 常数值
39 | */
40 | private void dic_LIT(int t, int a){
41 | runStack.push(a);
42 | }
43 |
44 | /**
45 | * LOD t a
46 | * 将变量值取到栈顶
47 | * @param t 层数
48 | * @param a 相对地址
49 | */
50 | private void dic_LOD(int t, int a){
51 | if(t==0){
52 | runStack.push(runStack.get(a));
53 | }else{
54 | runStack.push(runStack.get(a+origin));
55 | }
56 | }
57 |
58 | /**
59 | * sto t a
60 | * 将栈顶内容送入某变量单元中
61 | * @param t 层数
62 | * @param a 相对地址
63 | */
64 | private void dic_STO(int t, int a){
65 | if(t==0){
66 | runStack.set(a, runStack.get(runStack.size()-1));
67 | }else{
68 | runStack.set(origin + a, runStack.get(runStack.size()-1));
69 | }
70 | }
71 |
72 | /**
73 | * cal 0 a
74 | * 调用函数,a为函数地址
75 | * @param t 0
76 | * @param a 函数地址
77 | */
78 | private void dic_CAL(int t, int a){
79 | //修改DL 和 RL
80 | int base = runStack.size();
81 | runStack.push(origin);
82 | runStack.push(current+1);
83 | origin = base;
84 | current = a - 1;
85 | }
86 |
87 | /**
88 | * int 0 a
89 | * 在运行栈中为被调用的过程开辟a个单元的数据区
90 | * @param t 0
91 | * @param a 数据区数量
92 | */
93 | private void dic_INT(int t, int a){
94 | for(int i=0;i=500){
97 | //System.out.println("栈满500");
98 | Error.ShowErrMsg(4,"所在行数为:第"+current+"行");
99 | }
100 | }
101 | }
102 |
103 | /**
104 | * JMP 0 a
105 | * 无条件跳转至a地址
106 | * @param t 0
107 | * @param a 跳转到的地址
108 | */
109 | private void dic_JMP(int t, int a){
110 | current = a - 1;
111 | }
112 |
113 | /**
114 | * jpc 0 a
115 | * 条件跳转,当栈顶值为0,则跳转至a地址,否则顺序执行
116 | * @param t 0
117 | * @param a 跳转地址
118 | */
119 | private void dic_JPC(int t, int a){
120 | if(runStack.get(runStack.size()-1)==0){
121 | current = a - 1;
122 | }
123 | }
124 |
125 | /**
126 | * add 0 0
127 | * 次栈顶与栈顶相加,退两个栈元素,结果值进栈
128 | * @param t 0
129 | * @param a 0
130 | */
131 | private void dic_ADD(int t, int a){
132 | int val_a = runStack.get(runStack.size()-1);
133 | runStack.pop();
134 | int val_b = runStack.get(runStack.size()-1);
135 | runStack.set(runStack.size()-1, val_a+val_b);
136 | }
137 |
138 | /**
139 | * sub 0 0
140 | * 次栈顶减去栈顶,退两个栈元素,结果值进栈
141 | * @param t 0
142 | * @param a 0
143 | */
144 | private void dic_SUB(int t, int a){
145 | int val_a = runStack.get(runStack.size()-1);
146 | runStack.pop();
147 | int val_b = runStack.get(runStack.size()-1);
148 | runStack.set(runStack.size()-1, val_b-val_a);
149 | }
150 |
151 | /**
152 | * mul 0 0
153 | * 次栈顶乘以栈顶,退两个栈元素,结果值进栈
154 | * @param t 0
155 | * @param a 0
156 | */
157 | private void dic_MUL(int t, int a){
158 | int val_a = runStack.get(runStack.size()-1);
159 | runStack.pop();
160 | int val_b = runStack.get(runStack.size()-1);
161 | runStack.set(runStack.size()-1, val_b*val_a);
162 | }
163 |
164 | /**
165 | * div
166 | * 次栈顶除以栈顶,退两个栈元素,结果值进栈
167 | * @param t 0
168 | * @param a 0
169 | */
170 | private void dic_DIV(int t, int a){
171 | int val_a = runStack.get(runStack.size()-1);
172 | runStack.pop();
173 | if(val_a==0){
174 | Error.ShowErrMsg(1,"所在行数为:第"+current+"行");
175 | }
176 | int val_b = runStack.get(runStack.size()-1);
177 | runStack.set(runStack.size()-1, val_b/val_a);
178 | }
179 |
180 | /**
181 | * red 0 0
182 | * 从命令行读入一个输入置于栈顶
183 | * @param t 0
184 | * @param a 0
185 | */
186 | private void dic_RED(int t, int a){
187 | runStack.push(scanner.nextInt());
188 | }
189 |
190 | /**
191 | * wrt 0 0
192 | * 栈顶值输出至屏幕并换行
193 | * @param t 0
194 | * @param a 0
195 | */
196 | private void dic_WRT(int t, int a){
197 | if(runStack.empty()){
198 | //System.out.println("读入栈失败,栈为空");
199 | Error.ShowErrMsg(4,"所在行数为:第"+current+"行");
200 | }else{
201 | System.out.println(runStack.peek());
202 | }
203 | }
204 |
205 | /**
206 | * ret 0 0
207 | * 函数调用结束后,返回调用点并退栈
208 | * 如果当前为0层,则运行结束
209 | * @param t 0
210 | * @param a 0
211 | */
212 | private void dic_RET(int t, int a){
213 | if(origin==0){
214 | current = 999999;
215 | return;
216 | }
217 | int returnValue = runStack.get(runStack.size()-1);
218 | current = runStack.get(origin+1)-1;
219 | int originTemp = origin;
220 | origin = runStack.get(origin);
221 | while(runStack.size()>originTemp){
222 | runStack.pop();
223 | }
224 | runStack.push(returnValue);
225 | }
226 |
227 | /**
228 | * 初始化函数
229 | */
230 | void init(){
231 | System.out.println("input the C0Target file name");
232 | readFileByLines(scanner.next());
233 | execute();
234 | }
235 |
236 | /**
237 | * 执行函数
238 | */
239 | private void execute(){
240 | while(current dictateList=new ArrayList<>();
32 | private Stack runStack=new Stack<>();
33 |
34 | /**
35 | * LIT 0 a
36 | * 将常数值取到栈顶
37 | * @param t 0
38 | * @param a a
39 | */
40 | private void dictate_LIT(int t,int a){
41 | runStack.push(a);
42 | }
43 |
44 | /**
45 | * LOD t a
46 | * 将变量值
47 | * @param t 层数
48 | * @param a 相对地址
49 | */
50 | private void dictate_LOD(int t,int a){
51 | if(t==0){
52 | runStack.push(runStack.get(a));
53 | }else{
54 | runStack.push(runStack.get(a+baseAddress));
55 | }
56 | }
57 |
58 | /**
59 | * STO t a
60 | * 将栈顶内容送入某变量单元中
61 | * @param t 层数
62 | * @param a 相对地址
63 | */
64 | private void dictate_STO(int t,int a){
65 | if(t==0){
66 |
67 | runStack.set(a, runStack.pop());
68 | }else{
69 | //不是0层,变量单元地址就是当前层的基地址+相对地址
70 | runStack.set(baseAddress + a, runStack.pop());
71 | }
72 | }
73 |
74 | /**
75 | * int 0 a
76 | * 在运行栈中为被调用的过程开辟a个单元的数据区
77 | * @param t 0
78 | * @param a 函数地址
79 | */
80 | private void dictate_CAL(int t,int a){
81 | //修改DL 和 RL
82 | int base = runStack.size();
83 | runStack.push(baseAddress);
84 | runStack.push(currentIndex+1);
85 | //更新当前层数基地址
86 | //更新当前执行指令的标号
87 | baseAddress = base;
88 | currentIndex = a - 1;
89 | }
90 | /**
91 | * int 0 a
92 | * 在运行栈中为被调用的过程开辟a个单元的数据区
93 | * @param t 0
94 | * @param a 数据区数量
95 | */
96 | private void dictate_INT(int t, int a){
97 | for(int i=0;i=500){
100 | //System.out.println("栈满500");
101 | Error.ShowErrMsg(4,"所在行数为:第"+currentIndex+"行");
102 | }
103 | }
104 | }
105 | /**
106 | * JMP 0 a
107 | * 无条件跳转至a地址
108 | * @param t 0
109 | * @param a 跳转到的地址
110 | */
111 | private void dictate_JMP(int t, int a){
112 | currentIndex = a - 1;
113 | }
114 |
115 | /**
116 | * JPC 0 a
117 | * 条件跳转,当栈顶值为0,则跳转至a地址,否则顺序执行
118 | * @param t 0
119 | * @param a 跳转地址
120 | */
121 | private void dictate_JPC(int t, int a){
122 | if(runStack.peek()==0){
123 | currentIndex = a - 1;
124 | }
125 | }
126 |
127 | /**
128 | * ADD 0 0
129 | * 次栈顶与栈顶相加,退两个栈元素,结果值进栈
130 | * @param t 0
131 | * @param a 0
132 | */
133 | private void dictate_ADD(int t, int a){
134 | int val_a = runStack.pop();
135 | int val_b = runStack.pop();
136 | runStack.push(val_a+val_b);
137 | }
138 | /**
139 | * SUB 0 0
140 | * 次栈顶减去栈顶,退两个栈元素,结果值进栈
141 | * @param t 0
142 | * @param a 0
143 | */
144 | private void dictate_SUB(int t, int a){
145 | int val_a = runStack.pop();
146 | int val_b = runStack.pop();
147 | runStack.push( val_b-val_a);
148 | }
149 |
150 | /**
151 | * MUL 0 0
152 | * 次栈顶乘以栈顶,退两个栈元素,结果值进栈
153 | * @param t 0
154 | * @param a 0
155 | */
156 | private void dictate_MUL(int t, int a){
157 | int val_a = runStack.pop();
158 | int val_b = runStack.pop();
159 | runStack.push(val_b*val_a);
160 | }
161 | /**
162 | * DIV
163 | * 次栈顶除以栈顶,退两个栈元素,结果值进栈
164 | * @param t 0
165 | * @param a 0
166 | */
167 | private void dictate_DIV(int t, int a){
168 | int val_a = runStack.pop();
169 | if(val_a==0){
170 | Error.ShowErrMsg(1,"所在行数为:第"+currentIndex+"行");
171 | }
172 | int val_b = runStack.pop();
173 | runStack.push( val_b/val_a);
174 | }
175 |
176 | /**
177 | * RED 0 0
178 | * 从命令行读入一个输入置于栈顶
179 | * @param t 0
180 | * @param a 0
181 | */
182 | private void dictate_RED(int t, int a){
183 |
184 | runStack.push(scanner.nextInt());
185 | }
186 |
187 | /**
188 | * wrt 0 0
189 | * 栈顶值输出至屏幕并换行
190 | * @param t 0
191 | * @param a 0
192 | */
193 | private void dictate_WRT(int t, int a){
194 | if(runStack.empty()){
195 | //System.out.println("读入栈失败,栈为空");
196 | Error.ShowErrMsg(4,"所在行数为:第"+currentIndex+"行");
197 | }else{
198 | System.out.println(runStack.peek());
199 | }
200 | }
201 |
202 | /**
203 | * ret 0 0
204 | * 函数调用结束后,返回调用点并退栈
205 | * 如果当前为0层,则运行结束
206 | * @param t 0
207 | * @param a 0
208 | */
209 | private void dictate_RET(int t, int a){
210 | if(baseAddress==0){
211 | currentIndex = 999999;
212 | return;
213 | }
214 | //将要return的值存在一个临时变量中
215 | //把当前层所有都退栈
216 | //再把return的值放在栈顶
217 | int returnValue = runStack.peek();
218 | currentIndex = runStack.get(baseAddress+1)-1;
219 | int baseAddressTemp = baseAddress;
220 | baseAddress = runStack.get(baseAddress);
221 | while(runStack.size()>baseAddressTemp){
222 | runStack.pop();
223 | }
224 | runStack.push(returnValue);
225 | }
226 | /**
227 | * 初始化函数
228 | */
229 | void init(){
230 | System.out.println("input the C0Target file name");
231 | readFileByLines(scanner.next());
232 | execute();
233 | }
234 | /**
235 | * 执行函数
236 | */
237 | private void execute(){
238 | while(currentIndex listMain = new ArrayList();
24 | /** 分程序空间字母表 */
25 | public static ArrayList listPart = new ArrayList();
26 | /** 超前调用字母表 */
27 | public static ArrayList listOutstrip = new ArrayList();
28 | /** 中间代码表 */
29 | public static ArrayList middleCodeList = new ArrayList();
30 | /** 返回标志 */
31 | public static boolean returnFlag = false;
32 | public static int returnFlagType = 0;
33 | /**
34 | * 向字母表中添加字母
35 | * @param type 0-全局空间 1-函数内空间
36 | */
37 | public static void addSymbolList(Token t,int type){
38 | SymbolItem symbolItem = new SymbolItem(SymbolItem.SymbolType.intSym);
39 | symbolItem.setName(t.image);
40 | symbolItem.setLevel(type);
41 | if(type==0){
42 | for(int i=0;i-1;i--){
51 | if(listPart.get(i).getType()==SymbolItem.SymbolType.functionSym){
52 | lastFunction = i;
53 | break;
54 | }
55 | }
56 | for(int i=lastFunction;i-1;i--){
165 | if(listPart.get(i).getType()==SymbolItem.SymbolType.functionSym){
166 | lastFunction = i;
167 | break;
168 | }
169 | }
170 | int relative = 1;
171 | boolean isFind = false;
172 | for (int i=lastFunction;i
244 | |
245 |
246 | |
247 |
248 | |
249 |
250 | |
251 |
252 | |
253 |
254 | |
255 |
256 | |
257 |
258 | |
259 |
260 | |
261 |
262 | |
263 |
264 | |
265 |
266 | |
267 |
268 | |
269 |
270 | |
271 |
272 | |
273 |
274 | |
275 |
276 | |
277 |
278 | |
279 |
280 | |
281 |
282 | |
283 |
284 | |
285 |
286 | }
287 |
288 | /** 程序入口. */
289 | void procedure() :
290 | {}
291 | {
292 | //[<变量定义部分>] {<自定义函数定义部分>} <主函数>
293 | [LOOKAHEAD(2)VarDefinition_CC(0)]
294 | ( LOOKAHEAD(2)FunctionDefinition_CC() )*
295 | MainFunction_CC()
296 |
297 | {
298 | outPutMiddleCodeList();
299 | outPutListPart();
300 | outPutGoalCode();
301 | }
302 | }
303 |
304 | /** 变量定义部分. */
305 | void VarDefinition_CC(int type) :
306 | {
307 | Token s;
308 | }
309 | {
310 | //int id {, id};
311 |
312 | s={
313 | addSymbolList(s,type);
314 | }
315 | (
316 | s={
317 | addSymbolList(s,type);
318 | })* {
319 | askForSpace(type);
320 | }
321 | }
322 |
323 | /** 自定义函数定义部分. */
324 | void FunctionDefinition_CC() :
325 | {
326 | Token s;
327 | int type;
328 | }
329 | {
330 | //( int id | void id) '(' ')' <分程序>
331 | (
332 | {
333 | type = 1;
334 | returnFlagType = 1;
335 | }
336 | s= |
337 | {
338 | type = 0;
339 | returnFlagType = 0;
340 | } s=)
341 |
342 | {
343 | addPartFunction(s,type);
344 | }
345 | PartProgram_CC()
346 | }
347 |
348 | /** 主函数部分 */
349 | void MainFunction_CC() :
350 | {
351 | Token s;
352 | }
353 | {
354 | //void main'(' ')' <分程序>
355 | s=
356 | {
357 | returnFlagType = 0;
358 | int mainAddress = middleCodeList.size();
359 | middleCodeList.get(1).arg1 = mainAddress;
360 | addPartFunction(s,0);
361 | }
362 | PartProgram_CC()
363 | }
364 |
365 | /**
366 | * 分程序
367 | * 如果分程序没有返回值,则自动补上返回值
368 | */
369 | void PartProgram_CC():
370 | {}
371 | {
372 | //'{' [<变量定义部分>] <语句序列> '}'
373 |
374 | {
375 | returnFlag = false;
376 | }
377 | [LOOKAHEAD(2)VarDefinition_CC(1)] WordList_CC()
378 |
379 | {
380 | if(!returnFlag){
381 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.RET,0,0);
382 | middleCodeList.add(item);
383 | }
384 | }
385 | }
386 |
387 | /** 语句序列 */
388 | void WordList_CC():
389 | {}
390 | {
391 | //<语句> {<语句>}
392 | Word_CC()(Word_CC())*
393 | }
394 |
395 | /** 语句 */
396 | void Word_CC():
397 | {}
398 | {
399 | //<条件语句>|<循环语句> | '{'<语句序列>'}' | <自定义函数调用语句> |
400 | //<赋值语句> | <返回语句> | <读语句> | <写语句> | ;
401 | IfWord_CC()
402 | |
403 | ForWord_CC()
404 | |
405 | WordList_CC()
406 | |
407 | LOOKAHEAD(2)DefinitionFunctionCallWord_CC()
408 | |
409 | EvaluateWord_CC()
410 | |
411 | ReturnWord_CC(){returnFlag=true;}
412 | |
413 | ScanfWord_CC()
414 | |
415 | PrintfWord_CC()
416 | |
417 |
418 | }
419 |
420 | /** 条件语句 */
421 | void IfWord_CC():
422 | {
423 | int jpcAdress;
424 | int jmpAdress;
425 | }
426 | {
427 | //if '('<表达式>')' <语句> [else <语句> ]
428 |
429 | Expression_CC()
430 | {
431 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.JPC,0,0);
432 | middleCodeList.add(item);
433 | jpcAdress = middleCodeList.size()-1;
434 | }
435 |
436 | Word_CC()
437 | {
438 | MiddleCodeItem item2 = new MiddleCodeItem(MiddleCodeItem.CodeType.JMP,0,middleCodeList.size()+1);
439 | middleCodeList.add(item2);
440 | middleCodeList.get(jpcAdress).arg1 = middleCodeList.size();
441 | jmpAdress = middleCodeList.size()-1;
442 | }
443 | [LOOKAHEAD(2) Word_CC()
444 | {
445 | middleCodeList.get(jmpAdress).arg1 = middleCodeList.size();
446 | }
447 | ]
448 | }
449 |
450 | /** 循环语句 */
451 | void ForWord_CC():
452 | {
453 | int whileBegin;
454 | int whileEnd;
455 | }
456 | {
457 | //while '(' <表达式>')' <语句>
458 |
459 | {
460 | whileBegin = middleCodeList.size();
461 | }
462 | Expression_CC()
463 | {
464 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.JPC,0,whileBegin);
465 | middleCodeList.add(item);
466 | }
467 | Word_CC()
468 | {
469 | MiddleCodeItem item2 = new MiddleCodeItem(MiddleCodeItem.CodeType.JMP,0,whileBegin);
470 | middleCodeList.add(item2);
471 | whileEnd = middleCodeList.size();
472 | middleCodeList.get(whileBegin+1).arg1 = whileEnd;
473 | }
474 | }
475 |
476 | /** 自定义函数调用语句 */
477 | void DefinitionFunctionCallWord_CC():
478 | {}
479 | {
480 | //<自定义函数调用>
481 | DefinitionFunction_CC()
482 | }
483 |
484 | /** 赋值语句 */
485 | void EvaluateWord_CC():
486 | {
487 | Token t;
488 | }
489 | {
490 | //id = <表达式>;
491 | t= Expression_CC() {
492 | getVariableById(t,1);
493 | }
494 | }
495 |
496 | /** 返回语句 */
497 | void ReturnWord_CC():
498 | {
499 | int flag=0;
500 | }
501 | {
502 | //return ['(' <表达式> ')'] ;
503 | [ Expression_CC()
504 | {
505 | flag = 1;
506 | }
507 | ] {
508 | if(returnFlagType==0&&flag==1){
509 | ExError.ShowErrMsg(4,"This function must return null");
510 | }else if(returnFlagType==1&&flag==0){
511 | ExError.ShowErrMsg(4,"This function must return int");
512 | }
513 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.RET,0,0);
514 | middleCodeList.add(item);
515 | }
516 | }
517 |
518 | /** 读语句 */
519 | void ScanfWord_CC():
520 | {
521 | Token t;
522 | }
523 | {
524 | //scanf '(' id ')';
525 | t= {
526 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.RED,0,0);
527 | middleCodeList.add(item);
528 | getVariableById(t,1);
529 | }
530 | }
531 |
532 | /** 写语句 */
533 | void PrintfWord_CC():
534 | {}
535 | {
536 | // printf '(' [ <表达式>] ')';
537 | [Expression_CC()] {
538 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.WRT,0,0);
539 | middleCodeList.add(item);
540 | }
541 | }
542 |
543 | /** 表达式 */
544 | void Expression_CC():
545 | {
546 | Token t;
547 | }
548 | {
549 | //[+|-] <项> { (+|-) <项>}
550 | [|] Sum_CC() ( (
551 | t=|t=) Sum_CC()
552 | {
553 | if(t.image.equals("+")){
554 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.ADD,0,0);
555 | middleCodeList.add(item);
556 | }else{
557 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.SUB,0,0);
558 | middleCodeList.add(item);
559 | }
560 | })*
561 | }
562 |
563 | /** 项 */
564 | void Sum_CC():
565 | {}
566 | {
567 | //<因子>{(*|/) <因子>}
568 | Divisor_CC() ((
569 |
570 | {
571 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.MUL,0,0);
572 | middleCodeList.add(item);
573 | }
574 | |
575 |
576 | {
577 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.DIV,0,0);
578 | middleCodeList.add(item);
579 | }
580 | ) Divisor_CC())*
581 | }
582 |
583 | /** 因子 */
584 | void Divisor_CC():
585 | {
586 | Token s;
587 | }
588 | {
589 | //<自定义函数调用> | '(' <表达式>')' | num | id
590 | LOOKAHEAD(2)DefinitionFunction_CC()
591 | |
592 | Expression_CC()
593 | |
594 | s={
595 | MiddleCodeItem item = new MiddleCodeItem(MiddleCodeItem.CodeType.LIT,0,Integer.parseInt(s.image));
596 | middleCodeList.add(item);
597 | }
598 | |
599 | LOOKAHEAD(2)s=
600 | {
601 | getVariableById(s,0);
602 | }
603 | }
604 |
605 | /** 自定义函数调用 */
606 | void DefinitionFunction_CC():
607 | {
608 | Token t;
609 | }
610 | {
611 | //id '(' ')'
612 | t=
613 | {
614 | getFunctionById(t);
615 | }
616 | }
--------------------------------------------------------------------------------
/src/com/imudges/C0Compiler/JavaCC/ExError.java:
--------------------------------------------------------------------------------
1 | // package com.imudges.C0Compiler.JavaCC;
2 | /**
3 | * @author shianqi@imudges.com
4 | * Created by shianqi on 2016/12/14.
5 | */
6 | public class ExError {
7 | public static enum ErrCode{
8 | ArithmeticException, //算数异常
9 | InputParamErrException, //输入参数错误
10 | VariableException, //变量异常
11 | FunctionException,
12 | UnknowException //未知错误
13 | }
14 | public static boolean errFlag=false;
15 | public static void ShowErrMsg(int errCode,String errMsg){
16 | switch (errCode){
17 | case 1:{showMessage(ErrCode.ArithmeticException,errMsg);break;}
18 | case 2:{showMessage(ErrCode.InputParamErrException,errMsg);break;}
19 | case 3:{showMessage(ErrCode.VariableException,errMsg);break;}
20 | case 4:{showMessage(ErrCode.FunctionException,errMsg);break;}
21 | default:{showMessage(ErrCode.VariableException,errMsg);break;}
22 | }
23 |
24 | }
25 |
26 | private static void showMessage(ErrCode errCode,String errMsg){
27 | System.err.println("Error-"+errCode.toString()+": "+errMsg);
28 | errFlag=true;
29 | }
30 |
31 | /*public static void main(String[] args) {
32 | System.out.println(ErrCode.askMemoryTooBigException.toString());
33 | }*/
34 | }
35 |
--------------------------------------------------------------------------------
/src/com/imudges/C0Compiler/JavaCC/MiddleCodeItem.java:
--------------------------------------------------------------------------------
1 | // package com.imudges.C0Compiler.JavaCC;
2 | /**
3 | * @author shianqi@imudges.com
4 | * Created by shianqi on 2016/12/14.
5 | */
6 | public class MiddleCodeItem{
7 | public static enum CodeType{
8 | LIT, LOD, STO, CAL, INT, JMP, JPC,
9 | ADD, SUB, MUL, DIV, RED, WRT, RET
10 | }
11 | public CodeType codeType;
12 | public int arg0;
13 | public int arg1;
14 |
15 | public MiddleCodeItem(CodeType codeType,int arg0, int arg1){
16 | this.codeType = codeType;
17 | this.arg0 = arg0;
18 | this.arg1 = arg1;
19 | }
20 |
21 | public String toString(){
22 | return codeType.toString()+" "+arg0+" "+arg1;
23 | }
24 | public String toOutString(){
25 | return codeType.toString()+"\t"+arg0+"\t"+arg1;
26 | }
27 | }
--------------------------------------------------------------------------------
/src/com/imudges/C0Compiler/JavaCC/SymbolItem.java:
--------------------------------------------------------------------------------
1 | // package com.imudges.C0Compiler.JavaCC;
2 | /**
3 | * @author shianqi@imudges.com
4 | * Created by shianqi on 2016/12/13
5 | */
6 | public class SymbolItem {
7 | public SymbolItem(SymbolType type) {
8 | this.type = type;
9 | this.name = "";
10 | this.val = 0;
11 | this.level = 0;
12 | this.adr = 0;
13 | this.size = 0;
14 | this.returnType = 0;
15 | }
16 |
17 | public String toString(){
18 | return type.toString()+"\t"+name+"\t"+adr+"\t"+returnType;
19 | }
20 |
21 | public enum SymbolType{
22 | intSym,
23 | functionSym
24 | }
25 |
26 | private String name;
27 | private SymbolType type;
28 | private int val;
29 | private int level;
30 | private int adr;
31 | private int size;
32 | private int returnType;
33 |
34 | public int getReturnType() {
35 | return returnType;
36 | }
37 |
38 | public void setReturnType(int returnType) {
39 | this.returnType = returnType;
40 | }
41 |
42 | public String getName() {
43 | return name;
44 | }
45 |
46 | public void setName(String name) {
47 | this.name = name;
48 | }
49 |
50 | public SymbolType getType() {
51 | return type;
52 | }
53 |
54 | public void setType(SymbolType type) {
55 | this.type = type;
56 | }
57 |
58 | public int getVal() {
59 | return val;
60 | }
61 |
62 | public void setVal(int val) {
63 | this.val = val;
64 | }
65 |
66 | public int getLevel() {
67 | return level;
68 | }
69 |
70 | public void setLevel(int level) {
71 | this.level = level;
72 | }
73 |
74 | public int getAdr() {
75 | return adr;
76 | }
77 |
78 | public void setAdr(int adr) {
79 | this.adr = adr;
80 | }
81 |
82 | public int getSize() {
83 | return size;
84 | }
85 |
86 | public void setSize(int size) {
87 | this.size = size;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/com/imudges/C0Compiler/JavaCC/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "javacc",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start" : "java -cp C://javacc-6.0//bin//lib//javacc.jar javacc Compiler.jj & javac Compiler.java & java Compiler",
9 | "ex" : "java Compiler"
10 | },
11 | "author": "",
12 | "license": "ISC"
13 | }
14 |
--------------------------------------------------------------------------------
/testFile/main.c0:
--------------------------------------------------------------------------------
1 | int sum,count;
2 | int func(){
3 | int i,temp;
4 | i = count;
5 | temp = 0;
6 | while(i){
7 | temp = temp + i;
8 | i = i-1;
9 | }
10 | return (temp);
11 | }
12 | void main(){
13 | scanf(count);
14 | sum = +func();
15 | printf(sum);
16 | }
--------------------------------------------------------------------------------
/testFile/main.c0Target:
--------------------------------------------------------------------------------
1 | INT 0 2
2 | CAL 0 22
3 | RET 0 0
4 | JMP 0 4
5 | INT 0 2
6 | LOD 0 1
7 | STO 2 2
8 | LIT 0 0
9 | STO 2 3
10 | LOD 2 2
11 | JPC 0 20
12 | LOD 2 3
13 | LOD 2 2
14 | ADD 0 0
15 | STO 2 3
16 | LOD 2 2
17 | LIT 0 1
18 | SUB 0 0
19 | STO 2 2
20 | JMP 0 9
21 | LOD 2 3
22 | RET 0 0
23 | INT 0 0
24 | RED 0 0
25 | STO 0 1
26 | CAL 0 4
27 | STO 0 0
28 | LOD 0 0
29 | WRT 0 0
30 | RET 0 0
--------------------------------------------------------------------------------