├── .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 | 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 --------------------------------------------------------------------------------