├── IR.h ├── IR2ARM.md ├── Makefile ├── README.md ├── codegen.c ├── codegen.h ├── intercode.h ├── intercode2.c ├── list.c ├── list.h ├── node.c ├── node.h ├── symtable.c ├── symtable.h ├── syntax ├── syntax.dSYM └── Contents │ ├── Info.plist │ └── Resources │ └── DWARF │ └── syntax ├── syntax.l ├── syntax.y ├── testCase ├── README.md ├── lexTest │ ├── lexTest.l │ ├── lexTest.sh │ ├── lexTest.txt │ └── lextest ├── syntaxRight.c ├── test.c ├── test1.c ├── test2.c ├── test3.c ├── test4.c ├── test5.c └── test6.c ├── vector.c ├── vector.h ├── visAST ├── ast.dot ├── visast.c └── visast.h ├── 实验报告.assets ├── gitlab.png ├── hash_table.png ├── hash_table_scope.png ├── image-20210615214000523.png ├── lex_test_1.png ├── lex_test_2.png ├── lex_test_3.png ├── lex_test_4.png ├── lex_test_5.png ├── result_ast.png ├── result_ast_vis.png ├── sem_test1.png ├── sem_test2.png ├── sem_test3.png ├── sem_test4.png ├── sem_test5.png ├── sem_test6.png └── type_array.png └── 实验报告.md /IR.h: -------------------------------------------------------------------------------- 1 | // simple intermediate code representation -- linear structure (learning from NJU, not the final result) 2 | // we can design the intermediate code by hand and use hierarchical representation for optimization, hence better performance 3 | #ifndef _IR_H_ 4 | #define _IR_H_ 5 | 6 | #include 7 | #include 8 | typedef struct Operand_* Operand; 9 | typedef struct InterCode_* InterCode; 10 | typedef struct Label_No_* Label_No; 11 | 12 | typedef struct Operand_ { 13 | // operand kind: temporary variable, variable, constant, virtual address, label, function?, true address? 14 | enum { TEMPVAR, VARIABLE, CONSTANT, VADDRESS, LABEL, FUNCTION_, TADDRESS } kind; 15 | union { 16 | int var_no; // variable number ? 17 | char* value; // element width ?? for variable kind 18 | Operand addr; // address 19 | } u; 20 | Operand next; 21 | } Operand_; 22 | 23 | typedef struct InterCode_{ 24 | // intercode kind: assgin, add, etc... 25 | enum { ASSIGN_N,ADD_N,SUB_N,MUL_N,DIV_N,RETURN_N,LABEL_N,GOTO_N,IFGOTO_N,READ_N,WRITE_N,CALL_N,ARG_N,FUNCTION_N,PARAM_N,DEC_N,ADDRESS_N } kind; 26 | // operands for different operations 27 | union { 28 | struct { Operand op; } sinop; // single 29 | struct { Operand left, right; } assign; 30 | struct { Operand op1, op2, result; } binop; // binary 31 | struct { Operand x; Operand y; Operand label; char *op; } triop; // triple 32 | struct { Operand op; int size; }dec; 33 | } u; 34 | InterCode pre; // doubly linked list code是线性结构的-每个三地址码用链表按顺序连接? 35 | InterCode next; 36 | } InterCode_; 37 | 38 | // Label for three address code ? Mark the place for jump 39 | typedef struct Label_No_ 40 | { 41 | int no; 42 | Label_No next; 43 | } Label_No_; 44 | 45 | void insertIRCode(InterCode c); 46 | void deleteIRCode(InterCode c); 47 | void printCode(char* fileName); 48 | 49 | extern struct IRList_ IRList; 50 | 51 | 52 | #endif -------------------------------------------------------------------------------- /IR2ARM.md: -------------------------------------------------------------------------------- 1 | | 中间代码 | ARM指令 | 2 | | ----------- | ---------------------- | 3 | | LABEL x: | x | 4 | | x := #k | mov reg(x), #k | 5 | | x := y | mov reg(x), reg(y) | 6 | | x := y + #k | add reg(x), reg(y), #k | 7 | | x := y + z | add reg(x), reg(y), reg(z) | 8 | | x := y - #k | sub reg(x), reg(y), #k | 9 | | x := y - z | sub reg(x), reg(y), reg(z) | 10 | | x := y *z | mul reg(x), reg(y), reg(z) | 11 | | x := y / z | div reg(x), reg(y), reg(z) | 12 | | x := *y | ldr reg(x), [reg(y)] | 13 | | *x = y | str reg(y), [reg(x)] | 14 | | GOTO x | B x | 15 | | x := CALL f | BL f
mov reg(x), r0 | 16 | | RETURN x | mov pc, lr | 17 | | IF x == y GOTO z| cmp reg(x), reg(y)
beq z | 18 | | IF x != y GOTO z| cmp reg(x), reg(y)
bne z | 19 | | IF x > y GOTO z | cmp reg(x), reg(y)
bgt z | 20 | | IF x < y GOTO z | cmp reg(x), reg(y)
blt z | 21 | | IF x >= y GOTO z | cmp reg(x), reg(y)
bge z | 22 | | IF x <= y GOTO z | cmp reg(x), reg(y)
ble z | 23 | 24 | | | | 25 | | ---------- | ------------------------------------------------------------ | 26 | | x := y % z | div reg_tmp reg(y), reg(z)
mul reg_tmp0 reg_tmp0, reg(z)
sub reg(x), reg(y), reg_tmp0 | 27 | | FUNCTION f | f | 28 | | PARAM x | | 29 | | | | 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | main: 2 | flex syntax.l 3 | bison -d syntax.y 4 | gcc -o syntax -g lex.yy.c syntax.tab.c node.c list.c vector.c symtable.c intercode2.c 5 | clean: 6 | rm lex.yy.c syntax.tab.c syntax.tab.h 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # myCompiler 2 | 3 | A simple compiler for a sysY language 4 | 5 | SysY language is a subset of the C programming language. Every source code of SysY program is stored with an extension of 'sy'. It has one and only one 'main' function. It can also have several global variable declarations, constant variable declarations and other function definitions. SysY language supports **int** type and **multidimensional arrays**. 'int' type integer is 32-bit signed number. 6 | 7 | SysY language itself has no input/output(I/O) constructs, and I/O is provided by means of runtime library, which can be invoked inside functions of SysY programs. 8 | 9 | We implement a SysY language compiler which can carry out lexical analysis, syntax analysis, semantic analysis, code generation and optimization. 10 | 11 | ## 1 Lexical analysis 12 | 13 | ### 1.1 Tokens 14 | 15 | * Types:`int`,`void`,`const` 16 | * Control Flow:`if`,`else`,`while`,`continue`,`break` 17 | * Function:`return`,`{}`,`;` 18 | * Operators(by priority): 19 | * `()`,`[]` :parameter、subscript 20 | * `!`,`-` :negation、minus 21 | * `*`,`/`,`%`:multiplication、division、modulus 22 | * `+`,`-`:plus、minus 23 | * `<`,`<=`,`>`,`>=`:relation operators 24 | * `==`,`!=`:equals to、not equals to 25 | * `&&`:logical and 26 | * `||`:logical or 27 | * `=`:assign 28 | * `,`:separator 29 | 30 | ### 1.2 Token definitions 31 | 32 | ```c 33 | // keywords 34 | %token RETURN IF ELSE WHILE CONST VOID BREAK CONTINUE INT 35 | 36 | // identifiers and numbers 37 | %token ID INTCONST 38 | 39 | // Operators 40 | %token LT GT LTE GTE EQ NEQ PLUS MINUS STAR DIV PERCENT 41 | %token AND OR NOT ASSIGNOP 42 | 43 | // Delimeters 44 | %token LP RP LB RB LC RC SEMI COMMA 45 | // ( ) [ ] { } ; , 46 | 47 | Regular expressions: 48 | 49 | ```c 50 | // ID 51 | identifier = [a-zA-Z_][a-zA-Z0-9_]* 52 | 53 | // INTCONST 54 | octal_const = 0[0-7]* 55 | decimal_const = [1-9][0-9]* 56 | hexadecimal_const = (0x|0X)[0-9A-F]+ 57 | 58 | // Comment 59 | single_line_comment = "//".* 60 | multi_line_comment = [/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] 61 | 62 | 63 | ### 1.3 Implementation using Lex 64 | 65 | We use Lex to implement lexical analysis. Lex source code is mainly a table composed of regular expressions and corresponding code snippets. Lex will convert the table into a corresponding program to read the input stream, divide the input into character strings matching regular expressions, and execute the corresponding program fragments after identifying the corresponding character strings. Lex recognizes expressions by generating deterministic finite automata, and code fragments will be executed in the order of expressions corresponding to strings appearing in the input stream. 66 | 67 | Consider the generation of the subsequent syntax tree (details are given later), after identifying the corresponding string, we will create a new and return the corresponding node. Examples are as follows: 68 | 69 | ```c 70 | "+" { yylval.node = newNodeOp("PLUS"); return PLUS; } 71 | ``` 72 | 73 | The lex codes of keywords, operators, and delimiters are all similar to this, and will not be listed one by one. 74 | 75 | Identifiers and real numbers are different. In addition to returning nodes of the corresponding type, they also require additional operations. For example, identifiers need to return the identifier name, and real numbers need to return the corresponding value. The specific implementation is as follows: 76 | 77 | ```c 78 | // identifier 79 | [a-zA-Z_][a-zA-Z0-9_]* { 80 | yylval.node = newNodeString("ID", yytext); 81 | return ID; 82 | } 83 | // numbers 84 | {octal_const} { 85 | int itmp; 86 | sscanf(yytext, "%o", &itmp); 87 | yylval.node = newNodeInt("INTCONST", itmp); 88 | return INTCONST; 89 | } 90 | {decimal_const} { 91 | int itmp; 92 | sscanf(yytext, "%d", &itmp); 93 | yylval.node = newNodeInt("INTCONST", itmp); 94 | return INTCONST; 95 | } 96 | {hexadecimal_const} { 97 | int itmp; 98 | sscanf(yytext, "%x", &itmp); 99 | yylval.node = newNodeInt("INTCONST", itmp); 100 | return INTCONST; 101 | } 102 | ``` 103 | 104 | When a blank character of comment is encountered, the operation is skipped. 105 | 106 | ## 2 Syntax analysis 107 | 108 | ### 2.1 Syntax 109 | /// 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /codegen.c: -------------------------------------------------------------------------------- 1 | #include "codegen.h" 2 | #include 3 | #include 4 | #include 5 | #include "intercode.h" 6 | #define isConst(op) (op->kind==OP_CONSTANT) 7 | #define opVal(op) (op->u.val) 8 | asmCodeList target_codelist = NULL; 9 | 10 | int isText = -1; //-1: 初始 0:在data段中 1:在text段中 11 | asmCodeList new_asmCodeList(char* code) 12 | { 13 | asmCodeList cl = (asmCodeList)malloc(sizeof(struct asmCodeList_)); 14 | cl->code = code; 15 | cl->next = cl->prev = NULL; // 双向链表 16 | return cl; 17 | } 18 | 19 | // 合并两个CodeList 20 | asmCodeList asm_join(asmCodeList head, asmCodeList body) 21 | { 22 | if(head == NULL) { 23 | return body; 24 | } 25 | asmCodeList tmp = head; 26 | while(tmp->next != NULL) { // 链表结尾是NULL 27 | tmp = tmp->next; 28 | } 29 | tmp->next = body; 30 | if(body != NULL) { 31 | body->prev = tmp; 32 | } 33 | return head; 34 | } 35 | 36 | CodeList currentCode = NULL; // 记录主循环中当前遍历到的中间代码 37 | void codegen(CodeList cl){ 38 | if(cl==NULL) 39 | { 40 | fprintf(stderr, "CodeList is NULL!\n"); 41 | return; 42 | } 43 | asm_join(target_codelist, gen_header()); 44 | while(cl) 45 | { 46 | currentCode = cl; // 47 | InterCode p = cl->code; 48 | if(p->kind == IR_FUNC){ 49 | target_codelist = asm_join(target_codelist, gen_ir_func(p)); 50 | cl=cl->next; 51 | while(cl) 52 | { 53 | if(cl->code->kind == IR_ENDFUNC) break; 54 | switch (cl->code->kind) 55 | { 56 | case IR_ASSIGN: // x := y 57 | gen_ir_assign(ir); break; 58 | case IR_LABEL: // LABEL x : 59 | gen_ir_label(ir);break; 60 | case IR_PLUS: // x := y+z 61 | gen_ir_plus(ir, "ADD");break; 62 | case IR_MINUS: // x := y-z 63 | gen_ir_plus(ir, "SUB");break; 64 | case IR_MUL: // x := y*z 65 | gen_ir_plus(ir, "MUL");break; 66 | case IR_DIV: // x := y/z 67 | gen_ir_plus(ir, "DIV");break; 68 | case IR_MOD: // x : = y%z 69 | gen_ir_plus(ir, "MOD");break; // arm无mod-需要修改 70 | case IR_FUNC: // FUNCTION f : 71 | gen_ir_func(ir);break; 72 | case IR_GOTO: // GOTO x 73 | gen_ir_goto(ir);break; 74 | case IR_IFGOTO: // IF x [relop] y GOTO z 75 | gen_ir_ifgoto(ir);break; 76 | case IR_RET: // x = *y 77 | // 不太确定 78 | break; 79 | case IR_DEC: // DEC x [size] 内存空间申请-大小为4的倍数 用于数组 80 | //不太确定 81 | gen_ir_dec(ir);break; 82 | case IR_ARG: // ARG x 83 | gen_ir_arg(ir);break; 84 | case IR_CALL: // x := CALL f 85 | gen_ir_call(ir);break; 86 | case IR_PARAM: // PARAM x 87 | gen_ir_params(ir);break; 88 | case IR_READ: // 不用 89 | // gen_ir_read(ir); 90 | break; 91 | case IR_WRITE: // 不用 92 | // gen_ir_write(ir); 93 | break; 94 | case IR_RETURN: // RETURN x 95 | gen_ir_return(ir);break; 96 | case IR_CHANGE_ADDR: // *x := y 取y值以赋给x值为地址的内存单元 97 | // 不确定 98 | break; 99 | case IR_GET_ADDR: // x := &y 取y的地址赋给x // 名字可能起的不是很好 100 | // 不确定 101 | break; 102 | default: 103 | printf("Error: Unknown Kind to ARM32\n"); 104 | break; 105 | } 106 | cl=cl->next; 107 | } 108 | cl=cl->next; 109 | } 110 | } 111 | } 112 | 113 | asmCodeList gen_header() 114 | { 115 | return asm_join( 116 | asm_join( 117 | new_asmCodeList(".macro mov32, reg, val"), 118 | new_asmCodeList("\tmovw \\reg, #:lower16:\\val") 119 | ), 120 | asm_join( 121 | new_asmCodeList("\tmovt \\reg, #:upper16:\\val"), 122 | asm_join( 123 | new_asmCodeList(".endm"), 124 | new_asmCodeList("\n") 125 | ) 126 | ) 127 | ); 128 | } 129 | 130 | asmCodeList gen_ir_func(InterCode ir) 131 | { 132 | CodeList res = NULL; 133 | if(isText != 1){ 134 | res = asm_join(res, new_asmCodeList(".text")); 135 | char* msg = malloc(64); 136 | sprintf(msg, ".global %s", ir->u.func); 137 | res = asm_join(res, new_asmCodeList(msg)); 138 | msg = malloc(64); 139 | sprintf(msg, ".type\t %s, %%function", ir->u.func); 140 | res = asm_join(res, new_asmCodeList(msg)); 141 | msg = malloc(64); 142 | sprintf(msg, "%s:", ir->u.func); 143 | res = asm_join(res, new_asmCodeList(msg)); 144 | } 145 | else if(isText == 0){ 146 | int frameSize = getframeSize(); //获取局部变量以及需要用到的参数的值(小于等于4个-如果多余-直接用fp去往前找) 147 | stackSize = frameSize; // 这个全局变量-其他地方可能会用到 148 | char* msg = malloc(64); 149 | //sprintf(msg, "%s:\n\tSUB sp, sp, #4\n\tSTR $fp, 0(sp)\n\tmov $fp, $sp\n\tsubu $sp, $sp, %d\n",interCode->u.sinop.op->u.value,stackSize); 150 | sprintf(msg, "%s:\n\tSUB sp, sp, #4\n\tSTR fp, [sp, #0]\n\tMOV fp, sp,\n\tSUB sp, sp, #%d\n", ir->u.func,frameSize); 151 | // SUB sp, sp, #4 152 | // STR fp, [sp, #0] -- 存老的fp -- lr存储这里是在CALL解析的时候做 153 | // MOV fp, sp -- fp指向栈底 154 | // SUB sp, sp, #stacksize -- 函数的变量空间 155 | spOffset = 0; 156 | curParam = 0; 157 | res = new_asmCodeList(msg); 158 | } 159 | isText = 1; 160 | return res; 161 | } 162 | 163 | // 获取一个函数的栈帧大小 164 | int getframeSize() 165 | { 166 | CodeList cl = currentCode; // 遍历函数部分中间代码-记录变量数 167 | //从function开始往下 168 | int countParam = 0; 169 | int countVarTmp = 0; 170 | while(cl) 171 | { 172 | InterCode p = cl->code; 173 | if(p->kind == IR_PARAM) 174 | { 175 | ++countParam; 176 | } 177 | if(p->kind == IR_ASSIGN || p->kind == IR_PLUS || p->kind == IR_MINUS || 178 | p->kind == IR_MUL || p->kind == IR_DIV || p->kind==IR_MOD) // 可能还有address的kind以及数组的空间申请 179 | { 180 | //左边变量名在中间代码里面应该没有重复的-所以直接加上去了-区别就是没有和源代码对应 181 | ++countVarTmp; 182 | } 183 | if(p->kind == IR_DEC) 184 | { 185 | countVarTmp += p->u.dec.size; //这里数组空间申请可能还是不太清楚 186 | } 187 | if(p->kind == IR_ENDFUNC) 188 | break; 189 | cl = cl->next; 190 | } 191 | int frameSize = 4 * (countParam - 4) + 4 * countVarTmp; 192 | return frameSize; 193 | } 194 | 195 | // 对应的就是 DEC x [size] 申请数组空间 也不确定 196 | asmCodeList gen_ir_dec(InterCode ir){ 197 | Var_t *arrayHead = malloc(sizeof(Var_t)); 198 | spOffset -= 4; 199 | arrayHead->offset = spOffset; 200 | spOffset -= ir->u.dec.size; 201 | char *arrayName = malloc(32); 202 | memset(arrayName, 0, sizeof(arrayName)); 203 | if(ir->u.dec.x->kind == OP_VARIABLE) 204 | { 205 | sprintf(arrayName, "v%d", ir->u.dec.x->u.var_no); 206 | arrayHead->name = arrayName; 207 | } 208 | else if (ir->u.dec.x->kind == OP_TEMP) 209 | { 210 | sprintf(arrayName, "t%d", ir->u.dec.x->u.temp_no); 211 | arrayHead->name = arrayName; 212 | } 213 | addVar(arrayHead); 214 | char msg = malloc(64); 215 | sprintf(msg, "\tADD r4, fp, #%d\n\tSTR r4, [fp, #%d]", spOffset, arrayHead->offset); 216 | // 这里也不太确定--写一个字节系的是什么呢? 217 | return new_asmCodeList(msg); 218 | } 219 | 220 | /*char* trans_operand(Operand op) 221 | { 222 | char msg[64] = ""; 223 | if(op->kind == OP_CONSTANT) { 224 | sprintf(msg,"#%d",op->u.val); // 常量(目前应该叫立即数). 例如 #0 225 | } 226 | else if(op->kind == OP_LABEL) { 227 | sprintf(msg,"label%d",op->u.label_no); // 标签. 例如 label1. 全局唯一 228 | } 229 | else{ 230 | int regid = getreg(op); //分配寄存器 231 | sprintf(msg, "r%d", regid); 232 | } 233 | char *ret = malloc(strlen(msg)+1); // 返回空间指针 234 | strcpy(ret, msg); 235 | return ret; 236 | }*/ 237 | int getreg(Operand op) 238 | { 239 | return 1; 240 | } 241 | 242 | asmCodeList load_to_reg(Operand op, int regid) 243 | { 244 | return NULL; 245 | } 246 | 247 | // ok 248 | asmCodeList gen_ir_label(InterCode ir) 249 | { 250 | char* msg = (char*)malloc(64); 251 | sprintf(msg, "label%d:", ir->u.op->u.label_no); 252 | return new_asmCodeList(msg); 253 | } 254 | 255 | 256 | asmCodeList gen_ir_assign(InterCode ir) 257 | { 258 | if(isConst(ir->u.assign.right)) 259 | { 260 | int reg_left = getreg(ir->u.assign.left); 261 | char* msg = (char*)malloc(64); 262 | sprintf(msg, "\tMOV r%d, #%d", reg_left, opVal(ir->u.assign.right)); 263 | return new_asmCodeList(msg); 264 | } 265 | else 266 | { 267 | int reg_left = getreg(ir->u.assign.left); 268 | int reg_right = getreg(ir->u.assign.right); 269 | asmCodeList load_right = load_to_reg(ir->u.assign.right, reg_right); 270 | char* msg = (char*)malloc(64); 271 | sprintf(msg, "\tMOV r%d, r%d", reg_left, reg_right); 272 | asmCodeList mov_value = new_asmCodeList(msg); 273 | //asmCodeList store_left = store_to_reg(ir->u.assign.left, reg_left); 274 | return asm_join(load_right, mov_value); 275 | } 276 | } 277 | 278 | // 将变量对应的寄存器值保存到栈上 ok 279 | asmCodeList swReg(int index){ 280 | char* msg = malloc(64); 281 | memset(msg, 0, 64); 282 | Var_t *var = regs[index].var; 283 | sprintf(msg, "\tSTR %s, [fp, #%d]\n", regName[index], var->offset); 284 | return new_asmCodeList(msg); 285 | } 286 | // 将栈上值加载到寄存器上 ok 287 | asmCodeList lwReg(int index, Var_t *var) { 288 | char* msg = malloc(64); 289 | memset(msg, 0, 64); 290 | regs[index].var = var; 291 | sprintf(msg, "\tLDR %s, [fp, #%d]\n", regName[index], var->offset); 292 | return new_asmCodeList(msg); 293 | } 294 | 295 | // x := CALL f ok 296 | asmCodeList gen_ir_call(InterCode ir) 297 | { 298 | char* msg = malloc(64); 299 | asmCodeList res; 300 | sprintf(msg, "\tSUB sp, sp, #4\n"); // SUB sp, sp, #4 -- 开出一个字节的空间 301 | asmCodeList sub_sp = new_asmCodeList(msg); 302 | sprintf(msg, "\tSTR, lr, [sp, #0]\n"); // STR LR, [sp, #0] -- 保存返回地址 303 | asmCodeList str_lr = new_asmCodeList(msg); 304 | res = asm_join(sub_sp, str_lr); 305 | 306 | ir->u.call.func; 307 | Operand op = ir->u.call.result; // 函数返回值接受对象 308 | int x = getreg(op); // 大概是寄存器返回的序号 309 | 310 | // BL f 311 | // MOV reg(x), r0 312 | sprintf(msg, "\tBL %s\n\tMOV %s, r0\n", ir->u.call.func, regName[x]); /// 注意x的返回情况 313 | asmCodeList bl_mov = new_asmCodeList(msg); 314 | res = asm_join(res, bl_mov); 315 | asmCodeList swreg = swReg(x); 316 | res = asm_join(res, swreg); 317 | 318 | sprintf(msg, "\tLDR lr, [sp, #0]\n"); // LDR, lr, [sp, #0] -- 加载原来的lr 319 | asmCodeList ldr_lr = new_asmCodeList(msg); 320 | res = asm_join(res, ldr_lr); 321 | 322 | sprintf(msg, "\tADD sp, sp, #4\n"); // ADD, sp, sp, #4 -- 回收lr的空间 323 | asmCodeList add_sp = new_asmCodeList(msg); 324 | res = asm_join(res, add_sp); 325 | curArg = 0; // arg数清0 326 | 327 | return res; 328 | } 329 | 330 | // ARG x ok 331 | asmCodeList gen_ir_arg(InterCode ir) 332 | { 333 | char* msg = malloc(64); 334 | memset(msg, 0, 64); 335 | Operand op = ir->u.op; 336 | Var_t *arg = NULL; 337 | if(op->kind == OP_TEMP){ 338 | char argName[20]; 339 | memset(argName, 0, 20); 340 | sprintf(argName, "t%d", op->u.var_no); 341 | arg = findVar(argName); 342 | } else if(op->kind == OP_VARIABLE){ 343 | char argName[20]; 344 | memset(argName, 0, 20); 345 | sprintf(argName, "v%d", op->u.var_no); 346 | arg = findVar(argName); 347 | // 这部分之后可能会会统一 348 | } 349 | if(arg == NULL) 350 | exit(-1); 351 | 352 | /// 实参传递 - 小于4个直接放到r0到r3寄存器中 353 | /// 多余4个放到栈上 -- 这里我也不清楚栈的变化情况?属于当前函数的栈的-变量部分? 354 | if(curArg < 4){ 355 | sprintf(msg, "\tLDR r%d, [fp, #%d]\n", curArg, arg->offset); // LDR r0-r3, [fp, #offset] // 应该就是根据fp的offset定位变量位置 356 | } 357 | else { 358 | sprintf(msg, "\tLDR r4, [fp, #%d]\n\tSUB sp, sp, #4\n\tSTR r4, [sp, #0]\n", arg->offset); 359 | // LDR r4, [fp, #offset] 360 | // SUB sp, sp, #4 361 | // STR r4, [sp, #0] 362 | // 原来的mips版本如下-比较疑惑-最后应该是sw才对 363 | // sprintf(str, "\tlw $s0, %d($fp)\n\tsubu $sp, $sp, 4\n\tlw $s0, 0($sp)\n", arg->offset); 364 | } 365 | ++curArg; 366 | if(currentCode->next==NULL || currentCode->next->code->kind != IR_ARG) // 实参传递结束 367 | { 368 | curArg = 0; 369 | return NULL; 370 | } 371 | return new_asmCodeList(msg); 372 | } 373 | 374 | // RETURN x ok 375 | asmCodeList gen_ir_return(InterCode ir) 376 | { 377 | char* msg = malloc(64); 378 | memset(msg, 0, 64); 379 | Operand op = ir->u.op; // RETURN x 380 | if(op->kind!=OP_CONSTANT){ 381 | int x = getreg(op); 382 | // MOV r0, reg(x) -- 返回值存r0上 383 | // ADD sp, sp, #stacksize -- stacksize的计算和传递!!未完善 -- 这里回收变量栈空间 384 | // LDR fp, [sp, #0] -- 加载老的fp指针 385 | // ADD sp, sp, #4 -- 回收空间 386 | // MOV pc, lr -- 指令跳转 387 | // lr寄存器的空间的回收在gen_ir_call中进行 388 | sprintf(msg, "\tMOV r0, %s\n\tADD sp, sp, #%d\n\tLDR fp, [sp, #0]\n\tADD sp, sp, #4\n\tMOV pc, lr\n", regName[x], stackSize); // stackSize空间传递未完善 389 | } 390 | else { 391 | // 常数的输出 --感觉还是有错的 392 | // MOV r0, #constVal 393 | // ADD sp, sp, #stacksize 394 | // LDR fp, [sp, #0] 395 | // ADD sp, sp, #4 396 | // MOV pc, lr 397 | sprintf(msg, "\tmov r0, #%d\n\tADD sp, sp, #%d\n\tLDR fp, [sp, #0]\n\tADD sp, sp, #4\n\tMOV pc, lr\n", op->u.val, stackSize); 398 | } 399 | return new_asmCodeList(msg); 400 | } 401 | 402 | // PARAM x ok 403 | asmCodeList gen_ir_params(InterCode ir) 404 | { 405 | char* msg = malloc(64); 406 | Var_t* param = malloc(sizeof(Var_t)); 407 | param->name = malloc(20); // 注意在变量很大的情况下可能会超出-要改进 408 | sprintf(param->name, "v%d",ir->u.op->u.var_no); // 应该是参数也是按变量来的 409 | spOffset -= 4; // 应该就是对fp的偏移才对 410 | param->offset = spOffset; 411 | addVar(param); 412 | 413 | // 对于前4个参数 存入a0~a3寄存器中 - 这里就是将寄存器里的参数放到本函数栈上 - 所以是STR 414 | if(curParam < 4){ 415 | sprintf(msg, "\tSTR r%d, [fp, #%d]\n", curParam, param->offset); // 存储r0-r3-并且优先处理寄存器上参数 416 | // STR r0-r3, [fp, #offset] 417 | } 418 | // 对于其他参数 传递是放到栈上 - 这里就是从栈上拿出来放到寄存器上 - 再放回到本函数栈上 419 | else { 420 | sprintf(msg, "\tLDR r0, [fp, #%d]\n\tSTR r0, [fp, #%d]\n", (curParam-2)*4, param->offset); 421 | // LDR r0, [fp, #从fp找参数的偏移] 422 | // STR r0, [fp, #到本栈变量区的偏移] 423 | } 424 | asmCodeList result = new_asmCodeList(msg); 425 | ++curParam; 426 | return result; 427 | } 428 | 429 | // 可能对应的是 IR_GET_ADDR ? 430 | asmCodeList gen_ir_address(InterCode ir) 431 | { 432 | Operand leftOp = ir->u.assign.left; 433 | Operand rightOp = ir->u.assign.right; 434 | Var_t *arrayHead = NULL; 435 | if(rightOp->kind == OP_TEMP) { 436 | char *arrayName = malloc(32); 437 | memset(arrayName, 0, sizeof(arrayName)); 438 | sprintf(arrayName, "t%d", rightOp->u.var_no); 439 | arrayHead = findVar(arrayName); 440 | } else if(rightOp->kind == OP_VARIABLE) { 441 | char *arrayName = malloc(32); 442 | memset(arrayName, 0, sizeof(arrayName)); 443 | sprintf(arrayName, "v%d", rightOp->u.var_no); 444 | arrayHead = findVar(arrayName); 445 | } 446 | if (arrayHead == NULL){ 447 | exit(-1); 448 | } 449 | int x = getreg(leftOp); 450 | char msg = malloc(64); 451 | memset(msg, 0, 64); 452 | sprintf(msg, "\tLDR %s, [fp, #%d]\n",regName(x),arrayHead->offset); 453 | asmCodeList swregCode = swReg(x); 454 | asmCodeList result = asm_join(new_asmCodeList(msg), swregCode); 455 | return result/ 456 | } 457 | 458 | // 删除函数变量表 ok 459 | void delVars(){ 460 | Var_t *ptr = varList; 461 | while(ptr != NULL) { 462 | varList = varList->next; 463 | free(ptr); 464 | ptr = varList; 465 | } 466 | } 467 | 468 | // 添加到函数变量表 ok 469 | void addVar(Var_t * var) 470 | { 471 | if(var==NULL) 472 | exit(-1); 473 | var->next = NULL; 474 | if(var_tail == NULL){ 475 | varList = var; 476 | } else { 477 | Var_t *ptr = varList; 478 | while(ptr->next != NULL) 479 | ptr = ptr->next; 480 | ptr->next = var; 481 | } 482 | } 483 | 484 | // 在Var_t中遍历查找相同的名字-返回对应的变量指针 ok 485 | Var_t* findVar(char* name) { 486 | Var_t *ptr = varList; 487 | while(ptr != NULL){ 488 | if(strcmp(ptr->name, name)==0) { 489 | break; 490 | } else{ 491 | ptr = ptr->next; 492 | } 493 | } 494 | return ptr; 495 | } 496 | 497 | // 初始化寄存器 ok 498 | void initRegs(){ 499 | int i = 0; 500 | for(i = 0; i < 16;i++) // 一共16个寄存器 501 | { 502 | regs[i].name = regName[i]; 503 | regs[i].var = NULL; 504 | } 505 | } 506 | 507 | asmCodeList gen_ir_plus(InterCode ir, char* op_type) 508 | { 509 | int reg_left = getreg(ir->u.binop.result); 510 | if(isConst(ir->u.binop.op1) && isConst(ir->u.binop.op2)) 511 | { 512 | char* msg = (char*)malloc(64); 513 | sprintf(msg, "\t%s r%d, #%d, #%d", op_type, reg_left, opVal(ir->u.binop.op1), opVal(ir->u.binop.op2)); 514 | return new_asmCodeList(msg); 515 | } 516 | else if(isConst(ir->u.binop.op1)) 517 | { 518 | int reg_op2 = getreg(ir->u.binop.op2); 519 | asmCodeList load_reg_op2 = load_to_reg(ir->u.binop.op2, reg_op2); 520 | char* msg = (char*)malloc(64); 521 | sprintf(msg, "\t%s r%d, #%d, r%d", op_type, reg_left, opVal(ir->u.binop.op1), reg_op2); 522 | return asm_join(load_reg_op2, new_asmCodeList(msg)); 523 | } 524 | else if(isConst(ir->u.binop.op2)) 525 | { 526 | int reg_op1 = getreg(ir->u.binop.op1); 527 | asmCodeList load_reg_op1 = load_to_reg(ir->u.binop.op1, reg_op1); 528 | char* msg = (char*)malloc(64); 529 | sprintf(msg, "\t%s r%d, r%d, #%d", op_type, reg_left, reg_op1, opVal(ir->u.binop.op2)); 530 | return asm_join(load_reg_op1, new_asmCodeList(msg)); 531 | } 532 | else 533 | { 534 | int reg_op1 = getreg(ir->u.binop.op1); 535 | int reg_op2 = getreg(ir->u.binop.op2); 536 | asmCodeList load_reg_op1 = load_to_reg(ir->u.binop.op1, reg_op1); 537 | asmCodeList load_reg_op2 = load_to_reg(ir->u.binop.op2, reg_op2); 538 | char* msg = (char*)malloc(64); 539 | sprintf(msg, "\t%s r%d, r%d, r%d", op_type, reg_left, reg_op1, reg_op2); 540 | asmCodeList calc_value = new_asmCodeList(msg); 541 | return asm_join(load_reg_op1, asm_join(load_reg_op2, calc_value)); 542 | } 543 | } 544 | 545 | asmCodeList gen_ir_goto(InterCode ir) 546 | { 547 | char* msg = (char*)malloc(64); 548 | sprintf(msg, "\tB label%d", ir->u.op->u.label_no); 549 | return new_asmCodeList(msg); 550 | } 551 | 552 | asmCodeList gen_ir_ifgoto(InterCode ir) 553 | { 554 | int label_id = ir->u.if_goto.z->u.label_no; 555 | char* relop = ir->u.if_goto.relop; 556 | char* cmpmsg = (char*)malloc(64); 557 | char* msg = (char*)malloc(64); 558 | memset(cmpmsg, 0, sizeof(cmpmsg)); 559 | memset(msg, 0, sizeof(msg)); 560 | char* code_op; 561 | if(!strcmp(relop, ">")) 562 | { 563 | code_op = "bgt"; 564 | } 565 | else if(!strcmp(relop, ">=")) 566 | { 567 | code_op = "bge"; 568 | } 569 | else if(!strcmp(relop, "<")) 570 | { 571 | code_op = "blt"; 572 | } 573 | else if(!strcmp(relop, "<=")) 574 | { 575 | code_op = "ble"; 576 | } 577 | else if(!strcmp(relop, "==")) 578 | { 579 | code_op = "beq"; 580 | } 581 | else if(!strcmp(relop, "!=")) 582 | { 583 | code_op = "bne"; 584 | } 585 | 586 | if(isConst(ir->u.if_goto.x) && isConst(ir->u.if_goto.y)) 587 | { 588 | sprintf(cmpmsg, "\tcmp #%d, #%d", opVal(ir->u.if_goto.x), opVal(ir->u.if_goto.y)); 589 | sprintf(msg, "\t%s label%d", code_op, label_id); 590 | return asm_join(new_asmCodeList(cmpmsg), new_asmCodeList(msg)); 591 | } 592 | else if(isConst(ir->u.if_goto.x)) 593 | { 594 | int reg_y = getreg(ir->u.if_goto.y); 595 | asmCodeList load_reg_y = load_to_reg(ir->u.if_goto.y, reg_y); 596 | sprintf(cmpmsg, "\tcmp #%d, r%d", opVal(ir->u.if_goto.x), reg_y); 597 | sprintf(msg, "\t%s label%d", code_op, label_id); 598 | return asm_join(new_asmCodeList(cmpmsg), new_asmCodeList(msg)); 599 | } 600 | else if(isConst(ir->u.if_goto.y)) 601 | { 602 | int reg_x = getreg(ir->u.if_goto.x); 603 | asmCodeList load_reg_x = load_to_reg(ir->u.if_goto.x, reg_x); 604 | sprintf(cmpmsg, "\tcmp r%d, #%d", reg_x, opVal(ir->u.if_goto.y)); 605 | sprintf(msg, "\t%s label%d", code_op, label_id); 606 | return asm_join(new_asmCodeList(cmpmsg), new_asmCodeList(msg)); 607 | } 608 | else 609 | { 610 | int reg_x = getreg(ir->u.if_goto.x); 611 | int reg_y = getreg(ir->u.if_goto.y); 612 | asmCodeList load_reg_x = load_to_reg(ir->u.if_goto.x, reg_x); 613 | asmCodeList load_reg_y = load_to_reg(ir->u.if_goto.y, reg_y); 614 | sprintf(cmpmsg, "\tcmp r%d, r%d", reg_x, reg_y); 615 | sprintf(msg, "\t%s label%d", code_op, label_id); 616 | return asm_join(new_asmCodeList(cmpmsg), new_asmCodeList(msg)); 617 | } 618 | } 619 | 620 | 621 | Register_ regs[16]; 622 | Var_t *varList = NULL; 623 | int curReg = 0; 624 | int spOffset = 0; 625 | int curParam = 0; 626 | int curArg = 0; 627 | int stackSize = 100; //栈的变量区大小 628 | 629 | char* regName[] = { 630 | "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","fp","r12", 631 | "sp","lr", "pc" 632 | } -------------------------------------------------------------------------------- /codegen.h: -------------------------------------------------------------------------------- 1 | #ifndef CODEGEN 2 | #define CODEGEN 3 | 4 | #include "intercode.h" 5 | 6 | typedef struct asmCodeList_ *asmCodeList; 7 | 8 | struct asmCodeList_{ 9 | char* code; 10 | asmCodeList prev, next; 11 | }; 12 | 13 | asmCodeList new_asmCodeList(char* code); 14 | // 合并两个CodeList 15 | asmCodeList asm_join(asmCodeList head, asmCodeList body); 16 | void codegen(CodeList cl); 17 | asmCodeList gen_header(); 18 | asmCodeList gen_ir_func(InterCode ir); 19 | int getreg(Operand op); 20 | asmCodeList load_to_reg(Operand op, int regid); 21 | asmCodeList gen_ir_label(InterCode ir); 22 | asmCodeList gen_ir_assign(InterCode ir); 23 | asmCodeList gen_ir_plus(InterCode ir, char* op_type); 24 | asmCodeList gen_ir_goto(InterCode ir); 25 | asmCodeList gen_ir_ifgoto(InterCode ir); 26 | 27 | asmCodeList gen_ir_call(InterCode ir); 28 | asmCodeList gen_ir_func(InterCode ir); 29 | asmCodeList gen_ir_arg(InterCode ir); 30 | asmCodeList gen_ir_params(InterCode ir); 31 | asmCodeList gen_ir_return(InterCode ir); 32 | asmCodeList gen_ir_dec(InterCode ir); 33 | asmCodeList gen_ir_address(InterCode ir); 34 | 35 | 36 | void initRegs(); 37 | asmCodeList swReg(int index); 38 | asmCodeList lwReg(int index, Var_t *var); 39 | void delVars(); 40 | void addVars(Var_t *var); 41 | Var_t* findVar(char *name); 42 | 43 | // 应该是一个函数内部的变量链表 应该是所有变量都存储到栈空间 44 | typedef struct Var_t { 45 | char *name; // 变量名字 46 | int reg; // 应该是对应的寄存器的序号 47 | int offset; // 应该是相对于"fp"的偏移量 48 | struct Var_t *next; 49 | } Var_t; 50 | 51 | typedef struct Register_ { 52 | char *name; // 寄存器的名字 53 | Var_t *var; // 应该是寄存器存储的变量的名字 54 | } Register_; 55 | 56 | 57 | extern Register_ regs[]; // 寄存器数组 58 | extern char* regName[]; // 寄存器名字映射数组-目前有名字的就 r11-fp, r13-sp, r14-lr, r15-pc 59 | extern Var_t *varList; // 函数中的变量链表 60 | extern int curReg; // 61 | extern int spOffset; // 还不太确定-应该是相对fp的偏移-可能名字有问题 62 | extern int curParam; // 63 | extern int curArg; // 64 | 65 | #endif 66 | 67 | /* 68 | 栈管理 69 | 参数传入 70 | 前4个参数, 存入r0到r3寄存器中。 71 | 对于其他参数, 按顺序存入栈中, 在函数中, 利用fp拿出实参存入栈中作为临时变量。 72 | */ -------------------------------------------------------------------------------- /intercode.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERCODE 2 | #define INTERCODE 3 | /* 4 | 中间代码定义如下 5 | LABEL x : 定义标号x 6 | FUNCTION f: 定义函数f 7 | x := y 赋值操作 8 | x := y + z 加法操作 9 | x := y - z 减法操作 10 | x := y * z 乘法操作 11 | x := y / z 除法操作 12 | x := y % z 模除操作 13 | x := &y 取y的地址赋给x 14 | x := *y 取以y值为地址的内存单元的内容赋给x 15 | *x := y 取y值赋给以x值为地址的内存单元 16 | GOTO x 无条件跳转至标号x 17 | IF x [relop] y GOTO z 如果x与y满足[relop]关系则跳转至标号z 18 | RETURN x 退出当前函数并返回x值 19 | DEC x [size] 内存空间申请, 大小为4的倍数 20 | ARG x 传实参 21 | x := CALL f 调用函数, 并将其返回值赋给x 22 | PARAM x 函数参数申明 23 | READ x 从控制台读取x的值 // 目前不用 24 | WRITE x 从控制台打印x的值 // 目前不用 25 | */ 26 | #include "node.h" 27 | #include "list.h" 28 | 29 | 30 | 31 | typedef struct ArgList_* ArgList; // 函数实参链表 32 | typedef struct Variable_* Variable; // 变量 33 | typedef struct Operand_* Operand; // 操作数 34 | typedef struct InterCode_* InterCode; // 中间代码节点 35 | typedef struct CodeList_* CodeList; // 中间代码链表 36 | 37 | 38 | typedef struct Label_No_* Label_No; // 记录Label的链表 与多余标签删除优化有关 39 | 40 | struct Operand_{ 41 | enum{ 42 | OP_VARIABLE, // 变量 43 | OP_CONSTANT, // 常量 44 | OP_ADDRESS, // 地址 45 | OP_LABEL, // 标签 46 | OP_ARR_STRU, // 数组 结构体-不用 47 | OP_TEMP // 暂时变量 48 | } kind; 49 | union{ 50 | int var_no; // 变量序号 51 | int label_no; // 代码label序号 52 | int val; // 用于常数 53 | int temp_no; // 暂时变量序号 主要这些的作用就是作为唯一标示--每一个变量都是不同名的--从而解决作用域问题 54 | }u; 55 | }; 56 | 57 | struct InterCode_{ 58 | enum{ 59 | IR_ASSIGN, // x := y 60 | IR_LABEL, // LABEL x : 61 | IR_PLUS, // x := y+z 62 | IR_MINUS, // x := y-z 63 | IR_MUL, // x := y*z 64 | IR_DIV, // x := y/z 65 | IR_MOD, // x : = y%z 66 | IR_FUNC, // FUNCTION f : 67 | IR_GOTO, // GOTO x 68 | IR_IFGOTO, // IF x [relop] y GOTO z 69 | IR_RET, // x = *y 70 | IR_DEC, // DEC x [size] 内存空间申请-大小为4的倍数 用于数组 71 | IR_ARG, // ARG x 72 | IR_CALL, // x := CALL f 73 | IR_PARAM, // PARAM x 74 | IR_READ, // 不用 75 | IR_WRITE, // 不用 76 | IR_RETURN, // RETURN x 77 | IR_CHANGE_ADDR, // *x := y 取y值以赋给x值为地址的内存单元 78 | IR_GET_ADDR, // x := &y 取y的地址赋给x // 名字可能起的不是很好 79 | IR_ENDFUNC // 函数声明结束 80 | } kind; 81 | union{ 82 | Operand op; 83 | char *func; 84 | struct{Operand right, left; } assign; // 赋值 x := y 85 | struct{Operand result, op1, op2; } binop; // 双目 x := y + z 86 | struct{Operand x, y, z; char *relop;} if_goto; // IF x [relop] y GOTO z 87 | struct{Operand x; int size;} dec; // DEC x [size] 88 | struct{Operand result; char *func;} call; // x := CALL f 89 | }u; 90 | }; 91 | // 中间代码链表 92 | struct CodeList_{ 93 | InterCode code; 94 | CodeList prev, next; 95 | }; 96 | 97 | // 函数*实参*链表 98 | struct ArgList_{ 99 | Operand args; 100 | ArgList next; 101 | }; 102 | 103 | // 变量链表 104 | struct Variable_{ 105 | char* name; 106 | Operand op; 107 | Variable next; 108 | }; 109 | 110 | // 记录Label的链表 与多余标签删除优化有关 111 | struct Label_No_ 112 | { 113 | int no; 114 | Label_No next; 115 | }; 116 | 117 | 118 | int var_num,label_num,temp_num; // 标号表示唯一标识符 119 | 120 | 121 | Operand new_constant(); 122 | Operand new_temp(); 123 | Operand new_label(); 124 | Operand new_fparam(); 125 | Operand op_from_var(char* var); 126 | 127 | InterCode new_InterCode(int kind); 128 | CodeList new_CodeList(InterCode code); 129 | // 合并两个CodeList 130 | CodeList join(CodeList head, CodeList body); 131 | CodeList translate_Operand(Operand op,int IR_KIND); // Operand 132 | 133 | void tranlate_InterCode(treeNode*root, char*file); 134 | void start_translate(treeNode* root); // 递归翻译 135 | void insert_code(CodeList code); // 插入到总代码中 136 | 137 | char *Operand_toString(Operand op); 138 | char* InterCode_toString(InterCode code); 139 | 140 | CodeList translate_Exp(treeNode *Exp, Operand place); 141 | CodeList translate_AddExp(treeNode *AddExp, Operand place); 142 | CodeList translate_MulExp(treeNode *MulExp, Operand place); 143 | CodeList translate_Number(treeNode *Number, Operand place); 144 | CodeList translate_PrimaryExp(treeNode *PrimaryExp,Operand place) ; 145 | CodeList translate_UnaryExp(treeNode *UnaryExp, Operand place); 146 | CodeList translate_Stmt(treeNode* Stmt, Operand label_1, Operand label_3); 147 | CodeList translate_Block(treeNode *Block, Operand label_1, Operand label_3, int isFuncBlock); 148 | CodeList translate_BlockItem_rep(treeNode *BlockItem_rep, Operand label_1, Operand label_3); 149 | CodeList translate_BlockItem(treeNode *BlockItem, Operand label_1, Operand label_3); 150 | CodeList translate_LVal(treeNode *LVal, Operand place, int isLeft); 151 | //CodeList translate_Exp_rep(treeNode *Exp_rep); 152 | CodeList translate_FuncDef(treeNode *FuncDef); 153 | CodeList translate_FuncRParams(treeNode *FuncRParams, ArgList *arg_list); 154 | CodeList translate_comExp_rep(treeNode *comExp_rep, ArgList *arg_list); 155 | CodeList translate_Exp_rep(treeNode *Exp_rep, Operand place, int* index); 156 | InterCode new_InterCode(int kind); 157 | CodeList new_CodeList(InterCode code); 158 | CodeList join(CodeList head, CodeList body); 159 | CodeList translate_Operand(Operand op, int IR_KIND); 160 | void insert_code(CodeList code); 161 | Operand new_constant(int val); 162 | Operand new_temp(); 163 | Operand new_label(); 164 | Operand new_var(); 165 | Operand op_from_var(char* var); 166 | char *Operand_toString(Operand op); 167 | char* InterCode_toString(InterCode code); 168 | CodeList translate_InterCode(treeNode* root, char* file); 169 | void start_translate(treeNode* root); 170 | CodeList translate_CompUnit(treeNode *CompUnit); 171 | CodeList translate_Decl(treeNode *Decl); 172 | CodeList translate_VarDecl(treeNode *VarDecl); 173 | CodeList translate_VarDef(treeNode *VarDef); 174 | CodeList translate_ConstDef(treeNode *ConstDef); 175 | CodeList translate_ConstInitVal(treeNode *ConstInitVal, Operand place); 176 | CodeList translate_InitVal(treeNode *InitVal,Operand place, int arrayDim, int* arrayDimList); 177 | treeNode* translate_InitVal_array(treeNode *r, Operand place, int arrayDim, int* arrayDimList, int index, int* numCount, int numCountLim, CodeList* code); 178 | CodeList translate_LOrExp(treeNode *LOrExp, Operand label_true, Operand label_false); 179 | CodeList translate_LAndExp(treeNode *LAndExp, Operand label_true, Operand label_false); 180 | CodeList translate_EqExp_Calc(treeNode *EqExp, Operand place); 181 | CodeList translate_RelExp_Calc(treeNode *RelExp, Operand place); 182 | CodeList translate_EqExp(treeNode *EqExp, Operand label_true, Operand label_false); 183 | CodeList translate_RelExp(treeNode *RelExp, Operand label_true, Operand label_false); 184 | CodeList translate_Cond(treeNode *Condition, Operand label_true, Operand label_false); 185 | CodeList translate_ConstExp(treeNode *ConstExp, Operand place); 186 | CodeList translate_ComVarDef_rep(treeNode *ComVarDef_rep); 187 | CodeList translate_ComConstDef_rep(treeNode *ComConstDef_rep); 188 | CodeList translate_ConstDecl(treeNode *Decl); 189 | void printCodeList(CodeList tmp); 190 | 191 | void deleteCode(CodeList c); 192 | void calcConst(); 193 | 194 | 195 | CodeList code_head, code_tail; // 中间代码链表 196 | Variable var_head,var_tail; // 变量链表 197 | 198 | #endif -------------------------------------------------------------------------------- /list.c: -------------------------------------------------------------------------------- 1 | // List functions 2 | /* Adapted from: Yu Zhang (yuzhang@ustc.edu.cn) */ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "list.h" 8 | 9 | static ListItr glistitr = NULL; 10 | 11 | // new an error or a warn message 12 | listNode 13 | newlistNode(void *item) 14 | { 15 | listNode new; 16 | NEW0(new); 17 | new->item = item; 18 | return new; 19 | } 20 | 21 | List 22 | newList() 23 | { 24 | List new; 25 | NEW0(new); 26 | listNode newNode; 27 | NEW0(newNode); 28 | new -> first = newNode; 29 | new -> last = newNode; 30 | return new; 31 | } 32 | 33 | /** 34 | * Links element item as first element of the list 35 | */ 36 | static void 37 | linkFirst(List list, void *item) 38 | { 39 | listNode first = list->first; 40 | listNode firstNext = first->next; 41 | listNode newnode = newlistNode(item); 42 | newnode->next = firstNext; 43 | newnode->prev = first; 44 | newnode->list = list; 45 | if ( firstNext == NULL ) 46 | list->last = newnode; 47 | else 48 | firstNext->prev = newnode; 49 | first -> next = newnode; 50 | list->size ++; 51 | } 52 | 53 | /** 54 | * Links element item as first element of the list 55 | */ 56 | static void 57 | linkLast(List list, void *item) 58 | { 59 | listNode last = list->last; 60 | listNode newnode = newlistNode(item); 61 | newnode->prev = last; 62 | newnode->next = NULL; 63 | newnode->list = list; 64 | last->next = newnode; 65 | list->last = newnode; 66 | list->size ++; 67 | } 68 | 69 | /** 70 | * Inserts element item before non-NULL & non-default-first node succ 71 | */ 72 | static void 73 | linkBefore(List list, void *item, listNode succ) 74 | { 75 | assert(succ != NULL); 76 | listNode pred = succ->prev; 77 | listNode newnode = newlistNode(item); 78 | newnode->next = succ; 79 | newnode->prev = succ->prev; 80 | newnode->list = list; 81 | succ->prev = newnode; 82 | pred->next = newnode; 83 | list->size ++; 84 | } 85 | 86 | /** 87 | * Unlinks non-NULL & non-default-first node 88 | */ 89 | static void * 90 | unlink(List list, listNode node) 91 | { 92 | assert(node != NULL); 93 | listNode prev, next; 94 | void *item; 95 | 96 | item = node->item; 97 | prev = node->prev; 98 | next = node->next; 99 | if (prev == NULL) 100 | list->first = next; 101 | else { 102 | prev->next = next; 103 | node->prev = NULL; 104 | } 105 | if (next == NULL) 106 | list->last = prev; 107 | else { 108 | next->prev = prev; 109 | node->next = NULL; 110 | } 111 | 112 | node->item = NULL; 113 | free(node); 114 | list->size--; 115 | return item; 116 | } 117 | 118 | /** 119 | * Returns the first element in this list 120 | */ 121 | void * 122 | getFirst(List list) 123 | { 124 | listNode first = list->first->next; 125 | if ( first == NULL ) { 126 | printf("The list is empty!\n"); 127 | exit(-1); 128 | } 129 | return first->item; 130 | } 131 | 132 | /** 133 | * Returns the last element in this list 134 | */ 135 | void * 136 | getLast(List list) 137 | { 138 | listNode last = list->last; 139 | if ( last == NULL || list->first->next == NULL) { 140 | printf("The list is empty!\n"); 141 | exit(-1); 142 | } 143 | return last->item; 144 | } 145 | 146 | /** 147 | * Removes and returns the first element from this list 148 | */ 149 | void * 150 | removeFirst(List list) 151 | { 152 | listNode first = list->first->next; 153 | if ( first == NULL ) { 154 | printf("The list is empty!\n"); 155 | exit(-1); 156 | } 157 | return unlink(list, first); 158 | } 159 | 160 | /** 161 | * Removes and returns the last element from this list 162 | */ 163 | void * 164 | removeLast(List list) 165 | { 166 | listNode last = list->last; 167 | if ( last == NULL || list->first->next == NULL ) { 168 | printf("The list is empty!\n"); 169 | exit(-1); 170 | } 171 | return unlink(list, last); 172 | } 173 | 174 | /** 175 | * Inserts the specified element at the beginning of the list 176 | */ 177 | void 178 | addFirst(List list, void * item) 179 | { 180 | linkFirst(list, item); 181 | } 182 | 183 | /** 184 | * Inserts the specified element to the end of the list 185 | */ 186 | void 187 | addLast(List list, void * item) 188 | { 189 | linkLast(list, item); 190 | } 191 | 192 | /** 193 | * Returns the index of the first occurence of the specified 194 | * element in the list, or -1 if the list does not contain 195 | * the element. 196 | */ 197 | int 198 | indexof(List list, void *item) 199 | { 200 | int index = 0; 201 | listNode node = list->first->next; 202 | while (node != NULL) { 203 | if ( (node->item == item) ) 204 | return index; 205 | index ++; 206 | node = node->next; 207 | } 208 | return -1; 209 | } 210 | 211 | /** 212 | * Returns TRUE if the list contains the specified element. 213 | */ 214 | bool 215 | listcontains(List list, void *item) 216 | { 217 | return indexof(list, item) != -1; 218 | } 219 | 220 | /** 221 | * Returns the number of elements in the list 222 | */ 223 | int 224 | listsize(List list) 225 | { 226 | return list->size; 227 | } 228 | 229 | /** 230 | * Appends the specified element to the end of the list 231 | */ 232 | bool 233 | listaddItem(List list, void * item) 234 | { 235 | linkLast(list, item); 236 | return TRUE; 237 | } 238 | 239 | /** 240 | * Removes the first occurrence of the specified element from 241 | * the list, if it is present. 242 | */ 243 | bool 244 | listremoveItem(List list, void *item) 245 | { 246 | listNode node = list->first->next; 247 | while(node!=NULL) { 248 | if (node->item == item) { 249 | unlink(list, node); 250 | return TRUE; 251 | } 252 | node = node->next; 253 | } 254 | return FALSE; 255 | } 256 | 257 | /** 258 | * Removes all of the elements from the list 259 | */ 260 | void 261 | listclear(List list, void destroyItem()) 262 | { 263 | listNode node = list->first->next; 264 | while (node != NULL) { 265 | listNode next = node->next; 266 | if (destroyItem != NULL) 267 | destroyItem(&node->item); 268 | node->item = NULL; 269 | free(node); 270 | node = next; 271 | } 272 | list->size = 0; 273 | } 274 | 275 | /** 276 | * Returns the node at the specified element index 277 | */ 278 | listNode 279 | listnode(List list, int index) 280 | { 281 | listNode node; 282 | int i; 283 | if ( index < (list->size >> 1)) { 284 | node = list->first->next; 285 | for ( i = 0; i < index; i++) 286 | node = node->next; 287 | return node; 288 | } else { 289 | node = list->last; 290 | for ( i = list->size - 1; i > index; i--) 291 | node = node->prev; 292 | return node; 293 | } 294 | } 295 | 296 | /** 297 | * Returns the element at the specified position in the list 298 | */ 299 | void * 300 | listget(List list, int index) 301 | { 302 | listNode node = listnode(list, index); 303 | return node==NULL ? NULL : node->item; 304 | } 305 | 306 | /** 307 | * Replaces the element at the specified position in the list 308 | */ 309 | void * 310 | listset(List list, int index, void *item) 311 | { 312 | listNode node = listnode(list, index); 313 | if ( node==NULL ) { 314 | printf("Index %d is out of the bound!\n", index); 315 | exit(-1); 316 | } 317 | void *oldval = node->item; 318 | node->item = item; 319 | return oldval; 320 | } 321 | 322 | /** 323 | * Inserts the specified element at the specified position in the 324 | * list 325 | */ 326 | void 327 | listadd(List list, int index, void *item) 328 | { 329 | if ( index == list->size ) { 330 | linkLast(list, item); 331 | return; 332 | } 333 | listNode node = listnode(list, index); 334 | if ( node==NULL ) { 335 | printf("Index %d is out of the bound!\n", index); 336 | exit(-1); 337 | } 338 | linkBefore(list, item, node); 339 | } 340 | 341 | /** 342 | * Removes the element at the specified position in the list 343 | */ 344 | void * 345 | listremove(List list, int index) 346 | { 347 | listNode node = listnode(list, index); 348 | if ( node==NULL ) { 349 | printf("Index %d is out of the bound!\n", index); 350 | exit(-1); 351 | } 352 | return unlink(list, node); 353 | } 354 | 355 | /** 356 | * Destroys the list 357 | */ 358 | void 359 | destroyList(List *list, void destroyItem()) 360 | { 361 | listclear(*list, destroyItem); 362 | free((*list)->first); 363 | free(*list); 364 | *list = NULL; 365 | } 366 | /************************************************************* 367 | * Functions for iterating elements 368 | ************************************************************/ 369 | 370 | /** 371 | * Creates an iterator 372 | */ 373 | ListItr 374 | newListItr(List list, int index) 375 | { 376 | ListItr new; 377 | NEW0(new); 378 | new->list = list; 379 | new->next = listnode(list, index); 380 | new->nextIndex = index; 381 | return new; 382 | } 383 | 384 | /** 385 | * Gets the singleton global List iterator 386 | */ 387 | ListItr 388 | getGListItr(List list, int index) 389 | { 390 | if ( glistitr == NULL ) 391 | NEW0(glistitr); 392 | glistitr->list = list; 393 | glistitr->next = listnode(list, index); 394 | glistitr->nextIndex = index; 395 | return glistitr; 396 | } 397 | 398 | /** 399 | * Resets the list iterator 400 | */ 401 | void 402 | resetListItr(ListItr itr, List list, int index) 403 | { 404 | assert(itr != NULL); 405 | itr->list = list; 406 | itr->next = listnode(list, index); 407 | itr->nextIndex = index; 408 | } 409 | 410 | /** 411 | * Returns TRUE if there is next element 412 | */ 413 | bool 414 | hasNext(ListItr itr) 415 | { 416 | return itr->nextIndex < itr->list->size; 417 | } 418 | 419 | /** 420 | * Advance and returns the next element 421 | */ 422 | void * 423 | nextItem(ListItr itr) 424 | { 425 | if ( !hasNext(itr) ) { 426 | printf("Already reach the end of the list.\n"); 427 | return NULL; 428 | } 429 | itr->lastRet = itr->next; 430 | itr->next = itr->next->next; 431 | itr->nextIndex ++; 432 | return itr->lastRet->item; 433 | } 434 | 435 | /** 436 | * Returns TRUE if there is previous element 437 | */ 438 | bool 439 | hasPrevious(ListItr itr) 440 | { 441 | return itr->nextIndex > 0; 442 | } 443 | 444 | /** 445 | * Backward and returns the previous element 446 | */ 447 | void * 448 | prevItem(ListItr itr) 449 | { 450 | if ( !hasPrevious(itr) ) { 451 | printf("Already reach the beginning of the list.\n"); 452 | return NULL; 453 | } 454 | if ( itr->next == NULL ) 455 | itr->next = itr->list->last; 456 | else 457 | itr->next = itr->next->prev; 458 | 459 | itr->lastRet = itr->next; 460 | itr->nextIndex --; 461 | return itr->lastRet->item; 462 | } 463 | 464 | /** 465 | * Destroys the iterator 466 | */ 467 | void 468 | destroyListItr(ListItr *itr) 469 | { 470 | free(*itr); 471 | *itr = NULL; 472 | } 473 | 474 | /** 475 | * Return next iterator 476 | */ 477 | ListItr nextItr (ListItr itr) 478 | { 479 | if ( !hasNext(itr) ) { 480 | printf("Already reach the end of the list.\n"); 481 | return NULL; 482 | } 483 | ListItr newItr = newListItr(itr->list, itr->nextIndex+1); 484 | return newItr; 485 | } 486 | 487 | 488 | /** 489 | * Return previous iterator 490 | */ 491 | ListItr prevItr (ListItr itr) 492 | { 493 | if ( !hasPrevious(itr) ) { 494 | printf("Already reach the beginning of the list.\n"); 495 | return NULL; 496 | } 497 | ListItr newItr = newListItr(itr->list, itr->nextIndex-11); 498 | return newItr; 499 | } 500 | 501 | 502 | /** 503 | * destroyItem example. 504 | */ 505 | void destroyItem(void* item) { 506 | free(item); 507 | } 508 | 509 | 510 | /** 511 | * iterList example. 512 | */ 513 | void iterList (ListItr itr, void hook()) 514 | { 515 | while(hasNext(itr)) 516 | { 517 | // what you want to do 518 | void* item = nextItem(itr); //会自动往下走的 519 | hook(item); 520 | } 521 | } 522 | 523 | 524 | void removeNode(listNode node) 525 | { 526 | // 仅适用于prev一定存在的情况 527 | listNode prev = node -> prev; 528 | listNode next = node -> next; 529 | prev -> next = next; 530 | if(next != NULL) next -> prev = prev; 531 | node -> item = NULL; 532 | node -> prev = NULL; 533 | node -> next = NULL; 534 | ((List)(node -> list)) -> size --; 535 | free(node); 536 | } 537 | 538 | listNode getFirstNode(List list) 539 | { 540 | return list->first->next; 541 | } -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | // List function declaration 2 | /* Adapted from: Yu Zhang (yuzhang@ustc.edu.cn) */ 3 | #ifndef _UTIL_H_ 4 | #define _UTIL_H_ 5 | #define NEW(p) ((p) = malloc(sizeof *(p))) 6 | #define NEW0(p) memset(NEW(p), 0, sizeof *(p)) 7 | #define bool char 8 | #define TRUE 1 9 | #define FALSE 0 10 | 11 | typedef struct listnode{ 12 | void *item; // pointer to the item. 13 | void *next; // pointer to the next node 14 | void *prev; // pointer to the previous node 15 | void *list; 16 | } *listNode; 17 | 18 | typedef struct { 19 | int size; // number of nodes 20 | listNode first; // pointer to the first node 21 | listNode last; // pointer to the last node 22 | } *List; 23 | 24 | listNode newlistNode (void *item); // 新建一个链表节点 25 | List newList (); // 新建一个链表 26 | void *getFirst (List list); // 获取链表第一个元素 27 | void *getLast (List list); // 返回链表中最后一个元素 28 | void *removeFirst (List list); // 删除并返回链表中第一个元素 29 | void *removeLast (List list); // 删除并返回链表中最后一个元素 30 | void addFirst (List list, void *item); // 添加元素到链表开始 31 | void addLast (List list, void *item); // 添加元素到链表结尾 32 | int indexof (List list, void *item); // 返回元素第一次出现的下标 33 | bool listcontains (List list, void *item); // 判断链表是否包含对应元素 34 | int listsize (List list); // 返回链表中元素个数 35 | bool listaddItem (List list, void *item); // 相应元素添加到链表 36 | bool listremoveItem (List list, void *item); // 链表中删除第一次出现的元素 37 | void listclear (List list, void (*destroyItem)()); // 删除链表中的所有元素 38 | listNode listnode (List list, int index); // 返回对应的下标中的节点 39 | void *listget (List list, int index); // 返回对应下标中的元素 40 | void *listset (List list, int index, void *item); // 替换对应下标中的元素 41 | void listadd (List list, int index, void *item); // 向链表中特定位置插入元素 42 | void *listremove (List list, int index); // 删除链表中的对应下标的元素 43 | void destroyList (List *list, void (*destroyItem)()); // 销毁链表 44 | 45 | void destroyItem(void* item); // destroyItem函数例子-实际上要看item结构 46 | 47 | // List Iterator 48 | typedef struct { 49 | List list; 50 | int nextIndex; 51 | listNode lastRet; 52 | listNode next; 53 | } *ListItr; 54 | 55 | ListItr newListItr (List list, int index); 56 | ListItr getGListItr (List list, int index); 57 | void resetListItr (ListItr itr, List list, int index); 58 | bool hasNext (ListItr itr); 59 | void *nextItem (ListItr itr); 60 | bool hasPrevious (ListItr itr); 61 | void *prevItem (ListItr itr); 62 | void destroyListItr (ListItr *itr); 63 | 64 | 65 | ListItr nextItr (ListItr itr); 66 | ListItr prevItr (ListItr itr); 67 | void iterList (ListItr itr, void hook()); 68 | 69 | void removeNode(listNode node); 70 | listNode getFirstNode(List list); 71 | 72 | 73 | #endif //!def(_UTIL_H_) 74 | -------------------------------------------------------------------------------- /node.c: -------------------------------------------------------------------------------- 1 | #include "node.h" 2 | extern int yylineno; 3 | #define NEW(p) ((p) = malloc(sizeof *(p))) 4 | #define NEW0(p) memset(NEW(p), 0, sizeof *(p)) 5 | 6 | 7 | /* new Node */ 8 | 9 | treeNode *newNodeOp(char* name) 10 | { 11 | treeNode *node; 12 | NEW0(node); 13 | //node->lineNo=yylineno; 14 | strcpy(node->name,name); 15 | node->child=NULL; 16 | node->next=NULL; 17 | node->father=NULL; 18 | node->lineNo = yylineno; 19 | return node; 20 | } 21 | 22 | treeNode* newNodeString(char *name,char *value) 23 | { 24 | treeNode *node; 25 | NEW0(node); 26 | //node->lineNo=yylineno; 27 | strcpy(node->name,name); 28 | strcpy(node->value,value); 29 | node->child=NULL; 30 | node->next=NULL; 31 | node->father=NULL; 32 | node->lineNo = yylineno; 33 | return node; 34 | } 35 | 36 | treeNode *newNodeInt(char* name, int int_val) 37 | { 38 | treeNode *node; 39 | NEW0(node); 40 | //node->lineNo=yylineno; 41 | strcpy(node->name,name); 42 | node->child=NULL; 43 | node->next=NULL; 44 | node->int_val=int_val; 45 | node->father=NULL; 46 | node->lineNo = yylineno; 47 | return node; 48 | } 49 | 50 | treeNode *newNodeError() { 51 | treeNode *node; 52 | NEW0(node); 53 | strcpy(node->name,"ERROR"); 54 | node->lineNo=yylineno; 55 | node->child=NULL; 56 | node->next=NULL; 57 | node->father=NULL; 58 | return node; 59 | } 60 | 61 | /*give father a child*/ 62 | void addChild(treeNode* parent,treeNode* child) 63 | { 64 | if(child == NULL) 65 | { 66 | parent->child = NULL; 67 | return; 68 | } 69 | if(parent != NULL && child != NULL) 70 | { 71 | child->next = parent->child; // add to head of children list 72 | parent->child = child; 73 | child->father = parent; 74 | parent->lineNo = child->lineNo; // update the row of father node 75 | } 76 | } 77 | 78 | 79 | /* print the syntax tree */ 80 | void printTree(treeNode* r,int count) 81 | { 82 | if(r==NULL)return; 83 | if(r->child==NULL) //token 84 | { 85 | int i=0; 86 | for(;i < count;i++) // retract 87 | { 88 | printf(" "); 89 | } 90 | //not all nodes need to print value 91 | if(strcmp(r->name,"TYPE")==0||strcmp(r->name,"INTCONST")==0||strcmp(r->name,"ID")==0) 92 | { 93 | if(strcmp(r->name,"INTCONST")==0) 94 | printf("%s: %d\n",r->name,r->int_val); 95 | else 96 | printf("%s: %s\n",r->name,r->value); 97 | } 98 | else 99 | { 100 | printf("%s\n",r->name); 101 | } 102 | } 103 | else //non-terminal 104 | { 105 | int i=0; 106 | for(;iname,r->lineNo); 111 | treeNode *p=r->child; 112 | //traverse the child nodes 113 | while(p!=NULL){ 114 | printTree(p,count+1); 115 | p=p->next; 116 | } 117 | } 118 | return; 119 | } -------------------------------------------------------------------------------- /node.h: -------------------------------------------------------------------------------- 1 | //syntax tree 2 | #ifndef _NODE_H 3 | #define _NODE_H 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct Node { 9 | int lineNo; 10 | char name[16]; 11 | char value[32]; 12 | int int_val; 13 | struct Node *child; 14 | struct Node *next; 15 | struct Node *father; // used in sdt parse 16 | }treeNode; 17 | treeNode *newNodeOp(char* name); 18 | treeNode *newNodeString(char* name, char* value); 19 | treeNode *newNodeInt(char* name, int int_val); 20 | treeNode *newNodeError(); 21 | void addChild(treeNode* parent, treeNode* child); 22 | void printTree(treeNode* r, int count); // debug syntax tree 23 | 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /symtable.c: -------------------------------------------------------------------------------- 1 | #include "node.h" 2 | #include "list.h" 3 | #include "vector.h" 4 | #include "symtable.h" 5 | #include 6 | #define HT_SIZE 233 7 | #define HT_SEED 32 8 | #define NEW(p) ((p) = malloc(sizeof *(p))) 9 | #define NEW0(p) memset(NEW(p), 0, sizeof *(p)) 10 | List funcTable[HT_SIZE], paraTable[HT_SIZE]; 11 | const char *RESERVE_WORDS[] = {(const char *)"int\0", (const char *)"void\0", (const char *)"NULL\0"}; 12 | int scope = 0, whileCnt = 0; 13 | vector scopeTable; 14 | int errorcnt = 0; 15 | 16 | void handleError(int no, int lineno) 17 | { 18 | errorcnt ++; 19 | printf("Error %d on Line %d: ", no, lineno); 20 | switch (no) 21 | { 22 | case 1: { printf("storage size of this variable isn't known. \n"); break; } 23 | case 2: { printf("division by zero. \n"); break; } 24 | case 3: { printf("function cannot be called in a constant expression. \n"); break;} 25 | case 4: { printf("size of array is negative. \n"); break; } 26 | case 5: { printf("excess elements in scalar initializer. \n"); break; } 27 | case 6: { printf("invalid initializer. \n"); break; } 28 | case 7: { printf("the variable has't been defined. \n"); break; } 29 | case 8: { printf("too many braces around scalar initializer. \n"); break; } 30 | case 9: { printf("const type variable is required here. \n"); break; } 31 | case 10: { printf("excess elements in scalar initializer. \n"); break; } 32 | case 11: { printf("an identifier can not be the same as reserve names. \n"); break; } 33 | case 12: { printf("repeated definition. \n"); break; } 34 | case 13: { printf("the continue/break statement is not in while loop. \n"); break; } 35 | case 14: { printf("NOT '!' operation can only appear in condition expressions. \n"); break; } 36 | case 15: { printf("the actual parameter type is different from the formal parameter type defined by the function. \n"); break; } 37 | case 16: { printf("function parameter type cannot be void. \n"); break; } 38 | case 17: { printf("the return type is different from the return type defined by the function. \n"); break; } 39 | case 18: { printf("when lvalue is passed as a function argument, the reference of the array variable is illegal. \n"); break; } 40 | case 19: { printf("lvalue subscript out of bounds. \n"); break; } 41 | case 20: { printf("lvalue passed as a function argument here should be an array/constarray. \n"); break; } 42 | case 21: { printf("lvalue in assignment statements can only be a non-array variable, or locate an array element. \n"); break; } 43 | case 22: { printf("too many function arguments. \n"); break; } 44 | case 23: { printf("too many function arguments. \n"); break; } 45 | case 24: { printf("the function has't been defined. \n"); break; } 46 | case 25: { printf("missing function arguments. \n"); break; } 47 | default: { printf("undefined error. \n"); break; } 48 | } 49 | } 50 | 51 | void printType(List type) 52 | { 53 | if (listsize(type) == 0) 54 | { 55 | printf("List is empty\n"); 56 | return; 57 | } 58 | int blanknum = 0, j; 59 | ListItr i = getGListItr(type, 0); 60 | while (hasNext(i)) 61 | { 62 | for (j = 0; j < blanknum; j++) 63 | printf(" "); 64 | Type tmp = nextItem(i); 65 | switch (tmp->kind) 66 | { 67 | case constant: 68 | printf("constant\n"); 69 | break; 70 | case basic: 71 | printf("basic\n"); 72 | break; 73 | case array: 74 | printf("array: %d\n", tmp->size); 75 | break; 76 | case constArray: 77 | printf("constArray: %d\n", tmp->size); 78 | break; 79 | } 80 | blanknum += 2; 81 | } 82 | } 83 | 84 | int myHash(char *key) //自定义hash函数 85 | { 86 | int res = 0, p = 1, i; 87 | for (i = 0; i < strlen(key); i++) 88 | { 89 | res = (res + key[i] * p % HT_SIZE) % HT_SIZE; 90 | p = p * HT_SEED % HT_SIZE; 91 | } 92 | return res; 93 | } 94 | 95 | int isConst(List type) 96 | { 97 | ListItr i = getGListItr(type, 0); 98 | Type tmp = nextItem(i); 99 | if (tmp->kind == constant) 100 | return 1; 101 | if (tmp->kind == constArray) 102 | return 1; 103 | return 0; 104 | } 105 | 106 | Type isNotArray(List type) 107 | { 108 | ListItr i = getGListItr(type, 0); 109 | Type tmp = nextItem(i); 110 | if (tmp->kind == constant) 111 | { 112 | Type res; 113 | NEW0(res); 114 | res->kind = constant; 115 | return res; 116 | } 117 | if (tmp->kind == basic) 118 | { 119 | Type res; 120 | NEW0(res); 121 | res->kind = basic; 122 | return res; 123 | } 124 | return NULL; 125 | } 126 | 127 | int cmpType(List type1, List type2) // 判断两个类型是否完全一致,如const int-const int,int[2][3]-int[2][3] 128 | { 129 | int res = 0; 130 | if (listsize(type1) != listsize(type2)) 131 | { 132 | return 1; 133 | } 134 | int blanknum = 0, k; 135 | ListItr i = newListItr(type1, 0); 136 | ListItr j = newListItr(type2, 0); 137 | while (hasNext(i)) 138 | { 139 | Type tmp1 = nextItem(i); 140 | Type tmp2 = nextItem(j); 141 | if (tmp1->kind != tmp2->kind) 142 | { 143 | res = 1; 144 | break; 145 | } 146 | if (tmp1->kind == array && tmp1->size != tmp2->size) 147 | { 148 | res = 1; 149 | break; 150 | } 151 | if (tmp1->kind == constArray && tmp1->size != tmp2->size) 152 | { 153 | res = 1; 154 | break; 155 | } 156 | } 157 | destroyListItr(&i); 158 | destroyListItr(&j); 159 | return res; 160 | } 161 | 162 | int cmpSingleTypeConst(Type t1, Type t2) // 后者可以是const的Type比较,没有比size 163 | { 164 | switch (t1->kind) 165 | { 166 | case basic: 167 | if (t2->kind == basic || t2->kind == constant) 168 | return 0; 169 | break; 170 | case array: 171 | if (t2->kind == array || t2->kind == constArray) 172 | return 0; 173 | break; 174 | default: 175 | if (t2->kind == t1->kind) 176 | return 0; 177 | break; 178 | } 179 | return 1; 180 | } 181 | 182 | int cmpTypeConst(List type, List constType) // 后者可以是const的比较,如int=const int,int[2][3]=const int[2][3] 183 | { 184 | int res = 0; 185 | if (listsize(type) != listsize(constType)) 186 | { 187 | return 1; 188 | } 189 | ListItr i = newListItr(type, 0); 190 | ListItr j = newListItr(constType, 0); 191 | // ListItr i = getGListItr(type, 0); 192 | // ListItr j = getGListItr(constType, 0); 193 | while (hasNext(i)) 194 | { 195 | Type tmp1 = nextItem(i); 196 | Type tmp2 = nextItem(j); 197 | if (cmpSingleTypeConst(tmp1, tmp2) > 0) 198 | { 199 | res = 1; 200 | break; 201 | } 202 | if (tmp1->kind == array && tmp1->size != tmp2->size) 203 | { 204 | res = 1; 205 | break; 206 | } 207 | if (tmp1->kind == constArray && tmp1->size != tmp2->size) 208 | { 209 | res = 1; 210 | break; 211 | } 212 | } 213 | return res; 214 | } 215 | 216 | int cmpTypeFunc(List funcType, List type) // 前者为函数形参,后者为函数实参,判断能否传入,如int-int,int[]-int[3] 217 | { 218 | int res = 0; 219 | if (listsize(funcType) != listsize(type)) 220 | { 221 | return 1; 222 | } 223 | int blanknum = 0, k; 224 | ListItr i = newListItr(funcType, 0); 225 | ListItr j = newListItr(type, 0); 226 | int flag = 0; 227 | while (hasNext(i)) 228 | { 229 | Type tmp1 = nextItem(i); 230 | Type tmp2 = nextItem(j); 231 | if (cmpSingleTypeConst(tmp1, tmp2) > 0) 232 | { 233 | res = 1; 234 | break; 235 | } 236 | if (flag == 0) 237 | flag = 1; 238 | else 239 | { // 函数传参为数组时 从第二项才开始比较size 240 | if (tmp1->kind == array && tmp1->size != tmp2->size) 241 | { 242 | res = 1; 243 | break; 244 | } 245 | if (tmp1->kind == constArray && tmp1->size != tmp2->size) 246 | { 247 | res = 1; 248 | break; 249 | } 250 | } 251 | } 252 | destroyListItr(&i); 253 | destroyListItr(&j); 254 | return res; 255 | } 256 | 257 | List combineType(List defType, List callType) 258 | { 259 | if (defType == NULL) 260 | return NULL; 261 | List resType = newList(); 262 | Type def = isNotArray(defType); 263 | if (def != NULL) // 数值 其实用不到这部分 264 | { 265 | if (callType->size == 0) 266 | { 267 | handleError(30, 0); 268 | return defType; 269 | } 270 | int res = cmpSingleTypeConst((Type)getFirst(callType), (Type)getFirst(defType)); 271 | if (res) 272 | { 273 | def->kind = empty; 274 | def->size = 0; 275 | } // error 276 | addFirst(resType, def); 277 | } 278 | else // array 279 | { 280 | if (callType->size == 0) 281 | return defType; 282 | // 举个例子 deftype是a[4][2][3] list : 4 -> 2 -> 3 283 | // calltype a[1][2] list : 1 -> 2 284 | // 从第一项开始判断 1合法 2不合法 返回错误类型empty 285 | // calltype a[1][1] list : 1 -> 1 286 | // 判断 1 合法 1 合法 下一项没了 deftype还剩3 所以返回类型是 list : 3 检验到 287 | // 合法的时候再新建一个List返回 288 | if (listsize(defType) < listsize(callType)) 289 | { 290 | Type error; 291 | NEW0(error); 292 | error->kind = empty; 293 | error->size = 1; // error 294 | addFirst(resType, error); 295 | return resType; 296 | } 297 | ListItr i = newListItr(defType, 0); 298 | ListItr j = newListItr(callType, 0); 299 | int count = listsize(defType); 300 | while (hasNext(j)) 301 | { 302 | count--; 303 | Type tmp1 = nextItem(i); // def 304 | Type tmp2 = nextItem(j); // call 305 | if (tmp1->size <= tmp2->size) 306 | { 307 | Type error; 308 | NEW0(error); 309 | error->kind = empty; 310 | error->size = 2; // error 311 | addFirst(resType, error); 312 | destroyListItr(&i); 313 | destroyListItr(&j); 314 | return resType; 315 | } 316 | } 317 | if (count == 0) 318 | { 319 | Type tmp; 320 | NEW0(tmp); 321 | if (isConst(defType)) 322 | tmp->kind = constant; 323 | else 324 | tmp->kind = basic; 325 | addFirst(resType, tmp); 326 | } 327 | else 328 | { 329 | while (hasNext(i)) 330 | { 331 | Type tmp = nextItem(i); 332 | Type copyTmp; 333 | NEW0(copyTmp); 334 | copyTmp->size = tmp->size; 335 | copyTmp->kind = tmp->kind; 336 | addLast(resType, copyTmp); 337 | } 338 | } 339 | destroyListItr(&i); 340 | destroyListItr(&j); 341 | } 342 | return resType; 343 | } 344 | 345 | void initScopeTable() 346 | { 347 | scope = 0; 348 | scopeTable = newVector(); 349 | vector scope0 = newVector(); 350 | addItem(scopeTable, scope0); 351 | } 352 | 353 | void insertScopeItem(listNode r) 354 | { 355 | vector scope = (vector)(getLastItem(scopeTable)); 356 | addItem(scope, r); 357 | } 358 | 359 | void addScope() 360 | { 361 | scope++; 362 | vector newScope = newVector(); 363 | addItem(scopeTable, newScope); 364 | } 365 | 366 | void exitScope() 367 | { 368 | vector lastScope = (vector)(getLastItem(scopeTable)); 369 | for (int i = 0; i < lastScope->size; i++) 370 | { 371 | listNode item = (listNode)getItem(lastScope, i); 372 | removeNode(item); 373 | item = NULL; 374 | } 375 | destoryVector(lastScope); 376 | removeLastItem(scopeTable); 377 | scope--; 378 | } 379 | 380 | void clearScope0() 381 | { 382 | if (scope != 0) 383 | { 384 | printf("scope is not zero!\n"); 385 | return; 386 | } 387 | vector lastScope = (vector)(getLastItem(scopeTable)); 388 | for (int i = 0; i < lastScope->size; i++) 389 | { 390 | listNode item = (listNode)getItem(lastScope, i); 391 | removeNode(item); 392 | item = NULL; 393 | } 394 | destoryVector(lastScope); 395 | removeLastItem(scopeTable); 396 | for (int i = 0; i < HT_SIZE; i++) 397 | { 398 | if (paraTable[i] != NULL) 399 | { 400 | free(paraTable[i]->first); 401 | free(paraTable[i]); 402 | paraTable[i] = NULL; 403 | } 404 | } 405 | } 406 | 407 | void initSymTable() 408 | { 409 | int i; 410 | for (i = 0; i < HT_SIZE; i++) 411 | { 412 | funcTable[i] = paraTable[i] = NULL; 413 | } 414 | } 415 | 416 | // int insertSymTable(treeNode *root) 417 | // { 418 | // int pos = myHash(root->name); //hash表的下标 419 | // int flag = checkConflict(pos, root->name); 420 | // if (flag) //有冲突 421 | // { 422 | // return -1; 423 | // } 424 | // if (hashTable[pos] == NULL) 425 | // { 426 | // hashTable[pos] = newList(); 427 | // addFirst(hashTable[pos], ); 428 | // } 429 | // } 430 | 431 | int checkReserveNames(char *name) 432 | { 433 | int i; 434 | for (i = 0; i < sizeof(RESERVE_WORDS) / sizeof(const char *); i++) 435 | { 436 | if (strcmp(name, RESERVE_WORDS[i]) == 0) 437 | { 438 | return 1; 439 | } 440 | } 441 | return 0; 442 | } 443 | 444 | Para querySymTable_para(char *name) 445 | { 446 | int pos = myHash(name); 447 | List list = paraTable[pos]; 448 | if (list == NULL || listsize(list) == 0) 449 | return NULL; 450 | ListItr i = getGListItr(list, 0); 451 | while (hasNext(i)) 452 | { 453 | Para tmp = (Para)(nextItem(i)); 454 | if (strcmp(tmp->name, name) == 0) 455 | { 456 | return tmp; 457 | } 458 | } 459 | return NULL; 460 | } 461 | 462 | int para_exist(char *name, int scope) 463 | { 464 | int t = checkReserveNames(name); 465 | if (t != 0) 466 | { 467 | return 1; // handleError(11, 0); 468 | } 469 | Para query = querySymTable_para(name); 470 | if (query != NULL && query->scope == scope) 471 | { 472 | return 2; // handleError(12, 0); 473 | } 474 | return 0; 475 | } 476 | 477 | int insertSymTable_para(Para r, int lineno) 478 | { 479 | int t = para_exist(r->name, r->scope); 480 | if (t == 1) 481 | { 482 | handleError(11, lineno); 483 | return 1; 484 | } 485 | if (t == 2) 486 | { 487 | handleError(12, lineno); 488 | return 1; 489 | } 490 | int pos = myHash(r->name); 491 | if (paraTable[pos] == NULL) 492 | { 493 | paraTable[pos] = newList(); 494 | } 495 | addFirst(paraTable[pos], r); 496 | listNode n = getFirstNode(paraTable[pos]); 497 | insertScopeItem(n); 498 | return 0; 499 | } 500 | 501 | int sdtParseExp(treeNode *r, int isIdentConst, int flag, List list) 502 | { 503 | return sdtParseAddExp(r->child, isIdentConst, flag, list, 0); 504 | } 505 | 506 | void sdtParseExp_rep(treeNode *r, List *type) // Exp_rep LB Exp RB | empty 507 | { 508 | if (r->child == NULL) //Exp_rep -> empty 509 | { 510 | return; 511 | } 512 | else if (r->child != NULL) //Exp_rep -> Exp_rep LB Exp RB 513 | { 514 | treeNode *Exp = r->child->next->next; 515 | Type newType; 516 | NEW0(newType); 517 | newType->kind = array; 518 | newType->size = sdtParseExp(Exp, 0, 0, NULL); 519 | printf("%d\n", newType->size); 520 | if (newType->size < 0) //数组的维度必须是正数 521 | { 522 | handleError(4, r->lineNo); 523 | newType->size = 0; 524 | } 525 | addFirst(*type, newType); 526 | sdtParseExp_rep(r->child, type); 527 | } 528 | } 529 | 530 | int sdtParseLVal(treeNode *r, int isIdentConst, int flag, List list) // LVal : ID Exp_rep 531 | { 532 | //查询符号表,若isIdentConst = 1,则Ident必须为Constant,否则可以是任意(在符号表中存在即可) 533 | // 若flag=1,说明是形参-数组的情况 534 | int res = 0; 535 | Para p = querySymTable_para(r->child->value); 536 | if (p == NULL) 537 | { 538 | handleError(7, r->lineNo); // not exist 539 | return 0; 540 | } 541 | List ptype = p->type; 542 | if (!isConst(ptype) && isIdentConst == 1) // 必须是const但ID不是const 543 | { 544 | handleError(9, r->lineNo); 545 | } 546 | else 547 | { 548 | if (flag == 0) // 数值 549 | { 550 | if (isNotArray(ptype) != NULL) 551 | return p->const_val[0]; 552 | List type = newList(); 553 | sdtParseExp_rep(r->child->next, &type); 554 | if (listsize(type) != listsize(ptype)) // LVal如果是取数组必须取到一个元素 555 | { 556 | handleError(21, r->lineNo); 557 | } 558 | ListItr i = newListItr(ptype, 0); 559 | ListItr j = newListItr(type, 0); 560 | int index = 0, factor = 1, flag1 = 0; 561 | while (hasNext(j)) 562 | { 563 | Type tmp1 = nextItem(i); // def 564 | Type tmp2 = nextItem(j); // call 565 | if (tmp1->size <= tmp2->size) 566 | { 567 | if (tmp1->size != -1 || flag1 != 0) 568 | { 569 | handleError(19, r->lineNo); 570 | destroyListItr(&i); 571 | destroyListItr(&j); 572 | return 0; 573 | } 574 | else 575 | { 576 | flag1 = 2; 577 | } 578 | } 579 | if (flag1 == 0) 580 | flag1 = 1; 581 | else 582 | factor *= tmp1->size; 583 | index = index + factor * tmp2->size; 584 | } 585 | destroyListItr(&i); 586 | destroyListItr(&j); 587 | if (flag1 != 2) 588 | res = p->const_val[index]; 589 | else 590 | res = 0; 591 | } 592 | else // 形参-数组 593 | { 594 | if (isNotArray(ptype) != NULL) 595 | { 596 | handleError(20, r->lineNo); // 应该输入数组,但输入的是数值 597 | } 598 | List type = newList(); 599 | sdtParseExp_rep(r->child->next, &type); 600 | List callType = combineType(ptype, type); 601 | ListItr i = getGListItr(callType, 0); 602 | Type tmp = nextItem(i); 603 | if (tmp->kind == empty) 604 | { 605 | handleError(18, r->lineNo); // 调用不合法,例如int a[2]调用的时候使用了a[2] 606 | res = 1; 607 | } 608 | *list = *callType; 609 | } 610 | } 611 | return res; 612 | } 613 | 614 | int sdtParseNumber(treeNode *r) 615 | { 616 | return r->child->int_val; 617 | } 618 | 619 | int sdtParsePrimaryExp(treeNode *r, int isIdentConst, int flag, List list) 620 | { 621 | if (strcmp(r->child->name, "LP") == 0) //PrimaryExp -> '(' Exp ')' 622 | { 623 | return sdtParseExp(r->child->next, isIdentConst, flag, list); 624 | } 625 | else if (strcmp(r->child->name, "LVal") == 0) //PrimaryExp -> LVal 626 | { 627 | return sdtParseLVal(r->child, isIdentConst, flag, list); 628 | } 629 | else //PrimaryExp -> Number 630 | { 631 | return sdtParseNumber(r->child); 632 | } 633 | } 634 | 635 | int sdtParseUnaryExp(treeNode *r, int isIdentConst, int flag, List list, int isCond) 636 | { 637 | if (strcmp(r->child->name, "PrimaryExp") == 0) //UnaryExp -> PrimaryExp 638 | { 639 | return sdtParsePrimaryExp(r->child, isIdentConst, flag, list); 640 | } 641 | else if (strcmp(r->child->name, "UnaryOp") == 0) //UnaryExp -> UnaryOp UnaryExp 642 | { 643 | int a = sdtParseUnaryExp(r->child->next, isIdentConst, 0, NULL, isCond); 644 | if (strcmp(r->child->child->name, "PLUS") == 0) 645 | { 646 | return a; 647 | } 648 | else if (strcmp(r->child->child->name, "MINUS") == 0) 649 | { 650 | return -a; 651 | } 652 | else 653 | { 654 | if (isCond == 0) 655 | handleError(14, r->lineNo); 656 | return (a == 0); 657 | } 658 | } 659 | else //UnaryExp -> Ident '(' [FuncRParams] ')' 660 | { 661 | if (isIdentConst) //常量表达式里不可能出现函数,因为函数的返回值是变量 662 | { 663 | handleError(3, r->lineNo); 664 | } 665 | else 666 | { 667 | //判断Ident是函数,并且返回值是int变量,否则报错 668 | Func f = querySymTable_func(r->child->value); 669 | if (f == NULL) 670 | { 671 | handleError(24, r->lineNo); 672 | return 0; 673 | } 674 | // 解析FuncRParams 675 | if (r->child->next->next->next == NULL) 676 | { 677 | if (f->paraNum != 0) 678 | handleError(25, r->lineNo); 679 | } 680 | else if (f->paraNum == 0) 681 | handleError(22, r->lineNo); 682 | else 683 | { 684 | sdtParseFuncRParams(r->child->next->next, f->paraList); 685 | } 686 | } 687 | } 688 | } 689 | 690 | int sdtParseMulExp(treeNode *r, int isIdentConst, int flag, List list, int isCond) 691 | { 692 | if (strcmp(r->child->name, "UnaryExp") == 0) //MulExp -> UnaryExp 693 | { 694 | return sdtParseUnaryExp(r->child, isIdentConst, flag, list, isCond); 695 | } 696 | else //MulExp -> MulExp ('*'|'/'|'%') UnaryExp 697 | { 698 | int a = sdtParseMulExp(r->child, isIdentConst, 0, NULL, isCond); 699 | int b = sdtParseUnaryExp(r->child->next->next, isIdentConst, 0, NULL, isCond); // 应该是这样? 700 | if (strcmp(r->child->next->name, "STAR") == 0) //乘法 701 | { 702 | return a * b; 703 | } 704 | else 705 | { 706 | if (b == 0) //除运算和模运算,被除数不能是0 707 | { 708 | handleError(2, r->lineNo); 709 | } 710 | else if (strcmp(r->child->next->name, "DIV") == 0) 711 | { 712 | return a / b; 713 | } 714 | else 715 | { 716 | return a % b; 717 | } 718 | } 719 | } 720 | } 721 | 722 | int sdtParseAddExp(treeNode *r, int isIdentConst, int flag, List list, int isCond) 723 | { 724 | if (strcmp(r->child->name, "MulExp") == 0) //AddExp -> MulExp 725 | { 726 | return sdtParseMulExp(r->child, isIdentConst, flag, list, isCond); 727 | } 728 | else //AddExp -> AddExp ('+'|'-') MulExp 729 | { 730 | int a = sdtParseAddExp(r->child, isIdentConst, 0, NULL, isCond); 731 | int b = sdtParseMulExp(r->child->next->next, isIdentConst, 0, NULL, isCond); 732 | if (strcmp(r->child->child->name, "PLUS") == 0) 733 | { 734 | return a + b; 735 | } 736 | else 737 | { 738 | return a - b; 739 | } 740 | } 741 | } 742 | 743 | int sdtParseConstExp(treeNode *r) 744 | { 745 | return sdtParseAddExp(r->child, 1, 0, NULL, 0); //ConstExp -> AddExp 746 | } 747 | 748 | void sdtParseComConstDef_rep(treeNode *r) //ComConstDef_rep -> ComConstDef_rep COMMA ConstDef | empty 749 | { 750 | if (r == NULL || r->child == NULL) 751 | return; 752 | sdtParseComConstDef_rep(r->child); 753 | sdtParseConstDef(r->child->next->next); 754 | } 755 | 756 | void sdtParseConstDecl(treeNode *r) //ConstDecl : CONST FuncType ConstDef ComConstDef_rep SEMI 757 | { 758 | if (r == NULL) 759 | return; 760 | if (strcmp(r->name, "ConstDecl") == 0) 761 | { 762 | if (strcmp(r->child->next->child->name, "VOID") == 0) //常量类型不能是void 763 | { 764 | handleError(1, r->lineNo); 765 | return; 766 | } 767 | sdtParseConstDef(r->child->next->next); 768 | sdtParseComConstDef_rep(r->child->next->next->next); 769 | } 770 | } 771 | 772 | void sdtParseConstExp_rep(treeNode *r, List *type) 773 | { 774 | if (r->child == NULL) //constExp_rep -> empty 775 | { 776 | return; 777 | } 778 | else if (r->child != NULL) //constExp_rep -> constExp_rep LB ConstExp RB 779 | { 780 | treeNode *constExp = r->child->next->next; 781 | Type newType; 782 | NEW0(newType); 783 | newType->kind = constArray; 784 | newType->size = sdtParseConstExp(constExp); 785 | printf("%d\n", newType->size); 786 | if (newType->size <= 0) //数组的维度必须是正数 787 | { 788 | handleError(4, r->lineNo); 789 | newType->size = 1; 790 | } 791 | addFirst(*type, newType); 792 | sdtParseConstExp_rep(r->child, type); 793 | } 794 | } 795 | 796 | //返回r之后最近的一个'{', '}', ConstExp或者Exp 797 | treeNode *getNextToken(treeNode *r) 798 | { 799 | if (r == NULL) 800 | return NULL; 801 | //r=r->next; 802 | while (r != NULL) 803 | { 804 | if (strcmp(r->name, "LC") == 0 || strcmp(r->name, "RC") == 0 || strcmp(r->name, "ConstExp") == 0 || strcmp(r->name, "Exp") == 0) 805 | { 806 | return r; 807 | } 808 | else if (strcmp(r->name, "ConstInitVal") == 0 || strcmp(r->name, "ComConstInitVal_rep") == 0 || strcmp(r->name, "InitVal") == 0 || strcmp(r->name, "ComInitVal_rep") == 0) 809 | { 810 | if (r->child != NULL) 811 | return getNextToken(r->child); 812 | } 813 | if (r->next != NULL) 814 | { 815 | r = r->next; 816 | } 817 | else 818 | { 819 | while (r) 820 | { 821 | r = r->father; 822 | if (r->next != NULL) 823 | { 824 | r = r->next; 825 | break; 826 | } 827 | } 828 | } 829 | } 830 | } 831 | 832 | int getArraySize(int *a, int index, int size) 833 | { 834 | int arraySize = 1; 835 | for (; index < size; index++) 836 | arraySize *= a[index]; 837 | return arraySize; 838 | } 839 | 840 | void getArrayDimList(int *a, Para para) 841 | { 842 | ListItr i = getGListItr(para->type, 0); 843 | int size = 0; 844 | while (hasNext(i)) 845 | { 846 | a[size++] = ((Type)(nextItem(i)))->size; 847 | } 848 | } 849 | 850 | treeNode *sdtParseConstInitVal_Array(treeNode *r, Para *para, int *a, int arrayDim, int index, int paraCount, int *numCount, int numCountLim) 851 | { 852 | /* 853 | ConstInitVal : ConstExp | LC ConstInitVal ComConstInitVal_rep RC | LC RC 854 | ComConstInitVal_rep : ComConstInitVal_rep COMMA ConstInitVal | empty 855 | */ 856 | printf("sdtParseConstInitVal_Array(arrayDim=%d, index=%d, paraCount=%d, numCount=%d, numCountLim=%d\n", 857 | arrayDim, index, paraCount, *numCount, numCountLim); 858 | if (r == NULL) 859 | return NULL; 860 | while (1) 861 | { 862 | if (r->next != NULL) 863 | { 864 | r = r->next; 865 | } 866 | else 867 | { 868 | while (r) 869 | { 870 | r = r->father; 871 | if (r->next != NULL) 872 | { 873 | r = r->next; 874 | break; 875 | } 876 | } 877 | } 878 | if (r == NULL) 879 | return NULL; 880 | r = getNextToken(r); 881 | printf("nextToken: %s\n", r->name); 882 | if (strcmp(r->name, "LC") == 0) 883 | { 884 | if (index + 1 >= arrayDim) //大括号嵌套层数超过数组维数 885 | { 886 | handleError(8, r->lineNo); 887 | } 888 | if ((*numCount) % getArraySize(a, index + 1, arrayDim) != 0) //如果当前维度没有填满,需要隐式初始化 889 | { 890 | int dim = getArraySize(a, index + 1, arrayDim); 891 | (*numCount) += dim - (*numCount) % dim; 892 | } 893 | if ((*numCount) >= numCountLim) //同一层大括号的数量超过了这一层的维数 894 | { 895 | handleError(10, r->lineNo); 896 | } 897 | r = sdtParseConstInitVal_Array(r, para, a, arrayDim, index + 1, paraCount + 1, numCount, *numCount + getArraySize(a, index + 1, arrayDim)); 898 | } 899 | else if (strcmp(r->name, "RC") == 0) 900 | { 901 | if ((*numCount) % getArraySize(a, index, arrayDim) != 0) //当前维没填满 902 | { 903 | (*numCount) = numCountLim; 904 | } 905 | (*numCount) = numCountLim; 906 | return r; 907 | } 908 | else if (strcmp(r->name, "ConstExp") == 0) 909 | { 910 | int res = sdtParseConstExp(r); 911 | printf("res=%d\n", res); 912 | if (*numCount >= numCountLim) //常量数量超过当前维限制 913 | { 914 | handleError(10, r->lineNo); 915 | } 916 | (*para)->const_val[*numCount] = res; 917 | *numCount = *numCount + 1; 918 | } 919 | } 920 | } 921 | 922 | void sdtParseConstInitVal(treeNode *r, Para *para) 923 | { 924 | /* 925 | ConstInitVal : ConstExp | LC ConstInitVal ComConstInitVal_rep RC | LC RC 926 | ComConstInitVal_rep : ComConstInitVal_rep COMMA ConstInitVal | empty 927 | */ 928 | Type t = getFirst((*para)->type); 929 | if (t->kind == constant) //常量的初始化必须是一个单一int值 930 | { 931 | if (strcmp(r->child->name, "ConstExp") == 0) 932 | { 933 | (*para)->const_val = (int *)malloc(sizeof(int)); 934 | (*para)->const_val[0] = sdtParseConstExp(r->child); 935 | } 936 | else 937 | { 938 | handleError(5, r->lineNo); 939 | } 940 | } 941 | else // constArray 942 | { 943 | int arrayDim = listsize((*para)->type); 944 | printf("arrayDim: %d\n", arrayDim); 945 | int *arrayDimList = (int *)malloc(sizeof(int) * arrayDim); 946 | getArrayDimList(arrayDimList, *para); 947 | printf("arrayDimList: {"); 948 | int i; 949 | for (i = 0; i < arrayDim; i++) 950 | printf("%d,", arrayDimList[i]); 951 | printf("}\n"); 952 | int arraySize = getArraySize(arrayDimList, 0, arrayDim); 953 | printf("arraySize: %d\n", arraySize); 954 | (*para)->const_val = (int *)malloc(sizeof(int) * arraySize); 955 | memset((*para)->const_val, 0, sizeof((*para)->const_val)); 956 | if (strcmp(r->child->next->name, "RC") == 0) //仅一个{},全部初始化为0,直接返回 957 | { 958 | printf("All zero\n"); 959 | return; 960 | } 961 | else if (strcmp(r->child->name, "ConstExp") == 0) 962 | { 963 | handleError(6, r->lineNo); 964 | } 965 | else 966 | { 967 | int tmp = 0; 968 | sdtParseConstInitVal_Array(r->child, para, arrayDimList, arrayDim, 0, 1, &tmp, arraySize); 969 | int i; 970 | printf("{"); 971 | for (i = 0; i < arraySize; i++) 972 | printf("%d ", (*para)->const_val[i]); 973 | printf("}\n"); 974 | } 975 | free(arrayDimList); 976 | } 977 | } 978 | 979 | void sdtParseConstDef(treeNode *r) 980 | { 981 | if (r == NULL) 982 | return; 983 | if (strcmp(r->name, "ConstDef") == 0) //ConstDef -> ID ConstExp_rep ASSIGNOP ConstInitVal 984 | { 985 | Para item; 986 | NEW0(item); 987 | item->type = newList(); 988 | item->scope = scope; 989 | strcpy(item->name, r->child->value); 990 | if (r->child->next->child == NULL) //ID is a constant 991 | { 992 | Type newType; 993 | NEW0(newType); 994 | newType->kind = constant; 995 | addFirst(item->type, newType); 996 | sdtParseConstInitVal(r->child->next->next->next, &item); 997 | int tmp = insertSymTable_para(item, r->lineNo); 998 | if (!tmp) 999 | printf("constant: %d\n", item->const_val[0]); 1000 | } 1001 | else // ID is a const array 1002 | { 1003 | //printf("constDef: constArray\n"); 1004 | sdtParseConstExp_rep(r->child->next, &item->type); 1005 | //printType(item->type); 1006 | sdtParseConstInitVal(r->child->next->next->next, &item); 1007 | int tmp = insertSymTable_para(item, r->lineNo); 1008 | if (!tmp) 1009 | { 1010 | printf("constDef: constArray\n"); 1011 | printType(item->type); 1012 | } 1013 | } 1014 | } 1015 | } 1016 | 1017 | void sdtParseCompUnit(treeNode *r) 1018 | { 1019 | if (strcmp(r->child->name, "Decl") == 0) // Decl 1020 | { 1021 | sdtParseDecl(r->child); 1022 | } 1023 | else if (strcmp(r->child->name, "FuncDef") == 0) // FuncDef 1024 | { 1025 | sdtParseFuncDef(r->child); 1026 | } 1027 | else if (strcmp(r->child->next->name, "Decl") == 0) // CompUnit Decl 1028 | { 1029 | sdtParseCompUnit(r->child); 1030 | sdtParseDecl(r->child->next); 1031 | } 1032 | else if (strcmp(r->child->next->name, "FuncDef") == 0) // CompUnit FuncDef 1033 | { 1034 | sdtParseCompUnit(r->child); 1035 | sdtParseFuncDef(r->child->next); 1036 | } 1037 | } 1038 | 1039 | void sdtParseDecl(treeNode *r) // Decl -> ConstDecl | VarDecl 1040 | { 1041 | if (r == NULL) 1042 | return; 1043 | if (strcmp(r->name, "Decl") == 0) 1044 | { 1045 | if (strcmp(r->child->name, "ConstDecl") == 0) 1046 | { 1047 | sdtParseConstDecl(r->child); 1048 | } 1049 | else if (strcmp(r->child->name, "VarDecl") == 0) 1050 | { 1051 | sdtParseVarDecl(r->child); 1052 | } 1053 | } 1054 | } 1055 | 1056 | void sdtParseVarDecl(treeNode *r) // VarDecl -> FuncType(not void) VarDef VarDef_rep SEMI 1057 | { 1058 | if (r == NULL) 1059 | return; 1060 | if (strcmp(r->name, "VarDecl") == 0) 1061 | { 1062 | if (strcmp(r->child->child->name, "VOID") == 0) //变量类型不能是void 1063 | { 1064 | handleError(1, r->lineNo); 1065 | return; 1066 | } 1067 | sdtParseVarDef(r->child->next); 1068 | sdtParseComVarDef_rep(r->child->next->next); 1069 | } 1070 | } 1071 | 1072 | void sdtParseVarDef(treeNode *r) // VarDef -> ID ConstExp_rep | ID ConstExp_rep ASSIGNOP InitVal 1073 | { 1074 | if (r == NULL) 1075 | return; 1076 | if (strcmp(r->name, "VarDef") == 0) 1077 | { 1078 | Para item; 1079 | NEW0(item); 1080 | item->type = newList(); 1081 | item->scope = scope; 1082 | strcpy(item->name, r->child->value); 1083 | if (r->child->next->child == NULL) //ID is a variable 1084 | { 1085 | Type newType; 1086 | NEW0(newType); 1087 | newType->kind = basic; 1088 | addFirst(item->type, newType); 1089 | if (r->child->next->next != NULL) 1090 | { 1091 | sdtParseInitVal(r->child->next->next->next, &item); 1092 | } 1093 | else 1094 | { 1095 | item->const_val = (int *)malloc(sizeof(int)); 1096 | item->const_val[0] = 0; 1097 | } 1098 | int tmp = insertSymTable_para(item, r->lineNo); 1099 | if (!tmp) 1100 | printf("basic: %d\n", item->const_val[0]); 1101 | } 1102 | else // ID is an array 1103 | { 1104 | //printf("VarDef: VarArray\n"); 1105 | sdtParseConstExp_rep(r->child->next, &item->type); 1106 | //printType(item->type); 1107 | if (r->child->next->next != NULL) 1108 | { 1109 | sdtParseInitVal(r->child->next->next->next, &item); 1110 | } 1111 | else 1112 | { 1113 | sdtParseInitVal(NULL, &item); 1114 | } 1115 | int tmp = insertSymTable_para(item, r->lineNo); 1116 | if (!tmp) 1117 | { 1118 | printf("VarDef: VarArray\n"); 1119 | printType(item->type); 1120 | } 1121 | } 1122 | } 1123 | } 1124 | 1125 | void sdtParseComVarDef_rep(treeNode *r) // ComVarDef_rep -> ComVarDef_rep COMMA VarDef | empty 1126 | { 1127 | if (r == NULL || r->child == NULL) 1128 | return; 1129 | sdtParseComVarDef_rep(r->child); 1130 | sdtParseVarDef(r->child->next->next); 1131 | } 1132 | 1133 | void sdtParseInitVal(treeNode *r, Para *para) // InitVal -> Exp | LC InitVal ComInitVal_rep RC | LC RC 1134 | { // ComInitVal_rep -> ComInitVal_rep COMMA InitVal | empty 1135 | Type t = getFirst((*para)->type); 1136 | if (t->kind == basic) 1137 | { 1138 | if (strcmp(r->child->name, "Exp") == 0) 1139 | { 1140 | (*para)->const_val = (int *)malloc(sizeof(int)); 1141 | (*para)->const_val[0] = sdtParseExp(r->child, 0, 0, NULL); 1142 | } 1143 | else 1144 | { 1145 | handleError(5, r->lineNo); 1146 | } 1147 | } 1148 | else // array 1149 | { 1150 | int arrayDim = listsize((*para)->type); 1151 | printf("arrayDim: %d\n", arrayDim); 1152 | int *arrayDimList = (int *)malloc(sizeof(int) * arrayDim); 1153 | getArrayDimList(arrayDimList, *para); 1154 | printf("arrayDimList: {"); 1155 | int i; 1156 | for (i = 0; i < arrayDim; i++) 1157 | printf("%d,", arrayDimList[i]); 1158 | printf("}\n"); 1159 | int arraySize = getArraySize(arrayDimList, 0, arrayDim); 1160 | printf("arraySize: %d\n", arraySize); 1161 | (*para)->const_val = (int *)malloc(sizeof(int) * arraySize); 1162 | memset((*para)->const_val, 0, sizeof((*para)->const_val)); 1163 | if (r == NULL || strcmp(r->child->next->name, "RC") == 0) //仅一个{},全部初始化为0,直接返回 1164 | { 1165 | printf("All zero\n"); 1166 | return; 1167 | } 1168 | else if (strcmp(r->child->name, "Exp") == 0) 1169 | { 1170 | handleError(6, r->lineNo); 1171 | } 1172 | else 1173 | { 1174 | int tmp = 0; 1175 | sdtParseInitVal_Array(r->child, para, arrayDimList, arrayDim, 0, 1, &tmp, arraySize); 1176 | int i; 1177 | printf("{"); 1178 | for (i = 0; i < arraySize; i++) 1179 | printf("%d ", (*para)->const_val[i]); 1180 | printf("}\n"); 1181 | } 1182 | } 1183 | } 1184 | 1185 | treeNode *sdtParseInitVal_Array(treeNode *r, Para *para, int *a, int arrayDim, int index, int paraCount, int *numCount, int numCountLim) 1186 | { 1187 | // InitVal -> Exp | LC InitVal ComInitVal_rep RC | LC RC 1188 | // ComInitVal_rep -> ComInitVal_rep COMMA InitVal | empty 1189 | printf("sdtParseInitVal_Array(arrayDim=%d, index=%d, paraCount=%d, numCount=%d, numCountLim=%d\n", 1190 | arrayDim, index, paraCount, *numCount, numCountLim); 1191 | if (r == NULL) 1192 | return NULL; 1193 | while (1) 1194 | { 1195 | if (r->next != NULL) 1196 | { 1197 | r = r->next; 1198 | } 1199 | else 1200 | { 1201 | while (r) 1202 | { 1203 | r = r->father; 1204 | if (r->next != NULL) 1205 | { 1206 | r = r->next; 1207 | break; 1208 | } 1209 | } 1210 | } 1211 | if (r == NULL) 1212 | return NULL; 1213 | r = getNextToken(r); 1214 | printf("nextToken: %s\n", r->name); 1215 | if (strcmp(r->name, "LC") == 0) 1216 | { 1217 | if (index + 1 >= arrayDim) //大括号嵌套层数超过数组维数 1218 | { 1219 | handleError(8, r->lineNo); 1220 | } 1221 | if ((*numCount) % getArraySize(a, index + 1, arrayDim) != 0) //如果当前维度没有填满,需要隐式初始化 1222 | { 1223 | int dim = getArraySize(a, index + 1, arrayDim); 1224 | (*numCount) += dim - (*numCount) % dim; 1225 | } 1226 | if ((*numCount) >= numCountLim) //同一层大括号的数量超过了这一层的维数 1227 | { 1228 | handleError(10, r->lineNo); 1229 | } 1230 | r = sdtParseInitVal_Array(r, para, a, arrayDim, index + 1, paraCount + 1, numCount, *numCount + getArraySize(a, index + 1, arrayDim)); 1231 | } 1232 | else if (strcmp(r->name, "RC") == 0) 1233 | { 1234 | if ((*numCount) % getArraySize(a, index, arrayDim) != 0) //当前维没填满 1235 | { 1236 | (*numCount) = numCountLim; 1237 | } 1238 | (*numCount) = numCountLim; 1239 | return r; 1240 | } 1241 | else if (strcmp(r->name, "ConstExp") == 0 || strcmp(r->name, "Exp") == 0) 1242 | { 1243 | int res = sdtParseExp(r, 0, 0, NULL); 1244 | printf("res=%d\n", res); 1245 | if (*numCount >= numCountLim) //常量数量超过当前维限制 1246 | { 1247 | handleError(10, r->lineNo); 1248 | } 1249 | (*para)->const_val[*numCount] = res; 1250 | *numCount = *numCount + 1; 1251 | } 1252 | } 1253 | } 1254 | 1255 | void sdtParseFuncDef(treeNode *r) // FuncDef -> FuncType ID LP FuncFParams RP Block 1256 | { 1257 | Func f; 1258 | NEW0(f); 1259 | strcpy(f->name, r->child->next->value); 1260 | Type newType; 1261 | NEW0(newType); 1262 | addScope(); // 函数定义的参数表需要在符号表里面 1263 | if (strcmp(r->child->next->next->next->name, "FuncFParams") == 0) 1264 | { // FuncDef -> FuncType ID LP FuncFParams RP Block 1265 | vector list = sdtParseFuncFParams(r->child->next->next->next); 1266 | f->paraList = list; 1267 | f->paraNum = list->size; 1268 | if (strcmp(r->child->child->name, "VOID") == 0) 1269 | { 1270 | newType->kind = empty; 1271 | f->retType = newType; 1272 | insertSymTable_func(f, r->lineNo); // 函数内部可以调用自己 所以要在block前面插入符号表 1273 | sdtParseBlock(r->child->next->next->next->next->next, 2, 1); 1274 | } 1275 | else 1276 | { 1277 | newType->kind = basic; 1278 | f->retType = newType; 1279 | insertSymTable_func(f, r->lineNo); 1280 | sdtParseBlock(r->child->next->next->next->next->next, 1, 1); 1281 | } 1282 | } 1283 | else // FuncType ID LP RP Block 1284 | { 1285 | f->paraList = NULL; 1286 | f->paraNum = 0; 1287 | if (strcmp(r->child->child->name, "VOID") == 0) 1288 | { 1289 | newType->kind = empty; 1290 | f->retType = newType; 1291 | insertSymTable_func(f, r->lineNo); 1292 | sdtParseBlock(r->child->next->next->next->next, 2, 1); 1293 | } 1294 | else 1295 | { 1296 | newType->kind = basic; 1297 | f->retType = newType; 1298 | insertSymTable_func(f, r->lineNo); 1299 | sdtParseBlock(r->child->next->next->next->next, 1, 1); 1300 | } 1301 | } 1302 | exitScope(); 1303 | //insertSymTable_func(f); 1304 | } 1305 | 1306 | vector sdtParseFuncFParams(treeNode *r) // FuncFParams -> FuncFParam ComFuncFParam_rep 1307 | { 1308 | vector paraList = newVector(); 1309 | sdtParseFuncFParam(r->child, paraList); 1310 | sdtParseComFuncFParam_rep(r->child->next, paraList); 1311 | return paraList; 1312 | } 1313 | 1314 | void sdtParseComFuncFParam_rep(treeNode *r, vector paraList) // ComFuncFParam_rep : ComFuncFParam_rep COMMA FuncFParam | empty 1315 | { 1316 | if (r == NULL || r->child == NULL) 1317 | return; 1318 | sdtParseComFuncFParam_rep(r->child, paraList); 1319 | sdtParseFuncFParam(r->child->next->next, paraList); 1320 | } 1321 | 1322 | void sdtParseFuncFParam(treeNode *r, vector paraList) // FuncFParam -> FuncType (not void) ID 1323 | { // | FuncType (not void) ID LB RB LbEXPRb_rep 1324 | Para item; 1325 | NEW0(item); 1326 | item->type = newList(); 1327 | item->scope = scope; 1328 | strcpy(item->name, r->child->next->value); 1329 | if (strcmp(r->child->child->name, "VOID") == 0) 1330 | { 1331 | handleError(16, r->lineNo); 1332 | } 1333 | else if (r->child->next->next != NULL) 1334 | { 1335 | // array 加入paraList和scope 1336 | sdtParseLbEXPRb_rep(r->child->next->next->next->next, &item->type); 1337 | Type newType; 1338 | NEW0(newType); 1339 | newType->kind = array; 1340 | newType->size = -1; // []内任意size都可以 1341 | addFirst(item->type, newType); 1342 | int tmp = insertSymTable_para(item, r->lineNo); 1343 | if (!tmp) 1344 | { 1345 | addItem(paraList, item); 1346 | printf("function array param: %s\n", item->name); 1347 | } 1348 | } 1349 | else 1350 | { 1351 | // not array 加入paraList和scope 1352 | Type newType; 1353 | NEW0(newType); 1354 | newType->kind = basic; 1355 | addFirst(item->type, newType); 1356 | item->const_val = (int *)malloc(sizeof(int)); 1357 | item->const_val[0] = 0; 1358 | int tmp = insertSymTable_para(item, r->lineNo); 1359 | if (!tmp) 1360 | { 1361 | addItem(paraList, item); 1362 | printf("function int param: %s\n", item->name); 1363 | } 1364 | } 1365 | } 1366 | 1367 | void sdtParseLbEXPRb_rep(treeNode *r, List *type) // -> LbEXPRb_rep LB Exp RB | empty 1368 | { 1369 | if (r == NULL || r->child == NULL) 1370 | return; 1371 | treeNode *Exp = r->child->next->next; 1372 | Type newType; 1373 | NEW0(newType); 1374 | newType->kind = array; 1375 | newType->size = sdtParseExp(Exp, 0, 0, NULL); 1376 | if (newType->size < 0) //数组的维度必须是正数 1377 | { 1378 | handleError(4, r->lineNo); 1379 | newType->size = 0; 1380 | } 1381 | addFirst(*type, newType); 1382 | sdtParseLbEXPRb_rep(r->child, type); 1383 | } 1384 | 1385 | void sdtParseBlock(treeNode *r, int flag, int noAdd) // Block -> LC BlockItem_rep RC 1386 | { // flag = 1: return int | flag = 2: return void | flag = 0: no return 1387 | if (!noAdd) 1388 | addScope(); 1389 | sdtParseBlockItem_rep(r->child->next, flag); 1390 | if (!noAdd) 1391 | exitScope(); 1392 | } 1393 | 1394 | void sdtParseBlockItem_rep(treeNode *r, int flag) // BlockItem_rep : BlockItem_rep BlockItem | empty 1395 | { 1396 | if (r == NULL || r->child == NULL) 1397 | return; 1398 | sdtParseBlockItem_rep(r->child, flag); 1399 | sdtParseBlockItem(r->child->next, flag); 1400 | } 1401 | 1402 | void sdtParseBlockItem(treeNode *r, int flag) // BlockItem -> Decl | Stmt 1403 | { // flag = 1: return int | flag = 2: return void | flag = 0: no return 1404 | if (strcmp(r->child->name, "Decl") == 0) 1405 | { 1406 | return sdtParseDecl(r->child); 1407 | } 1408 | else if (strcmp(r->child->name, "Stmt") == 0) 1409 | { 1410 | return sdtParseStmt(r->child, flag); 1411 | } 1412 | } 1413 | 1414 | void sdtParseStmt(treeNode *r, int flag) 1415 | { // flag = 1: return int | flag = 2: return void | flag = 0: no return 1416 | if (strcmp(r->child->name, "Block") == 0) // Block 1417 | { 1418 | sdtParseBlock(r->child, flag, 0); 1419 | } 1420 | else if (strcmp(r->child->name, "LVal") == 0) // LVal ASSIGNOP Exp SEMI 1421 | { 1422 | sdtParseLVal(r->child, 0, 0, NULL); 1423 | sdtParseExp(r->child->next->next, 0, 0, NULL); 1424 | } 1425 | else if (strcmp(r->child->name, "Exp") == 0) // Exp SEMI 1426 | { 1427 | sdtParseExp(r->child, 0, 0, NULL); 1428 | } 1429 | else if (strcmp(r->child->name, "SEMI") == 0) // SEMI 1430 | { 1431 | return; 1432 | } 1433 | else if (strcmp(r->child->name, "IF") == 0) // IF LP Cond RP Stmt [ELSE Stmt] 1434 | { 1435 | sdtParseCond(r->child->next->next); 1436 | sdtParseStmt(r->child->next->next->next->next, flag); 1437 | if (r->child->next->next->next->next->next != NULL) 1438 | { 1439 | sdtParseStmt(r->child->next->next->next->next->next->next, flag); 1440 | } 1441 | } 1442 | else if (strcmp(r->child->name, "WHILE") == 0) // WHILE LP Cond RP Stmt 1443 | { 1444 | whileCnt++; 1445 | sdtParseCond(r->child->next->next); 1446 | sdtParseStmt(r->child->next->next->next->next, flag); 1447 | whileCnt--; 1448 | } 1449 | else if (strcmp(r->child->name, "BREAK") == 0) // BREAK SEMI 1450 | { 1451 | if (whileCnt <= 0) 1452 | { 1453 | handleError(13, r->lineNo); 1454 | } 1455 | return; 1456 | } 1457 | else if (strcmp(r->child->name, "CONTINUE") == 0) // CONTINUE SEMI 1458 | { 1459 | if (whileCnt <= 0) 1460 | { 1461 | handleError(13, r->lineNo); 1462 | } 1463 | return; 1464 | } 1465 | else if (strcmp(r->child->name, "RETURN") == 0) // RETURN SEMI | RETURN Exp SEMI 1466 | { 1467 | if (strcmp(r->child->next->name, "SEMI") == 0) 1468 | { 1469 | if (flag != 2) 1470 | handleError(17, r->lineNo); 1471 | } 1472 | else 1473 | { 1474 | if (flag != 1) 1475 | handleError(17, r->lineNo); 1476 | } 1477 | } 1478 | } 1479 | 1480 | void sdtParseExpRParams(treeNode *r, vector v, int i) // addExp 1481 | { 1482 | if (v->size <= i) 1483 | { 1484 | handleError(23, r->lineNo); 1485 | } 1486 | Para p = getItem(v, i); 1487 | List type = p->type; 1488 | if (isNotArray(type) != NULL) 1489 | { 1490 | // number 如果addExp在解析过程中发现不是number会自行报错 1491 | sdtParseAddExp(r->child, 0, 0, NULL, 0); 1492 | } 1493 | else 1494 | { 1495 | // array 1496 | List calltype; 1497 | NEW0(calltype); 1498 | sdtParseAddExp(r->child, 0, 1, calltype, 0); 1499 | int t = cmpTypeFunc(type, calltype); 1500 | if (t) 1501 | { 1502 | handleError(15, r->lineNo); 1503 | } 1504 | } 1505 | } 1506 | 1507 | void sdtParseComExp_repRParams(treeNode *r, vector v, int j) // comExp_rep COMMA Exp | empty 1508 | { 1509 | if (r == NULL || r->child == NULL) 1510 | { 1511 | if (j != 0) 1512 | handleError(25, r->lineNo); 1513 | return; 1514 | } 1515 | else if (j == 0) 1516 | { 1517 | handleError(22, r->lineNo); 1518 | return; 1519 | } 1520 | sdtParseComExp_repRParams(r->child, v, j - 1); 1521 | sdtParseExpRParams(r->child->next->next, v, j); 1522 | } 1523 | 1524 | void sdtParseFuncRParams(treeNode *r, vector paraList) // Exp comExp_rep 1525 | { 1526 | if (r == NULL || r->child == NULL) 1527 | { 1528 | if (paraList == NULL || paraList->size == 0) 1529 | return; 1530 | else 1531 | handleError(25, r->lineNo); 1532 | return; 1533 | } 1534 | sdtParseExpRParams(r->child, paraList, 0); 1535 | sdtParseComExp_repRParams(r->child->next, paraList, paraList->size - 1); 1536 | return; 1537 | } 1538 | 1539 | int sdtParseCond(treeNode *r) // LOrExp 1540 | { 1541 | return sdtParseLOrExp(r->child); 1542 | } 1543 | 1544 | int sdtParseLOrExp(treeNode *r) // LAndExp | LOrExp OR LAndExp 1545 | { 1546 | if (r->child->next == NULL) 1547 | { 1548 | return sdtParseLAndExp(r->child); 1549 | } 1550 | else 1551 | { 1552 | int i = sdtParseLOrExp(r->child); 1553 | int j = sdtParseLAndExp(r->child->next->next); 1554 | return i || j; 1555 | } 1556 | } 1557 | 1558 | int sdtParseLAndExp(treeNode *r) // EqExp | LAndExp AND EqExp 1559 | { 1560 | if (r->child->next == NULL) 1561 | { 1562 | return sdtParseEqExp(r->child); 1563 | } 1564 | else 1565 | { 1566 | int i = sdtParseLAndExp(r->child); 1567 | int j = sdtParseEqExp(r->child->next->next); 1568 | return i && j; 1569 | } 1570 | } 1571 | 1572 | int sdtParseEqExp(treeNode *r) // RelExp | EqExp EQ RelExp | EqExp NEQ RelExp 1573 | { 1574 | if (r->child->next == NULL) 1575 | { 1576 | return sdtParseRelExp(r->child); 1577 | } 1578 | else 1579 | { 1580 | int i = sdtParseEqExp(r->child); 1581 | int j = sdtParseRelExp(r->child->next->next); 1582 | if (strcmp(r->child->next->name, "EQ") == 0) 1583 | return i == j; 1584 | else 1585 | return i != j; 1586 | } 1587 | } 1588 | 1589 | int sdtParseRelExp(treeNode *r) // AddExp | RelExp LT/GT/LTE/GTE AddExp 1590 | { 1591 | if (r->child->next == NULL) 1592 | { 1593 | return sdtParseAddExp(r->child, 0, 0, NULL, 1); 1594 | } 1595 | else 1596 | { 1597 | int i = sdtParseRelExp(r->child); 1598 | int j = sdtParseAddExp(r->child->next->next, 0, 0, NULL, 1); 1599 | if (strcmp(r->child->next->name, "LT") == 0) 1600 | return i < j; 1601 | if (strcmp(r->child->next->name, "GT") == 0) 1602 | return i > j; 1603 | if (strcmp(r->child->next->name, "LTE") == 0) 1604 | return i <= j; 1605 | else 1606 | return i >= j; 1607 | } 1608 | } 1609 | 1610 | /* print the syntax tree */ 1611 | int sdtParse(treeNode *r) 1612 | { 1613 | initScopeTable(); 1614 | sdtParseCompUnit(r); 1615 | clearScope0(); 1616 | return errorcnt; 1617 | } 1618 | 1619 | Func querySymTable_func(char *name) 1620 | { 1621 | int pos = myHash(name); 1622 | List list = funcTable[pos]; 1623 | if (list == NULL || listsize(list) == 0) 1624 | return NULL; 1625 | ListItr i = getGListItr(list, 0); 1626 | while (hasNext(i)) 1627 | { 1628 | Func tmp = (Func)(nextItem(i)); 1629 | if (strcmp(tmp->name, name) == 0) 1630 | { 1631 | return tmp; 1632 | } 1633 | } 1634 | return NULL; 1635 | } 1636 | 1637 | int func_exist(char *name) 1638 | { 1639 | int t = checkReserveNames(name); 1640 | if (t != 0) 1641 | { 1642 | return 1; // handleError(11, 0); 1643 | } 1644 | Func res = querySymTable_func(name); 1645 | if (res != NULL) 1646 | { 1647 | return 2; // handleError(12, 0); 1648 | } 1649 | return 0; 1650 | } 1651 | 1652 | int insertSymTable_func(Func r, int lineno) 1653 | { 1654 | int t = func_exist(r->name); 1655 | if (t == 1) 1656 | { 1657 | handleError(11, lineno); 1658 | return 1; 1659 | } 1660 | if (t == 2) 1661 | { 1662 | handleError(12, lineno); 1663 | return 1; 1664 | } 1665 | int pos = myHash(r->name); 1666 | if (funcTable[pos] == NULL) 1667 | { 1668 | funcTable[pos] = newList(); 1669 | } 1670 | addFirst(funcTable[pos], r); 1671 | return 0; 1672 | } -------------------------------------------------------------------------------- /symtable.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYMTABLE_H 2 | #define _SYMTABLE_H 3 | #include "node.h" 4 | #include "list.h" 5 | #include "vector.h" 6 | #include "intercode.h" 7 | 8 | typedef struct Type_ *Type; 9 | struct Type_ 10 | { 11 | enum 12 | { 13 | basic, // for int variables and function return type int 14 | array, // for int array variables 15 | constant, // for const int variables 16 | constArray, // for const int array variables 17 | empty // for function return type void and combine type error 18 | } kind; 19 | // for array & constArray 20 | int size; 21 | }; 22 | 23 | struct paraItem //参数(变量、常量) 24 | { 25 | char name[16]; //参数名 26 | List type; //参数类型 27 | int *const_val; //常数组中的值,高维数组用一维数组存储 28 | int scope; //作用域层数 29 | Operand op; //对应的中间代码operand 30 | }; 31 | typedef struct paraItem *Para; 32 | 33 | struct funcItem //函数 34 | { 35 | char name[16]; 36 | int lineno; 37 | Type retType; //返回类型 38 | int paraNum; //参数的个数 39 | vector paraList; //参数表 40 | }; 41 | typedef struct funcItem *Func; 42 | 43 | struct attrInfo 44 | { 45 | int const_val; //常数表达式的值 46 | }; 47 | 48 | int sdtParse(treeNode *r); 49 | void initScopeTable(); 50 | void addScope(); 51 | void exitScope(); 52 | void printType(); 53 | void handleError(int no, int lineno); 54 | int checkReserveNames(char* name); 55 | Para querySymTable_para(char* name); 56 | int insertSymTable_para(Para r, int lineno); 57 | int sdtParseExp(treeNode *r, int isIdentConst, int flag, List list); 58 | int sdtParseLVal(treeNode *r, int isIdentConst, int flag, List list); 59 | int sdtParseNumber(treeNode *r); 60 | int sdtParsePrimaryExp(treeNode *r, int isIdentConst, int flag, List list); 61 | int sdtParseUnaryExp(treeNode *r, int isIdentConst, int flag, List list, int isCond); 62 | int sdtParseMulExp(treeNode *r, int isIdentConst, int flag, List list, int isCond); 63 | int sdtParseAddExp(treeNode *r, int isIdentConst, int flag, List list, int isCond); 64 | int sdtParseConstExp(treeNode *r); 65 | void sdtParseConstDecl(treeNode *r); 66 | void sdtParseConstExp_rep(treeNode *r, List *type); 67 | treeNode* getNextToken(treeNode *r); 68 | int getArraySize(int* a, int index, int size); 69 | void getArrayDimList(int *a, Para para); 70 | treeNode* sdtParseConstInitVal_Array(treeNode *r, Para *para, int* a, int arrayDim, int index, int paraCount, int* numCount, int numCountLim); 71 | void sdtParseConstInitVal(treeNode *r, Para *para); 72 | void sdtParseConstDef(treeNode *r); 73 | void sdtParseComConstDef_rep(treeNode* r); 74 | 75 | void sdtParseVarDecl(treeNode *r); 76 | void sdtParseVarDef(treeNode *r); 77 | void sdtParseComVarDef_rep(treeNode *r); 78 | void sdtParseInitVal(treeNode *r, Para *para); 79 | treeNode* sdtParseInitVal_Array(treeNode *r, Para *para, int* a, int arrayDim, int index, int paraCount, int* numCount, int numCountLim); 80 | void sdtParseDecl(treeNode *r); 81 | 82 | Func querySymTable_func(char* name); 83 | int insertSymTable_func(Func r, int lineno); 84 | 85 | void sdtParseFuncDef(treeNode *r); 86 | void sdtParseLbEXPRb_rep(treeNode *r, List *type); 87 | vector sdtParseFuncFParams(treeNode *r); 88 | void sdtParseComFuncFParam_rep(treeNode *r, vector paraList); 89 | void sdtParseFuncFParam(treeNode *r, vector paraList); 90 | void sdtParseBlock(treeNode *r, int flag, int noAdd); 91 | void sdtParseBlockItem_rep(treeNode *r, int flag); 92 | void sdtParseBlockItem(treeNode *r, int flag); 93 | void sdtParseStmt(treeNode *r, int flag); 94 | 95 | void sdtParseFuncRParams(treeNode* r, vector paraList); 96 | 97 | int sdtParseCond(treeNode *r); 98 | int sdtParseLOrExp(treeNode *r); 99 | int sdtParseLAndExp(treeNode *r); 100 | int sdtParseEqExp(treeNode *r); 101 | int sdtParseRelExp(treeNode *r); 102 | 103 | int para_exist(char *name, int scope); 104 | 105 | #endif -------------------------------------------------------------------------------- /syntax: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/syntax -------------------------------------------------------------------------------- /syntax.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.syntax 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | 1 19 | 20 | 21 | -------------------------------------------------------------------------------- /syntax.dSYM/Contents/Resources/DWARF/syntax: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/syntax.dSYM/Contents/Resources/DWARF/syntax -------------------------------------------------------------------------------- /syntax.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include 5 | #include "node.h" 6 | #include "syntax.tab.h" 7 | %} 8 | octal_const 0[0-7]* 9 | decimal_const [1-9][0-9]* 10 | hexadecimal_const (0x|0X)[0-9A-F]+ 11 | %option yylineno 12 | %option noyywrap 13 | %% 14 | 15 | [ \t\n] { } 16 | ";" { yylval.node = newNodeOp("SEMI"); return SEMI; } 17 | "," { yylval.node = newNodeOp("COMMA"); return COMMA; } 18 | "<=" { yylval.node = newNodeString("LTE","<="); return LTE; } 19 | ">=" { yylval.node = newNodeString("GTE",">=");return GTE; } 20 | "==" { yylval.node = newNodeString("EQ","==");return EQ; } 21 | "!=" { yylval.node = newNodeString("NEQ","!="); return NEQ; } 22 | "=" { yylval.node = newNodeOp("ASSIGNOP"); return ASSIGNOP; } 23 | "<" { yylval.node = newNodeString("LT","<"); return LT; } 24 | ">" { yylval.node = newNodeString("GT",">"); return GT; } 25 | "!" { yylval.node = newNodeOp("NOT"); return NOT; } 26 | "+" { yylval.node = newNodeOp("PLUS"); return PLUS; } 27 | "-" { yylval.node = newNodeOp("MINUS"); return MINUS; } 28 | "*" { yylval.node = newNodeOp("STAR"); return STAR; } 29 | "/" { yylval.node = newNodeOp("DIV"); return DIV; } 30 | "%" { yylval.node = newNodeOp("PERCENT"); return PERCENT; } 31 | "(" { yylval.node = newNodeOp("LP"); return LP; } 32 | ")" { yylval.node = newNodeOp("RP"); return RP; } 33 | "[" { yylval.node = newNodeOp("LB"); return LB; } 34 | "]" { yylval.node = newNodeOp("RB"); return RB; } 35 | "{" { yylval.node = newNodeOp("LC"); return LC; } 36 | "}" { yylval.node = newNodeOp("RC"); return RC; } 37 | "&&" { yylval.node = newNodeOp("AND"); return AND; } 38 | "||" { yylval.node = newNodeOp("OR"); return OR; } 39 | 40 | "return" { yylval.node = newNodeOp("RETURN"); return RETURN; } 41 | "const" { yylval.node = newNodeOp("CONST"); return CONST; } 42 | "else" { yylval.node = newNodeOp("ELSE"); return ELSE; } 43 | "if" { yylval.node = newNodeOp("IF"); return IF; } 44 | "while" { yylval.node = newNodeOp("WHILE"); return WHILE; } 45 | "void" { yylval.node = newNodeOp("VOID"); return VOID; } 46 | "break" { yylval.node = newNodeOp("BREAK"); return BREAK; } 47 | "continue" { yylval.node = newNodeOp("CONTINUE"); return CONTINUE; } 48 | "int" { yylval.node = newNodeOp("INT"); return INT; } 49 | 50 | [a-zA-Z_][a-zA-Z0-9_]* { 51 | yylval.node = newNodeString("ID", yytext); 52 | return ID; 53 | } 54 | {octal_const} { 55 | int itmp; double tmp; 56 | sscanf(yytext, "%o", &itmp); 57 | yylval.node = newNodeInt("INTCONST", itmp); 58 | return INTCONST; 59 | } 60 | 61 | {decimal_const} { 62 | int itmp; double tmp; 63 | sscanf(yytext, "%d", &itmp); 64 | yylval.node = newNodeInt("INTCONST", itmp); 65 | return INTCONST; 66 | } 67 | 68 | {hexadecimal_const} { 69 | int itmp; double tmp; 70 | sscanf(yytext, "%x", &itmp); 71 | yylval.node = newNodeInt("INTCONST", itmp); 72 | return INTCONST; 73 | } 74 | 75 | "//".* { /* Single line comment. DO NOTHING */} 76 | [/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] { /* Multiline comment DO NOTHING */ } 77 | [/][*] { perror("fatal_error"); } 78 | 79 | 80 | . { 81 | // error 82 | } 83 | %% 84 | 85 | -------------------------------------------------------------------------------- /syntax.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "node.h" 3 | #include "symtable.h" 4 | #include "intercode.h" 5 | #include "codegen.h" 6 | // #include "lex.yy.c" 7 | treeNode* root; 8 | extern int yylineno; 9 | int yylex(void); 10 | int yyerror(char* msg); 11 | int yyrestart(FILE* f); 12 | %} 13 | 14 | /*types*/ 15 | %union { 16 | int type_int; /* Constant integer value */ 17 | treeNode* node; 18 | }; 19 | 20 | //tokens 21 | %token INT ID SEMI COMMA ASSIGNOP LT GT LTE GTE EQ NEQ PLUS MINUS STAR DIV PERCENT 22 | %token AND OR NOT LP RP LB RB LC RC RETURN IF ELSE WHILE 23 | //int id ; , = < > <= >= == != + - * / % 24 | //&& || ! ( ) [ ] { } return if else while 25 | %token CONST VOID BREAK CONTINUE INTCONST 26 | //const void break continue intconst? 27 | 28 | //association 29 | %right ASSIGNOP 30 | %left OR AND LT GT LTE GTE EQ NEQ 31 | %left PLUS MINUS STAR DIV PERCENT 32 | %right NOT 33 | %left LB RB LP RP 34 | 35 | //noassociation 36 | %nonassoc ELSE 37 | %nonassoc RETURN WHILE 38 | 39 | //non-terminal 40 | %type CompUnit Decl FuncDef ConstDecl VarDecl 41 | %type ConstDef ConstInitVal ConstExp 42 | %type InitVal Exp FuncType FuncFParams Block FuncFParam 43 | %type BlockItem Stmt LVal Cond AddExp LOrExp Number 44 | %type UnaryExp PrimaryExp UnaryOp FuncRParams 45 | %type MulExp RelExp EqExp LAndExp 46 | 47 | %type ComConstDef_rep ConstExp_rep ComVarDef_rep VarDef 48 | %type ComInitVal_rep ComFuncFParam_rep LbEXPRb_rep 49 | %type BlockItem_rep Exp_rep comExp_rep ComConstInitVal_rep 50 | 51 | %% 52 | 53 | CompUnit : CompUnit Decl {$$=newNodeOp("CompUnit");root = $$;addChild($$,$2);addChild($$,$1);} 54 | | CompUnit FuncDef {$$=newNodeOp("CompUnit");root = $$;addChild($$,$2);addChild($$,$1);} 55 | | Decl {$$=newNodeOp("CompUnit");root = $$;addChild($$,$1);} 56 | | FuncDef {$$=newNodeOp("CompUnit");addChild($$,$1);root = $$;} 57 | ; 58 | //ok 59 | 60 | Decl : ConstDecl {$$=newNodeString("Decl","");addChild($$,$1);} 61 | | VarDecl {$$=newNodeString("Decl","");addChild($$,$1);} 62 | ; 63 | //ok 64 | 65 | ConstDecl : CONST FuncType ConstDef ComConstDef_rep SEMI {$$=newNodeOp("ConstDecl");addChild($$,$5);addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 66 | ; 67 | ComConstDef_rep : ComConstDef_rep COMMA ConstDef {$$=newNodeOp("ComConstDef_rep");addChild($$,$3);addChild($$,$2),addChild($$,$1);} 68 | | /*empty*/ {$$=newNodeOp("ComConstDef_rep");addChild($$,NULL);} 69 | ; 70 | //ok 71 | 72 | ConstDef : ID ConstExp_rep ASSIGNOP ConstInitVal {$$=newNodeOp("ConstDef");addChild($$,$4);addChild($$,$3);addChild($$, $2);addChild($$,$1);} 73 | ; 74 | ConstExp_rep : ConstExp_rep LB ConstExp RB {$$=newNodeOp("ConstExp_rep");addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 75 | | /* empty */ {$$=newNodeOp("ConstExp_rep");addChild($$, NULL);} 76 | ; 77 | //ok 78 | 79 | ConstInitVal : ConstExp {$$=newNodeOp("ConstInitVal");addChild($$,$1);} 80 | | LC ConstInitVal ComConstInitVal_rep RC {$$=newNodeOp("ConstInitVal");addChild($$,$4),addChild($$,$3);addChild($$,$2);addChild($$,$1);} 81 | | LC RC {$$=newNodeOp("ConstInitVal");addChild($$,$2);addChild($$,$1);} 82 | ; 83 | ComConstInitVal_rep : ComConstInitVal_rep COMMA ConstInitVal {$$=newNodeOp("ComConstInitVal_rep");addChild($$,$3);addChild($$,$2),addChild($$,$1);} 84 | | /*empty*/ {$$=newNodeOp("ComConstInitVal_rep");addChild($$, NULL);} 85 | ; 86 | //ok 87 | 88 | //VarDecl : 89 | VarDecl : FuncType VarDef ComVarDef_rep SEMI {$$=newNodeOp("VarDecl");addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 90 | ComVarDef_rep : ComVarDef_rep COMMA VarDef {$$=newNodeOp("ComVarDef_rep");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 91 | | /*empty*/ {$$=newNodeOp("ComVarDef_rep");addChild($$, NULL);} 92 | ; 93 | //ok 94 | 95 | VarDef : ID ConstExp_rep {$$=newNodeOp("VarDef");addChild($$,$2);addChild($$,$1);} 96 | | ID ConstExp_rep ASSIGNOP InitVal {$$=newNodeOp("VarDef");addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 97 | 98 | InitVal : Exp {$$=newNodeOp("InitVal");addChild($$,$1);} 99 | | LC InitVal ComInitVal_rep RC {$$=newNodeOp("InitVal");addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 100 | | LC RC {$$=newNodeOp("InitVal");addChild($$,$2);addChild($$,$1);} 101 | ; 102 | ComInitVal_rep : ComInitVal_rep COMMA InitVal {$$=newNodeOp("ComInitVal_rep");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 103 | | /*empty*/ {$$=newNodeOp("ComInitVal_rep");addChild($$, NULL);} 104 | //ok 105 | 106 | FuncDef : FuncType ID LP FuncFParams RP Block {$$=newNodeOp("FuncDef");addChild($$,$6);addChild($$,$5);addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 107 | | FuncType ID LP RP Block {$$=newNodeOp("FuncDef");addChild($$,$5);addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 108 | ; 109 | //ok 110 | 111 | FuncType : VOID {$$=newNodeOp("FuncType");addChild($$,$1);} 112 | | INT {$$=newNodeOp("FuncType");addChild($$,$1);} 113 | 114 | FuncFParams : FuncFParam ComFuncFParam_rep {$$=newNodeOp("FuncFParams");addChild($$,$2);addChild($$,$1);} 115 | ; 116 | ComFuncFParam_rep : ComFuncFParam_rep COMMA FuncFParam {$$=newNodeOp("ComFuncFParam_rep");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 117 | | /*empty*/ {$$=newNodeOp("ComFuncFParam_rep");addChild($$, NULL);} 118 | ; 119 | //ok 120 | 121 | FuncFParam : FuncType ID {$$=newNodeOp("FuncFParam");addChild($$,$2);addChild($$,$1);} 122 | | FuncType ID LB RB LbEXPRb_rep {$$=newNodeOp("FuncFParam");addChild($$,$5);addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 123 | ; 124 | LbEXPRb_rep : LbEXPRb_rep LB Exp RB {$$=newNodeOp("LbEXPRb_rep");addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 125 | | /*empty*/ {$$=newNodeOp("LbEXPRb_rep");addChild($$, NULL);} 126 | ; 127 | //ok 128 | 129 | Block : LC BlockItem_rep RC {$$=newNodeOp("Block");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 130 | ; 131 | BlockItem_rep : BlockItem_rep BlockItem {$$=newNodeOp("BlockItem_rep");addChild($$,$2);addChild($$,$1);} 132 | | /*empty*/ {$$=newNodeOp("BlockItem_rep");addChild($$, NULL);} 133 | ; 134 | //ok 135 | 136 | BlockItem : Decl {$$=newNodeOp("BlockItem");addChild($$,$1);} 137 | | Stmt {$$=newNodeOp("BlockItem");addChild($$,$1);} 138 | ; 139 | //ok 140 | 141 | Stmt : LVal ASSIGNOP Exp SEMI {$$=newNodeOp("Stmt");addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 142 | | Exp SEMI {$$=newNodeOp("Stmt");addChild($$,$2);addChild($$,$1);} 143 | | SEMI {$$=newNodeOp("Stmt");addChild($$,$1);} 144 | | Block {$$=newNodeOp("Stmt");addChild($$,$1);} 145 | | IF LP Cond RP Stmt ELSE Stmt {$$=newNodeOp("Stmt");addChild($$,$7);addChild($$,$6);addChild($$,$5);addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 146 | | IF LP Cond RP Stmt {$$=newNodeOp("Stmt");addChild($$,$5);addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 147 | | WHILE LP Cond RP Stmt {$$=newNodeOp("Stmt");addChild($$,$5);addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 148 | | BREAK SEMI {$$=newNodeOp("Stmt");addChild($$,$2);addChild($$,$1);} 149 | | CONTINUE SEMI {$$=newNodeOp("Stmt");addChild($$,$2);addChild($$,$1);} 150 | | RETURN Exp SEMI {$$=newNodeOp("Stmt");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 151 | | RETURN SEMI {$$=newNodeOp("Stmt");addChild($$,$2);addChild($$,$1);} 152 | ; 153 | //ok 154 | 155 | Exp : AddExp {$$=newNodeOp("Exp");addChild($$,$1);} 156 | ; 157 | //ok 158 | 159 | Cond : LOrExp {$$=newNodeOp("Cond");addChild($$,$1);} 160 | ; 161 | 162 | LVal : ID Exp_rep {$$=newNodeOp("LVal");addChild($$,$2);addChild($$,$1);} 163 | ; 164 | Exp_rep : Exp_rep LB Exp RB {$$=newNodeOp("Exp_rep");addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 165 | | /*empty*/ {$$=newNodeOp("Exp_rep");addChild($$, NULL);} 166 | ; 167 | 168 | PrimaryExp : LP Exp RP {$$=newNodeOp("PrimaryExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 169 | | LVal {$$=newNodeOp("PrimaryExp");addChild($$,$1);} 170 | | Number {$$=newNodeOp("PrimaryExp");addChild($$,$1);} 171 | ; 172 | 173 | Number : INTCONST {$$=newNodeOp("Number");addChild($$,$1);} 174 | ; 175 | 176 | UnaryExp : PrimaryExp {$$=newNodeOp("UnaryExp");addChild($$,$1);} 177 | | ID LP FuncRParams RP {$$=newNodeOp("UnaryExp");addChild($$,$4);addChild($$,$3);addChild($$,$2);addChild($$,$1);} 178 | | ID LP RP {$$=newNodeOp("UnaryExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 179 | | UnaryOp UnaryExp {$$=newNodeOp("UnaryExp");addChild($$,$2);addChild($$,$1);} 180 | ; 181 | //ok 182 | 183 | UnaryOp : PLUS {$$=newNodeOp("UnaryOp");addChild($$,$1);} 184 | | MINUS {$$=newNodeOp("UnaryOp");addChild($$,$1);} 185 | | NOT {$$=newNodeOp("UnaryOp");addChild($$,$1);} 186 | ; 187 | 188 | FuncRParams : Exp comExp_rep {$$=newNodeOp("FuncRParams");addChild($$,$2);addChild($$,$1);} 189 | ; 190 | comExp_rep : comExp_rep COMMA Exp {$$=newNodeOp("comExp_rep");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 191 | | /*empty*/ {$$=newNodeOp("comExp_rep");addChild($$, NULL);} 192 | ; 193 | 194 | 195 | MulExp : UnaryExp {$$=newNodeOp("MulExp");addChild($$,$1);} 196 | | MulExp STAR UnaryExp {$$=newNodeOp("MulExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 197 | | MulExp DIV UnaryExp {$$=newNodeOp("MulExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 198 | | MulExp PERCENT UnaryExp {$$=newNodeOp("MulExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 199 | ; 200 | 201 | AddExp : MulExp {$$=newNodeOp("AddExp");addChild($$,$1);} 202 | | AddExp PLUS MulExp {$$=newNodeOp("AddExp");addChild($$,$3);addChild($$,$2),addChild($$,$1);} 203 | | AddExp MINUS MulExp {$$=newNodeOp("AddExp");addChild($$,$3);addChild($$,$2),addChild($$,$1);} 204 | ; 205 | 206 | RelExp : AddExp {$$=newNodeOp("RelExp");addChild($$,$1);} 207 | | RelExp LT AddExp {$$=newNodeOp("RelExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 208 | | RelExp GT AddExp {$$=newNodeOp("RelExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 209 | | RelExp LTE AddExp {$$=newNodeOp("RelExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 210 | | RelExp GTE AddExp {$$=newNodeOp("RelExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 211 | ; 212 | 213 | EqExp : RelExp {$$=newNodeOp("EqExp");addChild($$,$1);} 214 | | EqExp EQ RelExp {$$=newNodeOp("EqExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 215 | | EqExp NEQ RelExp {$$=newNodeOp("EqExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 216 | ; 217 | 218 | LAndExp : EqExp {$$=newNodeOp("LAndExp");addChild($$,$1);} 219 | | LAndExp AND EqExp {$$=newNodeOp("LAndExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 220 | ; 221 | LOrExp : LAndExp {$$=newNodeOp("LOrExp");addChild($$,$1);} 222 | | LOrExp OR LAndExp {$$=newNodeOp("LOrExp");addChild($$,$3);addChild($$,$2);addChild($$,$1);} 223 | ; 224 | ConstExp : AddExp {$$=newNodeOp("ConstExp");addChild($$,$1);} 225 | ; 226 | 227 | %% 228 | 229 | int main(int argc, char** argv) 230 | { 231 | root=NULL; 232 | yylineno=1; 233 | // yyrestart(f); 234 | yyparse(); 235 | printTree(root,0); 236 | int errcnt = sdtParse(root); 237 | if (errcnt == 0) { 238 | printf("------------------IR INFO-------------------\n"); 239 | CodeList cl = translate_InterCode(root, NULL); 240 | printf("------------------CODEGEN INFO--------------\n"); 241 | codegen(cl); 242 | } 243 | return 0; 244 | } 245 | 246 | int yyerror(char* msg) 247 | { 248 | printf("Error type B at line %d:%s===>unexpected near '%s'\n",yylineno,msg,yylval.node->value); 249 | } -------------------------------------------------------------------------------- /testCase/README.md: -------------------------------------------------------------------------------- 1 | test cases 2 | 3 | 4 | 5 | ## Lexic and Syntatic tests 6 | 7 | test1.c 8 | 9 | ```C 10 | const int a = 2; // global const variable declaration 11 | 12 | int aaa; // global variable declaration 13 | int bbb = 100; // global variable declaration with initial value 14 | 15 | 16 | // global void function declaration 17 | int abc() { 18 | return 123; 19 | } 20 | 21 | // global int functino declaration 22 | void gcd() { 23 | int b; // local variable declaration 24 | int a = 1; // local variable declaration with initial value 25 | const int c = 1; // const local variable declaration with initial value 26 | 27 | int arr[4] = {1,1,2,5}; 28 | // const brr[4] = {1,2,3,4}; //? zsh: illegal hardware instruction 29 | } 30 | 31 | //? zsh: illegal hardware instruction 32 | // void avg(int a, int b) 33 | // { 34 | // //int c = a + b; 35 | // } 36 | int main() { 37 | int a = 1; 38 | // blocks 39 | { 40 | int a = 1; // nested variable 41 | int b = 1; 42 | // while expression. logical and relational expressions allowed 43 | while(a == b) 44 | { 45 | a = a+1; 46 | // if expression 47 | if( a == 100) 48 | { 49 | break; 50 | } 51 | } 52 | } 53 | int c = a + 1; // variable expression assignment 54 | int x3 = 0x10; // hexadecimal prefix 55 | int y3 = 0777; // octal digit 56 | } 57 | ``` 58 | 59 | error in declaring: const brr[4] = {1,2,3,4}; 60 | 61 | error in declaring: 62 | 63 | void avg(int a, int b) 64 | { 65 | 66 | ​ int c = a + b; 67 | } 68 | 69 | // problems to be fixed 70 | 71 | 72 | 73 | ## Advanced Lexic and Syntatic tests 74 | 75 | 76 | 77 | ## Semantic test 78 | 79 | test3.c 80 | 81 | ```C 82 | // some semantic test cases 83 | int main() 84 | { 85 | int min = 0, max = -1, mid = -1; 86 | if(min == 0) { 87 | if (pos) pos = 0; // undeclared variable 88 | return 0; 89 | } 90 | else { 91 | if(max > 5) 92 | { 93 | return 0; 94 | } 95 | } 96 | 97 | while(max >= min) { 98 | mid = (max + min) / 2; 99 | max = max - 1; 100 | } 101 | return 50; 102 | 103 | } 104 | ``` 105 | 106 | semantic error: undeclared variable 107 | 108 | // to be continue. 109 | 110 | 111 | 112 | ## Advanced Semantic Test 113 | 114 | 115 | 116 | 117 | 118 | ## IR 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /testCase/lexTest/lexTest.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define TESTINFO(type,value) printf("LexToken(%s,%s,%d))\n",type,value,yylineno) 8 | 9 | %} 10 | octal_const 0[0-7]* 11 | decimal_const [1-9][0-9]* 12 | hexadecimal_const (0x|0X)[0-9A-F]+ 13 | %option yylineno 14 | %option noyywrap 15 | %% 16 | 17 | [ \t\n] { } 18 | ";" { TESTINFO("SEMI" , ";"); } 19 | "," { TESTINFO("COMMA" , ","); } 20 | "<=" { TESTINFO("LTE" , "<="); } 21 | ">=" { TESTINFO("GTE" , ">="); } 22 | "==" { TESTINFO("EQ" , "=="); } 23 | "!=" { TESTINFO("NEQ" , "!="); } 24 | "=" { TESTINFO("ASSIGNOP" , "=");} 25 | "<" { TESTINFO("LT" , "<"); } 26 | ">" { TESTINFO("GT" , ">"); } 27 | "!" { TESTINFO("NOT" , "!"); } 28 | "+" { TESTINFO("PLUS" , "+"); } 29 | "-" { TESTINFO("MINUS" , "-"); } 30 | "*" { TESTINFO("STAR" , "*"); } 31 | "/" { TESTINFO("DIV" , "/"); } 32 | "%" { TESTINFO("PERCENT" , "%"); } 33 | "(" { TESTINFO("LP" , "("); } 34 | ")" { TESTINFO("RP" , ")"); } 35 | "[" { TESTINFO("LB" , "["); } 36 | "]" { TESTINFO("RB" , "]"); } 37 | "{" { TESTINFO("LC" , "{"); } 38 | "}" { TESTINFO("RC" , "}"); } 39 | "&&" { TESTINFO("AND" , "&&"); } 40 | "||" { TESTINFO("OR" , "||"); } 41 | 42 | "return" { TESTINFO("RETURN","return"); } 43 | "const" { TESTINFO("CONST" ,"const"); } 44 | "else" { TESTINFO("ELSE" ,"else"); } 45 | "if" { TESTINFO("IF" ,"if"); } 46 | "while" { TESTINFO("WHILE" ,"while"); } 47 | "void" { TESTINFO("VOID" ,"void"); } 48 | "break" { TESTINFO("BREAK" ,"break");} 49 | "continue" { TESTINFO("CONTINUE" ,"continue");} 50 | "int" { TESTINFO("INT" ,"int"); } 51 | 52 | [a-zA-Z_][a-zA-Z0-9_]* { 53 | TESTINFO("ID" ,yytext); 54 | } 55 | {octal_const} { 56 | int itmp; double tmp; 57 | sscanf(yytext, "%o", &itmp); 58 | printf("LexToken(%s,%d,%d))\n","INTCONST",itmp,yylineno); 59 | } 60 | 61 | {decimal_const} { 62 | int itmp; double tmp; 63 | sscanf(yytext, "%d", &itmp); 64 | printf("LexToken(%s,%d,%d))\n","INTCONST",itmp,yylineno); 65 | } 66 | 67 | {hexadecimal_const} { 68 | int itmp; double tmp; 69 | sscanf(yytext, "%x", &itmp); 70 | printf("LexToken(%s,%d,%d))\n","INTCONST",itmp,yylineno); 71 | } 72 | 73 | "//".* { /* Single line comment. DO NOTHING */} 74 | [/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] { /* Multiline comment DO NOTHING */ } 75 | [/][*] { perror("fatal_error"); } 76 | 77 | 78 | . { 79 | // error 80 | } 81 | %% 82 | 83 | int main() { 84 | yylex(); 85 | } -------------------------------------------------------------------------------- /testCase/lexTest/lexTest.sh: -------------------------------------------------------------------------------- 1 | filePath=lexTest.txt 2 | if [ $# -eq 1 ]; then filePath=$1; fi 3 | flex lexTest.l 4 | gcc -o lextest -g ./lex.yy.c 5 | ./lextest < $filePath 6 | rm lex.yy.c -------------------------------------------------------------------------------- /testCase/lexTest/lexTest.txt: -------------------------------------------------------------------------------- 1 | // Keywords 2 | int void 3 | if else 4 | else if 5 | while 6 | continue 7 | break 8 | return 9 | const 10 | 11 | // Identifier 12 | IAmIdentifier 13 | I2 14 | Id_is 15 | It000 16 | 17 | // Constant 18 | 996 19 | 007 20 | 0x3E4 21 | 0X3E4 22 | 01744 23 | 24 | // Operator 25 | + - * / % 26 | < > <= >= == != 27 | && || ! 28 | = 29 | 30 | // Delimeters 31 | ( ) 32 | [ ] 33 | { } 34 | , ; 35 | -------------------------------------------------------------------------------- /testCase/lexTest/lextest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/testCase/lexTest/lextest -------------------------------------------------------------------------------- /testCase/syntaxRight.c: -------------------------------------------------------------------------------- 1 | /* 多行注释测试 */ 2 | /** 3 | * @file syntaxRight.c 4 | * @note 这个文件测试SysY语言的所有文法要素, 用于检查生成的文法分析器的正确性。 5 | * 最终的结果是能够正确解析该文件并输出语法书。有关测试内容在下面给出注释。 6 | */ 7 | /* CompUnit */ 8 | /* 全局声明 */ 9 | int a; 10 | /* 全局声明与定义初始化 */ 11 | int b = 0; 12 | 13 | /* 连续声明与定义初始化 */ 14 | int ch = 5, b = 1, e; 15 | /* 多维数组声明 */ 16 | int thisIsAnArray[19][20][21]; 17 | /* 常量的全局声明 */ 18 | const int aa = 2; 19 | const int brr[4] = {1,2,3,4}; 20 | const int a[2][2] = {{5}, 8, 9}; 21 | // 函数 1 22 | int main() { 23 | /* 局部变量声明与初始化 */ 24 | int i=0, j, t, controller = 1, condition = 0; 25 | /** 26 | * @note Statements, Control Flows, Scopes 27 | **/ 28 | /* 空循环 */ 29 | while (1); 30 | while (1) { } // 空语句块 31 | 32 | /* 嵌套循环 */ 33 | while ( 1 ) { 34 | while ( controller ) { 35 | controller = controller+1; 36 | /* If-else 语句 */ 37 | if ( controller < 10) 38 | continue; // continue语句 39 | else { 40 | /* 函数调用 */ 41 | HelloWorld(); 42 | break; // break语句 43 | } 44 | } 45 | 46 | } 47 | /* else 悬挂 */ 48 | if ( 1 ) 49 | if ( 2 ) i = 333; 50 | else i = 955; 51 | else if ( 3 ) i = 666; 52 | else i = 233; 53 | /* 语句块嵌套 */ 54 | t = -5; 55 | { int t = 6; 56 | { int t = 10; 57 | { int t = 0; 58 | t = t * 10; // 乘除加减模运算 + 赋值 59 | t = t / 10; 60 | t = t + 10; 61 | t = t - 10; 62 | t = t % 5; 63 | } 64 | } 65 | } 66 | /* 空 */ 67 | ;;;;;; 68 | /** 69 | * @note 表达式 70 | **/ 71 | 72 | /* 运算符 */ 73 | // 连续赋值 74 | j = a = t; 75 | 76 | // 逻辑运算 SysY语言中逻辑运算必须在Cond或while语句中 77 | if (1 && 2) { 78 | if (3 || 0) { 79 | // 比较运算符 80 | while( i !=0 && j >= 0 ) { 81 | i = i - 1; 82 | j = j - 1; 83 | } 84 | } 85 | } 86 | // 其他的比较运算符 87 | if (a > 2) 88 | if (a <10) 89 | if(a >= 5) 90 | if(a <= 8) 91 | a = 4; 92 | 93 | // 单目运算符 94 | thisIsAnArray[0][0][1] = max(1,2); 95 | thisIsAnArray[0][0][1]; 96 | !thisIsAnArray[0][0][1]; // 当然不参与赋值-都不会有实际输出 97 | -thisIsAnArray[0][0][1]; 98 | (thisIsAnArray[0][0][1]); 99 | !(3+4 * thisIsAnArray[0][0][1]); 100 | 101 | /* 运算符优先级 */ 102 | // SysY语言文法本身就体现了优先级和结合性 103 | if(0 && 1) { 104 | i = 0; 105 | } 106 | if (1 || 0) { 107 | i = 4 == 3 >= 2 - 1 * -1; 108 | } 109 | return 0; 110 | } 111 | /* Function 2, void Return Value, void Parameter */ 112 | /* 函数2 返回void 参数也是空*/ 113 | void HelloWorld() { 114 | /* 库函数调用-参见SysY运行时库 */ 115 | //printf("Hello, Nano C!"); 116 | 117 | /* 空返回 */ 118 | return; 119 | } 120 | /* 函数3 多个参数 有int类型返回值 */ 121 | int max(int a, int b) { 122 | // return exp 123 | return a; 124 | } 125 | -------------------------------------------------------------------------------- /testCase/test.c: -------------------------------------------------------------------------------- 1 | const int a[2][2] = {{5}, 8, 9}; 2 | // int main() { 3 | // int a = 1; 4 | // } 5 | 6 | -------------------------------------------------------------------------------- /testCase/test1.c: -------------------------------------------------------------------------------- 1 | const int a = 2; // global const variable declaration 2 | 3 | 4 | 5 | int aaa; // global variable declaration 6 | int bbb = 100; // global variable declaration with initial value 7 | 8 | 9 | // global void function declaration 10 | int abc() { 11 | return 123; 12 | } 13 | 14 | // global int functino declaration 15 | void gcd() { 16 | int b; // local variable declaration 17 | int a = 1; // local variable declaration with initial value 18 | const int c = 1; // const local variable declaration with initial value 19 | 20 | int arr[4] = {1,1,2,5}; 21 | // const brr[4] = {1,2,3,4}; //? zsh: illegal hardware instruction 22 | } 23 | 24 | //? zsh: illegal hardware instruction 25 | // void avg(int a, int b) 26 | // { 27 | // //int c = a + b; 28 | // } 29 | 30 | int main() { 31 | int a = 1; 32 | // blocks 33 | { 34 | int a = 1; // nested variable 35 | int b = 1; 36 | // while expression. logical and relational expressions allowed 37 | while(a == b) 38 | { 39 | a = a+1; 40 | // if expression 41 | if( a == 100) 42 | { 43 | break; 44 | } 45 | } 46 | } 47 | int c = a + 1; // variable expression assignment 48 | int x3 = 0x10; // hexadecimal prefix 49 | int y3 = 0777; // octal digit 50 | } 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /testCase/test2.c: -------------------------------------------------------------------------------- 1 | const int brr[4] = {1,2,3,4}; -------------------------------------------------------------------------------- /testCase/test3.c: -------------------------------------------------------------------------------- 1 | // some semantic test cases 2 | int main() 3 | { 4 | int min = 0, max = -1, mid = -1; 5 | if(min == 0) { 6 | if (pos) pos = 0; // undeclared variable 7 | return 0; 8 | } 9 | else { 10 | if(max > 5) 11 | { 12 | return 0; 13 | } 14 | } 15 | 16 | while(max >= min) { 17 | mid = (max + min) / 2; 18 | max = max - 1; 19 | } 20 | return 50; 21 | 22 | } -------------------------------------------------------------------------------- /testCase/test4.c: -------------------------------------------------------------------------------- 1 | // no syntactic problem 2 | int look_and_say(int x) { 3 | int _1[32], i = 0; 4 | int _2[64], j = 0, k = 0; 5 | int count = 0; 6 | 7 | if (x < 0) { 8 | x = x-1; 9 | } 10 | i = 0; 11 | while (x > 0) { 12 | _1[i] = lsd(x); // undeclared function 13 | x = x / 10; 14 | i = i+1; 15 | } 16 | i = i - 1; 17 | j = 0; 18 | while (i >= 0) { 19 | if (i == 0) { 20 | _2[j] = 1; 21 | _2[j+1] = _1[0]; 22 | j = j+2; 23 | i = -1; 24 | } else { 25 | count = 1; 26 | while (i > 0 && _1[i - 1] == _1[i]) { 27 | count = count + 1; 28 | i = i - 1; 29 | } 30 | _2[j] = count; 31 | _2[j + 1] = _1[i]; 32 | i = i - 1; 33 | j = j + 2; 34 | } 35 | } 36 | k = 0; 37 | while (k < j) { 38 | write(_2[k]); 39 | k = k + 1; 40 | } 41 | return 0; 42 | } -------------------------------------------------------------------------------- /testCase/test5.c: -------------------------------------------------------------------------------- 1 | /* 多行注释测试 */ 2 | /** 3 | * @file syntaxRight.c 4 | * @note 这个文件测试SysY语言的所有文法要素, 用于检查生成的文法分析器的正确性。 5 | * 最终的结果是能够正确解析该文件并输出语法书。有关测试内容在下面给出注释。 6 | */ 7 | /* CompUnit */ 8 | /* 全局声明 */ 9 | int a; 10 | /* 全局声明与定义初始化 */ 11 | int b = 0; 12 | 13 | /* 连续声明与定义初始化 */ 14 | int ch = 5, d = 1, e; 15 | /* 多维数组声明 */ 16 | int thisIsAnArray[19][20][21]; 17 | /* 常量的全局声明 */ 18 | const int aa = 2; 19 | const int brr[4] = {1,2,3,4}; 20 | const int z[2][2] = {{5}, 8, 9}; 21 | /* Function 2, void Return Value, void Parameter */ 22 | /* 函数2 返回void 参数也是空*/ 23 | void HelloWorld() { 24 | /* 库函数调用-参见SysY运行时库 */ 25 | //printf("Hello, SysY!"); 26 | 27 | /* 空返回 */ 28 | return; 29 | } 30 | /* 函数3 多个参数 有int类型返回值 */ 31 | int max(int a, int b) { 32 | // return exp 33 | return a; 34 | } 35 | // 函数 1 36 | int main() { 37 | /* 局部变量声明与初始化 */ 38 | int i=0, j, t, controller = 1, condition = 0; 39 | /** 40 | * @note Statements, Control Flows, Scopes 41 | **/ 42 | /* 空循环 */ 43 | while (1); 44 | while (1) { } // 空语句块 45 | 46 | /* 嵌套循环 */ 47 | while ( 1 ) { 48 | while ( controller ) { 49 | controller = controller+1; 50 | /* If-else 语句 */ 51 | if ( controller < 10) 52 | continue; // continue语句 53 | else { 54 | HelloWorld(); 55 | break; // break语句 56 | } 57 | } 58 | 59 | } 60 | /* else 悬挂 */ 61 | if ( 1 ) 62 | if ( 2 ) i = 333; 63 | else i = 955; 64 | else if ( 3 ) i = 666; 65 | else i = 233; 66 | /* 语句块嵌套 */ 67 | t = -5; 68 | { int t = 6; 69 | { int t = 10; 70 | { int t = 0; 71 | t = t * 10; // 乘除加减模运算 + 赋值 72 | t = t / 10; 73 | t = t + 10; 74 | t = t - 10; 75 | t = t % 5; 76 | } 77 | } 78 | } 79 | /* 空 */ 80 | ;;;;;; 81 | /** 82 | * @note 表达式 83 | **/ 84 | 85 | /* 运算符 */ 86 | 87 | // 逻辑运算 SysY语言中逻辑运算必须在Cond或while语句中 88 | if (1 && 2) { 89 | if (3 || 0) { 90 | // 比较运算符 91 | while( i !=0 && j >= 0 ) { 92 | i = i - 1; 93 | j = j - 1; 94 | } 95 | } 96 | } 97 | // 其他的比较运算符 98 | if (a > 2) 99 | if (a <10) 100 | if(a >= 5) 101 | if(a <= 8) 102 | a = 4; 103 | 104 | // 单目运算符 105 | thisIsAnArray[0][0][1] = max(1,2); 106 | thisIsAnArray[0][0][1]; 107 | -thisIsAnArray[0][0][1]; 108 | (thisIsAnArray[0][0][1]); 109 | (3+4 * thisIsAnArray[0][0][1]); 110 | 111 | /* 运算符优先级 */ 112 | // SysY语言文法本身就体现了优先级和结合性 113 | if(0 && 1) { 114 | i = 0; 115 | } 116 | if (1 || 0) { 117 | i = 2 - 1 * -1; 118 | } 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /testCase/test6.c: -------------------------------------------------------------------------------- 1 | 2 | /* 多维数组声明 */ 3 | int thisIsAnArray[19][20][21]; 4 | 5 | /* 函数3 多个参数 有int类型返回值 */ 6 | int max(int a, int b) { 7 | // return exp 8 | return a; 9 | } 10 | // 函数 1 11 | int main() { 12 | // 单目运算符 13 | thisIsAnArray[0][0][1] = max(1,2); 14 | 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /vector.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "vector.h" 7 | 8 | vector newVector() { 9 | vector v; 10 | NEW0(v); 11 | v -> size = 0; 12 | v -> max_size = 10; 13 | v -> data = (DataType *)malloc(v->max_size*sizeof(DataType)); 14 | memset(v->data, 0, 10); 15 | return v; 16 | } 17 | 18 | DataType getItem(vector v, int i) { 19 | return v->data[i]; 20 | } 21 | 22 | void addItem(vector v, DataType item) { 23 | DataType *ptr; 24 | if (v->size >= v->max_size) { 25 | v->max_size *= 2; 26 | ptr = (DataType *)malloc(v->max_size*sizeof(DataType)); 27 | for (int i = 0; i < v->size; i ++) { 28 | ptr[i] = v->data[i]; 29 | } 30 | free(v->data); 31 | v->data = ptr; 32 | } 33 | v->data[v->size] = item; 34 | v->size += 1; 35 | } 36 | 37 | int getSize(vector v) { 38 | return v->size; 39 | } 40 | 41 | int isEmpty(vector v) { 42 | if (v->size == 0) return 1; 43 | else return 0; 44 | } 45 | 46 | DataType getLastItem(vector v) { 47 | if (v->size == 0) return NULL; 48 | else return v->data[v->size - 1]; 49 | } 50 | 51 | void removeLastItem(vector v) { 52 | if (getLastItem(v) != NULL) { 53 | v->data[v->size - 1] = NULL; 54 | v->size -= 1; 55 | } 56 | } 57 | 58 | void destoryVector(vector v) { 59 | for (int i = 0; i < v->size; i ++) { 60 | v->data[i] = NULL; 61 | } 62 | free(v->data); 63 | free(v); 64 | } 65 | 66 | // test vector 67 | // int main() { 68 | // vector v = newVector(); 69 | // int a = 1; 70 | // int b = 2; 71 | // int c = 3; 72 | // addItem(v, &a); 73 | // addItem(v, &b); 74 | // addItem(v, &c); 75 | 76 | // printf("%d\n", *(int*)getLastItem(v)); 77 | // printf("%d\n", *(int*)getItem(v, 0)); 78 | // printf("%d\n", *(int*)getItem(v, 1)); 79 | // printf("%d\n", *(int*)getItem(v, 2)); 80 | // removeLastItem(v); 81 | // printf("%d\n", *(int*)getLastItem(v)); 82 | // destoryVector(v); 83 | // } -------------------------------------------------------------------------------- /vector.h: -------------------------------------------------------------------------------- 1 | #ifndef _VECTOR_H_ 2 | #define _VECTOR_H_ 3 | #define NEW(p) ((p) = malloc(sizeof *(p))) 4 | #define NEW0(p) memset(NEW(p), 0, sizeof *(p)) 5 | typedef void* DataType; 6 | 7 | typedef struct Vector{ 8 | DataType* data; 9 | int size; 10 | int max_size; 11 | } *vector; 12 | 13 | vector newVector(); 14 | DataType getItem(vector v, int i); 15 | void addItem(vector v, DataType item); 16 | int getSize(vector v); 17 | DataType getLastItem(vector v); 18 | void removeLastItem(vector v); 19 | void destoryVector(vector v); 20 | 21 | #endif -------------------------------------------------------------------------------- /visAST/ast.dot: -------------------------------------------------------------------------------- 1 | hellodigraph G { 2 | node[shape=rect] 3 | _0x7fe7f7406290[label=CompUnit] 4 | _0x7fe7f7406290 -> _0x7fe7f7406240 5 | _0x7fe7f7406240[label=FuncDef] 6 | _0x7fe7f7406240 -> _0x7fe7f7405980 7 | _0x7fe7f7406240 -> _0x7fe7f74059d0 8 | _0x7fe7f7406240 -> _0x7fe7f7405a20 9 | _0x7fe7f7406240 -> _0x7fe7f7405a70 10 | _0x7fe7f7406240 -> _0x7fe7f74061f0 11 | _0x7fe7f7405980[label=FuncType] 12 | _0x7fe7f7405980 -> _0x7fe7f7405930 13 | _0x7fe7f7405930[label=INT] 14 | _0x7fe7f74059d0[label=ID] 15 | _0x7fe7f7405a20[label=LP] 16 | _0x7fe7f7405a70[label=RP] 17 | _0x7fe7f74061f0[label=Block] 18 | _0x7fe7f74061f0 -> _0x7fe7f7405ac0 19 | _0x7fe7f74061f0 -> _0x7fe7f7406150 20 | _0x7fe7f74061f0 -> _0x7fe7f74061a0 21 | _0x7fe7f7405ac0[label=LC] 22 | _0x7fe7f7406150[label=BlockItem_rep] 23 | _0x7fe7f7406150 -> _0x7fe7f7405b10 24 | _0x7fe7f7406150 -> _0x7fe7f7406100 25 | _0x7fe7f7405b10[label=BlockItem_rep] 26 | _0x7fe7f7406100[label=BlockItem] 27 | _0x7fe7f7406100 -> _0x7fe7f74060b0 28 | _0x7fe7f74060b0[label=Decl] 29 | _0x7fe7f74060b0 -> _0x7fe7f7406060 30 | _0x7fe7f7406060[label=VarDecl] 31 | _0x7fe7f7406060 -> _0x7fe7f7405bb0 32 | _0x7fe7f7406060 -> _0x7fe7f7405fc0 33 | _0x7fe7f7406060 -> _0x7fe7f7406010 34 | _0x7fe7f7406060 -> _0x7fe7f7405e80 35 | _0x7fe7f7405bb0[label=FuncType] 36 | _0x7fe7f7405bb0 -> _0x7fe7f7405b60 37 | _0x7fe7f7405b60[label=INT] 38 | _0x7fe7f7405fc0[label=VarDef] 39 | _0x7fe7f7405fc0 -> _0x7fe7f7405c00 40 | _0x7fe7f7405fc0 -> _0x7fe7f7405c50 41 | _0x7fe7f7405fc0 -> _0x7fe7f7405ca0 42 | _0x7fe7f7405fc0 -> _0x7fe7f7405f70 43 | _0x7fe7f7405c00[label=ID] 44 | _0x7fe7f7405c50[label=ConstExp_rep] 45 | _0x7fe7f7405ca0[label=ASSIGNOP] 46 | _0x7fe7f7405f70[label=InitVal] 47 | _0x7fe7f7405f70 -> _0x7fe7f7405f20 48 | _0x7fe7f7405f20[label=Exp] 49 | _0x7fe7f7405f20 -> _0x7fe7f7405ed0 50 | _0x7fe7f7405ed0[label=AddExp] 51 | _0x7fe7f7405ed0 -> _0x7fe7f7405e30 52 | _0x7fe7f7405e30[label=MulExp] 53 | _0x7fe7f7405e30 -> _0x7fe7f7405de0 54 | _0x7fe7f7405de0[label=UnaryExp] 55 | _0x7fe7f7405de0 -> _0x7fe7f7405d90 56 | _0x7fe7f7405d90[label=PrimaryExp] 57 | _0x7fe7f7405d90 -> _0x7fe7f7405d40 58 | _0x7fe7f7405d40[label=Number] 59 | _0x7fe7f7405d40 -> _0x7fe7f7405cf0 60 | _0x7fe7f7405cf0[label=INTCONST] 61 | _0x7fe7f7406010[label=ComVarDef_rep] 62 | _0x7fe7f7405e80[label=SEMI] 63 | _0x7fe7f74061a0[label=RC] 64 | } -------------------------------------------------------------------------------- /visAST/visast.c: -------------------------------------------------------------------------------- 1 | #include"visast.h" 2 | // reference: http://tang3w.com/2015/02/01/抽象语法树的可视化.html 3 | /* 用法: 在编译时加入visast.c, 并传入构建好的语法树的根即调用COSStylePrintAstAsDot(root), 4 | * 之后会生成.dot文件, 用Graphviz进行解析即可 (需要下载Graphviz/在线解析网站https://dreampuf.github.io/GraphvizOnline/) 5 | */ 6 | char FILENAME[] = "./visAST/ast.dot"; 7 | 8 | void COSStylePrintAstNodes(treeNode* ast,FILE* f){ 9 | if (ast == NULL) return; 10 | fprintf(f,"_%p[label=%s]\n", ast, ast->name); 11 | treeNode* node = ast->child; 12 | 13 | vector children = newVector(); 14 | //treeNode* children[100]; 15 | int count = 0; 16 | while(node!=NULL) { 17 | fprintf(f,"_%p -> _%p\n", ast, node); 18 | //children[count++] = node; 19 | addItem(children,node); 20 | node = node->next; 21 | } 22 | //printf("vector size is: %d\n",getSize(children)); 23 | count = getSize(children); 24 | for(int i = 0; i < count; i++) { 25 | COSStylePrintAstNodes((treeNode*)getItem(children,i),f); 26 | } 27 | } 28 | 29 | void COSStylePrintAstAsDot(treeNode *ast) { 30 | FILE* f = fopen(FILENAME,"w"); 31 | fprintf(f,"hello"); 32 | fprintf(f,"digraph G {\n"); 33 | fprintf(f,"node[shape=rect]\n"); 34 | 35 | COSStylePrintAstNodes(ast,f); 36 | 37 | fprintf(f,"}"); 38 | fclose(f); 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /visAST/visast.h: -------------------------------------------------------------------------------- 1 | #ifndef VISAST_H_ 2 | #define VISAST_H_ 3 | #include "../node.h" 4 | #include "../vector.h" 5 | #include 6 | #include 7 | void COSStylePrintAstNodes(treeNode* ast,FILE* f); 8 | void COSStylePrintAstAsDot(treeNode *ast); 9 | #endif -------------------------------------------------------------------------------- /实验报告.assets/gitlab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/gitlab.png -------------------------------------------------------------------------------- /实验报告.assets/hash_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/hash_table.png -------------------------------------------------------------------------------- /实验报告.assets/hash_table_scope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/hash_table_scope.png -------------------------------------------------------------------------------- /实验报告.assets/image-20210615214000523.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/image-20210615214000523.png -------------------------------------------------------------------------------- /实验报告.assets/lex_test_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/lex_test_1.png -------------------------------------------------------------------------------- /实验报告.assets/lex_test_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/lex_test_2.png -------------------------------------------------------------------------------- /实验报告.assets/lex_test_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/lex_test_3.png -------------------------------------------------------------------------------- /实验报告.assets/lex_test_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/lex_test_4.png -------------------------------------------------------------------------------- /实验报告.assets/lex_test_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/lex_test_5.png -------------------------------------------------------------------------------- /实验报告.assets/result_ast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/result_ast.png -------------------------------------------------------------------------------- /实验报告.assets/result_ast_vis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/result_ast_vis.png -------------------------------------------------------------------------------- /实验报告.assets/sem_test1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/sem_test1.png -------------------------------------------------------------------------------- /实验报告.assets/sem_test2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/sem_test2.png -------------------------------------------------------------------------------- /实验报告.assets/sem_test3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/sem_test3.png -------------------------------------------------------------------------------- /实验报告.assets/sem_test4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/sem_test4.png -------------------------------------------------------------------------------- /实验报告.assets/sem_test5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/sem_test5.png -------------------------------------------------------------------------------- /实验报告.assets/sem_test6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/sem_test6.png -------------------------------------------------------------------------------- /实验报告.assets/type_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yifan-bao/Compiler-for-SysY/f4733737bc1de7856c5f5ee3df74933a54a4aa58/实验报告.assets/type_array.png -------------------------------------------------------------------------------- /实验报告.md: -------------------------------------------------------------------------------- 1 |
摘要
2 | 3 | SysY语言是C语言的一个子集。每个SysY程序的源码存储在一个扩展名为sy的文件中。该文件有且仅有一个名为main的主函数定义,还可以包含若干全局变量声明、常量声明和其他函数定义。SysY语言支持**int类型**和元素为int类型且按行优先存储的**多维数组类型**,其中int型整数为32位有符号数,**const**修饰符用于声明常量。 4 | 5 | SysY语言本身没有提供输入/输出(I/O)的语言构造,I/O是以运行时库方式提供,库函数可以在SysY程序中的函数内调用。部分SysY运行时库函数的参数类型**会超出**SysY支持的数据类型,如可以为字符串。SysY编译器能处理这种情况,将SysY程序中这样的参数正确地传递给SysY运行时库。 6 | 7 | 我们小组编写了一个SysY语言的编译器,能够实现SysY语言的词法分析、语法分析、语义分析、中间代码生成及优化等部分,我们的编译器能够根据给定的程序输入输出正确的中间代码。 8 | 9 | 10 | 11 | # SysY语言编译器 12 | 13 | 编译生成编译器: 14 | 15 | ```shell 16 | git clone https://gitlab.eduxiji.net/aison/mycompiler.git 17 | cd mycompiler 18 | make & make clean 19 | ``` 20 | 21 | 使用编译器(目前完成前端部分,输出结果为语法树、语义分析结果和中间代码生成结果) 22 | 23 | ```shell 24 | ./compiler_name < [input_file_path] 25 | ``` 26 | 27 | 例如 28 | 29 | ```c 30 | /* 多行注释测试 */ 31 | /** 32 | * @file syntaxRight.c 33 | * @note 这个文件测试SysY语言的所有文法要素, 用于检查生成的文法分析器的正确性。 34 | * 最终的结果是能够正确解析该文件并输出语法书。有关测试内容在下面给出注释。 35 | */ 36 | /* CompUnit */ 37 | /* 全局声明 */ 38 | int a; 39 | /* 全局声明与定义初始化 */ 40 | int b = 0; 41 | 42 | /* 连续声明与定义初始化 */ 43 | int ch = 5, d = 1, e; 44 | /* 多维数组声明 */ 45 | int thisIsAnArray[19][20][21]; 46 | /* 常量的全局声明 */ 47 | const int aa = 2; 48 | const int brr[4] = {1,2,3,4}; 49 | const int z[2][2] = {{5}, 8, 9}; 50 | /* Function 2, void Return Value, void Parameter */ 51 | /* 函数2 返回void 参数也是空*/ 52 | void HelloWorld() { 53 | /* 库函数调用-参见SysY运行时库 */ 54 | //printf("Hello, SysY!"); 55 | 56 | /* 空返回 */ 57 | return; 58 | } 59 | /* 函数3 多个参数 有int类型返回值 */ 60 | int max(int a, int b) { 61 | // return exp 62 | return a; 63 | } 64 | // 函数1 65 | int main() { 66 | /* 局部变量声明与初始化 */ 67 | int i=0, j, t, controller = 1, condition = 0; 68 | /** 69 | * @note Statements, Control Flows, Scopes 70 | **/ 71 | /* 空循环 */ 72 | while (1); 73 | while (1) { } // 空语句块 74 | 75 | /* 嵌套循环 */ 76 | while ( 1 ) { 77 | while ( controller ) { 78 | controller = controller+1; 79 | /* If-else 语句 */ 80 | if ( controller < 10) 81 | continue; // continue语句 82 | else { 83 | HelloWorld(); 84 | break; // break语句 85 | } 86 | } 87 | 88 | } 89 | /* else 悬挂 */ 90 | if ( 1 ) 91 | if ( 2 ) i = 333; 92 | else i = 955; 93 | else if ( 3 ) i = 666; 94 | else i = 233; 95 | /* 语句块嵌套 */ 96 | t = -5; 97 | { int t = 6; 98 | { int t = 10; 99 | { int t = 0; 100 | t = t * 10; // 乘除加减模运算 + 赋值 101 | t = t / 10; 102 | t = t + 10; 103 | t = t - 10; 104 | t = t % 5; 105 | } 106 | } 107 | } 108 | /* 空 */ 109 | ;;;;;; 110 | /** 111 | * @note 表达式 112 | **/ 113 | 114 | /* 运算符 */ 115 | 116 | // 逻辑运算 SysY语言中逻辑运算必须在Cond或while语句中 117 | if (1 && 2) { 118 | if (3 || 0) { 119 | // 比较运算符 120 | while( i !=0 && j >= 0 ) { 121 | i = i - 1; 122 | j = j - 1; 123 | } 124 | } 125 | } 126 | // 其他的比较运算符 127 | if (a > 2) 128 | if (a <10) 129 | if(a >= 5) 130 | if(a <= 8) 131 | a = 4; 132 | 133 | // 单目运算符 134 | thisIsAnArray[0][0][1] = max(1,2); 135 | thisIsAnArray[0][0][1]; 136 | -thisIsAnArray[0][0][1]; 137 | (thisIsAnArray[0][0][1]); 138 | (3+4 * thisIsAnArray[0][0][1]); 139 | 140 | /* 运算符优先级 */ 141 | // SysY语言文法本身就体现了优先级和结合性 142 | if(0 && 1) { 143 | i = 0; 144 | } 145 | if (1 || 0) { 146 | i = 2 - 1 * -1; 147 | } 148 | return 0; 149 | } 150 | 151 | ``` 152 | 153 | 154 | 155 | ## 第1章 词法分析 156 | 157 | ### 1.1 Token说明 158 | 159 | * Types:`int`,`void`,`const` 160 | * Control Flow:`if`,`else`,`while`,`continue`,`break` 161 | * Function:`return`,`{}`,`;` 162 | * Operators(按优先级): 163 | * `()`,`[]` :括号、下标运算符 164 | * `!`,`-` :逻辑非、负号运算符 165 | * `*`,`/`,`%`:乘法、除法、取余运算符 166 | * `+`,`-`:加法、减法运算符 167 | * `<`,`<=`,`>`,`>=`:关系运算符 168 | * `==`,`!=`:等于、不等于运算符(判断) 169 | * `&&`:逻辑与运算符 170 | * `||`:逻辑非运算符 171 | * `=`:赋值运算符 172 | * `,`:逗号运算符(把若干表达式组合成一个表达式) 173 | 174 | 175 | 176 | ### 1.2 Token定义 177 | 178 | Token如下: 179 | 180 | ```c 181 | // keywords 182 | %token RETURN IF ELSE WHILE CONST VOID BREAK CONTINUE INT 183 | 184 | // identifiers and numbers 185 | %token ID INTCONST 186 | 187 | // Operators 188 | %token LT GT LTE GTE EQ NEQ PLUS MINUS STAR DIV PERCENT 189 | %token AND OR NOT ASSIGNOP 190 | 191 | // Delimeters 192 | %token LP RP LB RB LC RC SEMI COMMA 193 | // ( ) [ ] { } ; , 194 | ``` 195 | 196 | 正则表达式定义: 197 | 198 | ```c 199 | // ID 200 | identifier = [a-zA-Z_][a-zA-Z0-9_]* 201 | 202 | // INTCONST 203 | octal_const = 0[0-7]* 204 | decimal_const = [1-9][0-9]* 205 | hexadecimal_const = (0x|0X)[0-9A-F]+ 206 | 207 | // Comment 208 | single_line_comment = "//".* 209 | multi_line_comment = [/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] 210 | ``` 211 | 212 | 213 | 214 | ### 1.3 Lex实现 215 | 216 | 我们使用Lex来实现词法分析。Lex源代码主要是一个由正则表达式和相应代码片段组成的表。Lex会将表转换为对应程序,以读取输入流,将输入划分为匹配正则表达式的字符串,并且识别出对应字符串后会执行相应程序片段。Lex是通过生成确定性有限自动机来进行表达式的识别,并且代码片段会按照输入流中出现的字符串对应表达式顺序执行。 217 | 218 | 考虑后续语法树的生成(详细内容在后文:抽象语法树的设计与实现中给出),在识别出对应的字符串之后,我们会新建并返回相应的结点。举例如下: 219 | 220 | ```c 221 | "+" { yylval.node = newNodeOp("PLUS"); return PLUS; } 222 | ``` 223 | 224 | 关键字、操作符和分界符的lex代码都与此类似,不再一一列出。 225 | 226 | 标识符(identifier)和实数(number)有所不同,除了返回对应类型的节点以外,它们还需要另外的操作,例如标识符需要返回标识符名称,实数需要返回对应的值。具体实现如下: 227 | 228 | ```c 229 | // identifier 230 | [a-zA-Z_][a-zA-Z0-9_]* { 231 | yylval.node = newNodeString("ID", yytext); 232 | return ID; 233 | } 234 | // numbers 235 | {octal_const} { 236 | int itmp; 237 | sscanf(yytext, "%o", &itmp); 238 | yylval.node = newNodeInt("INTCONST", itmp); 239 | return INTCONST; 240 | } 241 | {decimal_const} { 242 | int itmp; 243 | sscanf(yytext, "%d", &itmp); 244 | yylval.node = newNodeInt("INTCONST", itmp); 245 | return INTCONST; 246 | } 247 | {hexadecimal_const} { 248 | int itmp; 249 | sscanf(yytext, "%x", &itmp); 250 | yylval.node = newNodeInt("INTCONST", itmp); 251 | return INTCONST; 252 | } 253 | ``` 254 | 255 | 在遇到空白符或注释时则略过不执行操作。 256 | 257 | 258 | 259 | ## 第2章 SysY语言文法分析 260 | 261 | ### 2.1 SysY语言文法说明 262 | 263 | 首先,具体说明一下SysY语言的文法。 264 | 265 | SysY语言文法主要分为**四部分**,分别是**变量/常量声明**,**函数声明**,**语句**,**表达式**。文法的开始符号为CompUnit,表示编译单元。 266 | 267 | 下面具体展开分析 268 | 269 | **变量/常量声明**: 270 | 271 | * SysY语言可以在一个变量/常量声明语句中声明**多个**变量或常量 272 | * 声明时可以带**初始化**表达式 273 | * 所有变量/常量要求**先定义再使用** 274 | * 在函数外声明的为**全局变量/常量** 275 | * 在函数内声明的为**局部变量/常量** 276 | 277 | **函数**: 278 | 279 | * 函数可以**带参数**也可以**不带参数** 280 | * 参数的类型可以是**int**或者**数组类型** 281 | * 函数可以**返回int**类型的值,或者**不返回值**(即声明为void类型) 282 | * 当参数为**int时,按值传递**;而参数为**数组类型时,实际传递的是数组的起始地址**,并且**形参只有第一维可以空缺** 283 | * 函数内部由若干**变量声明和语句**组成 284 | 285 | **语句**: 286 | 287 | * 语句包括**赋值语句**、**表达式语句**(表达式可以为空)、**语句块**、**if语句**、**while语句**、**break语句**、**continue语句**、**return语句** 288 | * 语句块中可以包含若干变量声明和语句 289 | * 语句块应该由用两个大括号,即 `{`,`}` 包围在一起,这个语句块可以递归的包含其他语句 290 | 291 | **表达式**: 292 | 293 | * 支持基本的**算数运算**(+、-、*、/、%)、**关系运算**(==、!=、<、>、<=、>=)和**逻辑运算**(!、&&、||) 294 | * 非0表示真、0表示假 295 | * 关系运算或逻辑运算的结果用1表示真、0表示假。 296 | * **算符的优先级和结合性以及计算规则(含逻辑运算的“短路计算”)与C语言一致**。 297 | 298 | 以上所有支持的文法内容的表现均与C语言一致 299 | 300 | 301 | 302 | 下面是一些**典型**的SysY语言不支持的文法相关内容 303 | 304 | * *不支持*实现预处理例如**宏**和**include**,即*不能*使用 `#define` 或者`#include` 305 | 306 | * 不支持**多文件编译**,这是第一条直接导致的,因此只能使用*一个C源文件* 307 | 308 | * *不支持*函数**原型声明**(Function Prototype Declaration) 309 | * *不支持***指针** 310 | * *不支持***三元表达式**,例如不能使用`?:` 311 | 312 | 313 | 314 | ### 2.2 SysY语言文法BNF定义 315 | 316 | 比赛提供的文法为SysY语言的**EBNF**(Extended Backus-Naur Form)范式。由于我们使用的是Yacc来进行文法分析器的生成,而Yacc是LALR分析器的生成器,因此不直接支持EBNF。 317 | 318 | 实验采用如下方法将EBNF转换为BNF 319 | 320 | 1. 对于EBNF中的**可选部分(optional)**,将其展开。 321 | * 例如,CompUnit $$\rightarrow$$ [CompUnit] (Decl | FuncDef) 转换为 CompUnit $$\rightarrow$$ CompUnit Decl | CompUnit FuncDef | Decl | FuncDef 322 | 323 | 2. 对EBNF中的 **可重复0次或多次(repetition)** 的部分,通过增加一个左递归的产生式来解决 324 | * 例如,ConstDef $$\rightarrow$$ Ident { '[' ConstExp ']' } '=' ConstInitVal 转换为 ConstDef $$\rightarrow$$ Ident **ConstExp_rep** = ConstInitVal ; **ConstExp_rep** $$\rightarrow$$ ConstExp_rep '[' ConstExp ']' | $$\epsilon$$ 325 | 326 | 首先展示的是比赛中规定的SysY语言的**EBNF**范式,其中: 327 | 328 | * 符号[...]表示方括号内包含的为可选项 329 | 330 | * 符号{...}表示花括号内包含的为可重复0次或多次的项 331 | 332 | * 终结符或者是由单引号括起的串,或者是Ident、InstConst这样的记号。 333 | 334 | > ​ 编译单元 CompUnit $$\rightarrow$$ [CompUnit] (Decl | FuncDef) 335 | > 336 | > ​ 声明 Decl $$\rightarrow$$ ConstDecl | VarDecl 337 | > 338 | > ​ 常量声明 ConstDecl $$\rightarrow$$ '**const**' BType ConstDef {',' ConstDef} ';' 339 | > 340 | > ​ 基本类型 BType $$\rightarrow$$ '**int**' 341 | > 342 | > ​ 常数定义 ConstDef $$\rightarrow $$ **Ident** { '[' ConstExp ']' } '=' ConstInitVal 343 | > 344 | > ​ 常量初值 ConstInitVal $$\rightarrow$$ ConstExp 345 | > 346 | > ​ | '{' [ ConstInitVal { ',' ConstInitVal } ] '}' 347 | > 348 | > ​ 变量声明 VarDecl $$\rightarrow$$ BType VarDef { ',' VarDef } ';' 349 | > 350 | > ​ 变量定义 VarDef $$\rightarrow$$ **Ident** { '[' ConstExp ']' } 351 | > 352 | > ​ | **Ident** { '[' ConstExp ']' } '=' InitVal 353 | > 354 | > ​ 变量初值 InitVal $$\rightarrow$$ Exp | '{'[InitVal{','InitVal}]'}' 355 | > 356 | > ​ 函数定义 FuncDef $$\rightarrow$$ FuncType **Ident** '(' [FuncFParams] ')' Block 357 | > 358 | > ​ 函数类型 FuncType $$\rightarrow$$ '**void**' | '**int**' 359 | > 360 | > ​ 函数形参表 FuncFParams $$\rightarrow$$ FuncFParam { ',' FuncFParam } 361 | > 362 | > ​ 函数形参 FuncFParam $$\rightarrow$$ BType **Ident** ['[' ']' { '[' Exp ']' }] 363 | > 364 | > ​ 语句块 Block $$\rightarrow$$ '{' { BlockItem } '}' 365 | > 366 | > ​ 语句块项 BlockItem $$\rightarrow$$ Decl | Stmt 367 | > 368 | > ​ 语句 Stmt $$\rightarrow$$ LVal '=' Exp ';' | [Exp] ';' | Block 369 | > 370 | > ​ | 'if' '( Cond ')' Stmt [ 'else' Stmt ] 371 | > 372 | > ​ | 'while' '(' Cond ')' Stmt 373 | > 374 | > ​ | 'break' ';' | 'continue' ';' 375 | > 376 | > ​ | 'return' [Exp] ';' 377 | > 378 | > ​ 表达式 Exp $$\rightarrow$$ AddExp 注: SysY表达式是int型表达式 379 | > 380 | > ​ 条件表达式 Cond $$\rightarrow$$ LOrExp 381 | > 382 | > ​ 左值表达式 LVal $$\rightarrow$$ **Ident** {'[' Exp ']'} 383 | > 384 | > ​ 基本表达式 PrimaryExp $$\rightarrow$$ '(' Exp ')' | LVal | Number 385 | > 386 | > ​ 数值 Number $$\rightarrow$$ **IntConst** 387 | > 388 | > ​ 一元表达式 UnaryExp $$\rightarrow$$ PrimaryExp | **Ident** '(' [FuncRParams] ')' 389 | > 390 | > ​ | UnaryOp UnaryExp 391 | > 392 | > ​ 单目运算符 UnaryOp $$\rightarrow$$ '+' | '−' | '!' 注: '!' 仅出现在条件表达式中 393 | > 394 | > ​ 函数实参表 FuncRParams $$\rightarrow$$ Exp{','Exp} 395 | > 396 | > 乘除模表达式 MulExp $$\rightarrow$$ UnaryExp | MulExp ('*' | '/' | '%') UnaryExp 397 | > 398 | > ​ 加减表达式 AddExp $$\rightarrow$$ MulExp | AddExp ('+' | '−') MulExp 399 | > 400 | > ​ 关系表达式 RelExp $$\rightarrow$$ AddExp | RelExp ('<' | '>' | '<=' | '>=') AddExp 401 | > 402 | > 相等性表达式 EqExp $$\rightarrow$$ RelExp | EqExp ('==' | '!=') RelExp 403 | > 404 | > 逻辑与表达式 LAndExp $$\rightarrow$$ EqExp | LAndExp '&&' EqExp 405 | > 406 | > 逻辑或表达式 LOrExp $$\rightarrow$$ LAndExp | LOrExp '||' LAndExp 407 | > 408 | > ​ 常量表达式 ConstExp $$\rightarrow$$ AddExp 注: 使用的Ident必须是常量 409 | 410 | 411 | 412 | 下面展示的是实验中用到**经过修改转换的BNF文法产生式** 413 | 414 | ```C 415 | // 实验中使用到的BNF文法产生式 416 | CompUnit: CompUnit Decl 417 | | CompUnit FuncDef 418 | | Decl 419 | | FuncDef 420 | Decl : ConstDecl 421 | | VarDecl 422 | ConstDecl : CONST FuncType ConstDef ComConstDef_rep SEMI 423 | ComConstDef_rep : ComConstDef_rep COMMA ConstDef 424 | | /*empty*/ 425 | ConstDef : ID ConstExp_rep ASSIGNOP ConstInitVal 426 | ConstExp_rep : ConstExp_rep LB ConstExp RB 427 | | /* empty */ 428 | ConstInitVal : ConstExp 429 | | LC ConstInitVal ComConstInitVal_rep RC 430 | | LC RC 431 | ComConstInitVal_rep : ComConstInitVal_rep COMMA ConstInitVal 432 | | /*empty*/ 433 | VarDecl : FuncType VarDef ComVarDef_rep SEMI 434 | ComVarDef_rep : ComVarDef_rep COMMA VarDef 435 | | /*empty*/ 436 | VarDef : ID ConstExp_rep 437 | | ID ConstExp_rep ASSIGNOP InitVal 438 | InitVal : Exp 439 | | LC InitVal ComInitVal_rep RC 440 | | LC RC 441 | ComInitVal_rep : ComInitVal_rep COMMA InitVal 442 | | /*empty*/ 443 | FuncDef : FuncType ID LP FuncFParams RP Block 444 | | FuncType ID LP RP Block 445 | FuncType : VOID 446 | | INT 447 | FuncFParams : FuncFParam ComFuncFParam_rep 448 | ComFuncFParam_rep : ComFuncFParam_rep COMMA FuncFParam 449 | | /*empty*/ 450 | FuncFParam : FuncType ID 451 | | FuncType ID LB RB LbEXPRb_rep 452 | LbEXPRb_rep : LbEXPRb_rep LB Exp RB 453 | | /*empty*/ 454 | Block : LC BlockItem_rep RC 455 | BlockItem_rep : BlockItem_rep BlockItem 456 | | /*empty*/ 457 | BlockItem : Decl 458 | | Stmt 459 | 460 | Stmt : LVal ASSIGNOP Exp SEMI 461 | | Exp SEMI 462 | | SEMI 463 | | Block 464 | | IF LP Cond RP Stmt ELSE Stmt 465 | | IF LP Cond RP Stmt 466 | | WHILE LP Cond RP Stmt 467 | | BREAK SEMI 468 | | CONTINUE SEMI 469 | | RETURN Exp SEMI 470 | | RETURN SEMI 471 | Exp : AddExp 472 | Cond : LOrExp 473 | LVal : ID Exp_rep 474 | Exp_rep : Exp_rep LB Exp RB 475 | | /*empty*/ 476 | PrimaryExp : LP Exp RP 477 | | LVal 478 | | Number 479 | Number : INTCONST 480 | UnaryExp : PrimaryExp 481 | | ID LP FuncRParams RP 482 | | ID LP RP 483 | | UnaryOp UnaryExp 484 | UnaryOp : PLUS 485 | | MINUS 486 | | NOT 487 | FuncRParams : Exp comExp_rep 488 | comExp_rep : comExp_rep COMMA Exp 489 | | /*empty*/ 490 | 491 | MulExp : UnaryExp 492 | | MulExp STAR UnaryExp 493 | | MulExp DIV UnaryExp 494 | | MulExp PERCENT UnaryExp 495 | AddExp : MulExp 496 | | AddExp PLUS MulExp 497 | | AddExp MINUS MulExp 498 | 499 | RelExp : AddExp 500 | | RelExp LT AddExp 501 | | RelExp GT AddExp 502 | | RelExp LTE AddExp 503 | | RelExp GTE AddExp 504 | 505 | EqExp : RelExp 506 | | EqExp EQ RelExp 507 | | EqExp NEQ RelExp 508 | LAndExp : EqExp 509 | | LAndExp AND EqExp 510 | LOrExp : LAndExp 511 | | LOrExp OR LAndExp 512 | ConstExp : AddExp 513 | ``` 514 | 515 | 516 | 517 | ### 2.3 抽象语法树的设计与实现 518 | 519 | 在有了良好定义的文法后,下一步就是将其转换为良好组织的抽象语法树。抽象语法树将在编译器的后面阶段发挥重要作用。 520 | 521 | **抽象语法树结点设计** 522 | 523 | ```c 524 | typedef struct Node { 525 | int lineNo; 526 | char name[16]; 527 | char value[32]; 528 | int int_val; 529 | struct Node *child; 530 | struct Node *next; 531 | struct Node *father; // used in sdt parse 532 | }treeNode; 533 | ``` 534 | 535 | 其中lineNo用于记录语句的行号,name用于记录结点在产生式中的名字(对应的非终结符的名字),value用于记录ID(标识符,例如变量名、函数名等)的内容,int_val用于记录常量数值。 536 | 537 | 抽象语法树采用了左孩子右兄弟的构造方法。同时有记录父亲结点的指针,用于语义分析。 538 | 539 | 程序提供抽象语法树输出接口printTree(),该函数可以以缩进的形式打印构造好的抽象语法树。其示例输出如下: 540 | 541 | 源代码 542 | 543 | ```C 544 | int main() { 545 | int a = 1; 546 | } 547 | ``` 548 | 549 | 语法树输出结果 550 | 551 | result_ast 552 | 553 | 更加详细的内容将在**测试分析**中给出。 554 | 555 | 556 | 557 | ------ 558 | 559 | ## 第3章 语义分析 560 | 561 | 一段语法上正确的源代码仍然可能包含严重的逻辑错误,对编译器的后续工作产生影响,这是我们进行语义分析的原因。语义分析能够帮助我们处理三个方面的内容: 562 | 563 | * **上下文相关的内容**,例如变量使用前是否定义、一个函数内部定义的变量在另一个函数中是否允许使用。语法分析阶段的理论基础是上下文无关文法,因此无法处理这样的内容。 564 | * **类型检查**,检查输入程序中的各种行为是否是类型安全的。 565 | * **提供需要提前确定的信息**,例如函数要返回什么类型的值,需要接受多少个参数。 566 | 567 | 我们实现了符号表以支持语义分析,对语法树进行遍历并进行符号表的相关操作,以及类型的构造与检查。 568 | 569 | ### 3.1 数据结构 570 | 571 | 语义分析中的核心数据结构为符号表。在介绍符号表的具体实现之前,我们首先介绍类型、函数、参数数据结构的定义。 572 | 573 | #### 3.1.1 类型 574 | 575 | SysY语言只有一种基本数据类型:`int`。同时,SysY也支持`const`和多维数组,支持函数返回类型为`void`或者`int`。因此,基本类型`Type`定义如下所示: 576 | 577 | ```c 578 | typedef struct Type_ *Type; 579 | struct Type_ 580 | { 581 | enum 582 | { 583 | basic, // for int variables and function return type int 584 | array, // for int array variables 585 | constant, // for const int variables 586 | constArray, // for const int array variables 587 | empty // for function return type void and combine type error 588 | } kind; 589 | // for array & constArray 590 | int size; 591 | }; 592 | ``` 593 | 594 | 对于数组变量来说,例如定义`int a[2][3][4]`,仅靠一个`Type`显然无法确定具体的维度信息。因此,我们用一个线性链表`List`来表示参数(变量、常量)的类型,以a为例,表示如下: 595 | 596 | type_array 597 | 598 | 非数组参数也可以用线性链表表示,只是链表只有一项。因此在参数项中,参数类型是使用线性链表`List`来表示的。 599 | 600 | #### 3.1.2 参数 601 | 602 | 参数项`paraItem`定义如下,包含参数名称、参数类型、参数值、作用域层数、对应中间代码的`operand`。 603 | 604 | ```c 605 | struct paraItem //参数(变量、常量) 606 | { 607 | char name[16]; //参数名 608 | List type; //参数类型 609 | int *const_val; //常数组中的值,高维数组用一维数组存储 610 | int scope; //作用域层数 611 | Operand op; //对应的中间代码operand 612 | }; 613 | typedef struct paraItem *Para; 614 | ``` 615 | 616 | 由于参数有单一实数也有数组,参数值用`int *`实现,单一实数则直接指向对应值,数组统一用一维数组的形式存储。作用域层数和`operand`会分别在符号表、中间代码部分说明,此处不多赘述。 617 | 618 | #### 3.1.3 函数 619 | 620 | SysY语言的函数定义与c语言类似,但返回类型限制在`void`和`int`,所以用基本类型就能表示。函数项`funcItem`定义如下,包含函数名称、所在行号、返回类型、参数个数和形参表。 621 | 622 | ```c 623 | struct funcItem //函数 624 | { 625 | char name[16]; 626 | int lineno; 627 | Type retType; //返回类型 628 | int paraNum; //参数的个数 629 | vector paraList; //形参表 630 | }; 631 | typedef struct funcItem *Func; 632 | ``` 633 | 634 | #### 3.1.4 符号表 635 | 636 | 我们分别建立两个符号表:参数表和函数表。前者用于存储所有定义的变量和常量,后者用于存储所有定义的函数,其中参数表的实现支持了多层**作用域**。符号表的主要结构用**哈希表**实现,我们定义了自己的hash函数,当哈希表出现冲突的时候,通过在相应数组元素下面挂一个链表的方式解决。 637 | 638 | 自定义hash函数如下所示: 639 | 640 | ```c 641 | int myHash(char *key) //自定义hash函数 642 | { 643 | int res = 0, p = 1, i; 644 | for (i = 0; i < strlen(key); i++) 645 | { 646 | res = (res + key[i] * p % HT_SIZE) % HT_SIZE; 647 | p = p * HT_SEED % HT_SIZE; 648 | } 649 | return res; 650 | } 651 | ``` 652 | 653 | 在实际应用中,每次查询符号表要匹配的是最近出现过的同名符号,因此每次插入元素会插在链表的开头。哈希表结构如下所示: 654 | 655 | hash_table 656 | 657 | 函数表用此结构即可,参数表还需要实现作用域,在后文详细阐述。 658 | 659 | ##### 3.1.4.1 函数表 660 | 661 | 函数表的主要用途有两点: 662 | 663 | * 函数声明时,检查函数名是否定义过或者与关键字重复,如果没有,则将新函数插入函数表,否则报错; 664 | * 函数调用时,检查函数名是否定义过,如果有,返回相应的`Func`结构,否则报错。 665 | 666 | 定义函数表如下: 667 | 668 | ```c 669 | List funcTable[HT_SIZE]; 670 | ``` 671 | 672 | 由上面的用途可以看出,函数表主要涉及查询和插入。实现对应接口如下: 673 | 674 | ```c 675 | Func querySymTable_func(char* name); // 查询到对应函数则返回对应Func,否则返回NULL 676 | int insertSymTable_func(Func r); // 成功插入函数返回0,否则返回1 677 | ``` 678 | 679 | ##### 3.1.4.2 参数表 680 | 681 | 对于参数来说,编译器还需要支持多层作用域。在前面的哈希表结构基础上,我们实现了如下所示的数据结构以支持scope: 682 | 683 | hash_table_scope 684 | 685 | 其中每个作用域在图上画成了红色的链表结构,实际上也是用`vector`实现,这里只是为了方便表示。 686 | 687 | 定义全局变量scope,初始化为0,参数表涉及以下功能: 688 | 689 | * 进入一个作用域时,新建 `vector`并加入`Scope Table`,全局变量`scope`加1; 690 | * 参数声明时,检查参数名是否**在当前作用域**定义过或者与关键字重复,如果没有,则将新参数加入哈希表,同时把链表节点加入当前作用域的`vector`,否则报错; 691 | * 参数调用时,检查参数名是否定义过,如果有,返回相应的`Para`结构,否则报错; 692 | * 离开一个作用域时,将当前作用域下所有参数的链表节点移除,在`Scope Table`中删除,全局变量`scope`减1。 693 | 694 | 实现对应接口如下: 695 | 696 | ```c 697 | void addScope(); // 进入作用域 698 | void exitScope(); // 离开作用域 699 | Para querySymTable_para(char* name); // 查询参数表 700 | int insertSymTable_para(Para r); // 插入参数表 701 | void insertScopeItem(listNode r); // 链表节点插入作用域,插入参数表时调用 702 | ``` 703 | 704 | 705 | 706 | ### 3.2 具体实现 707 | 708 | 从root开始对语法树进行遍历,并进行符号表的相关操作,实现类型的构造与语义检查。 709 | 710 | #### 3.2.1 参数定义(非数组) 711 | 712 | 参数定义需要检查是否有重复定义,并把参数插入符号表。这里仅讨论**非数组定义**,数组会在后文阐述。 713 | 714 | 若参数名在**当前作用域**定义过或者与关键字重复,则报错,否则: 715 | 716 | * 新建并分配内存给`Para`结构; 717 | * 设置参数名、参数类型和作用域; 718 | * 分配内存给参数值指针`const_val`,解析并填入参数值; 719 | * 将`Para`插入符号表。 720 | 721 | #### 3.2.2 数组定义 722 | 723 | 数组定义的过程与其他参数定义基本相同,但还需要以下两个工作: 724 | 725 | * **维数解析**。例如定义`int a[2][3]`,需要通过`[2][3]`解析出维数对应的类型,在前文3.1.1已经说明类型定义。 726 | 727 | * **值解析**。非数组定义只需要一个数值,但在SysY语言中,数组初值有多种情况,以`int a[3][2]`为例: 728 | 729 | * 所有元素初始为0:`int a[3][2] = {};` 730 | 731 | * 与数组维数和各维长度完全对应的初始值,例如: 732 | 733 | * `int a[3][2] = {1, 2, 3, 4, 5, 6};` 734 | * `int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};` 735 | * `int a[3][2] = {1, 2, {3, 4}, 5, 6};` 736 | 737 | * `{}`括起来的初始值比对应维数少,隐式初始化,例如: 738 | 739 | * `int a[3][2] = {{}, {3}, 5, 6};` 740 | 741 | 上文会将`a[3][2]`初始化为`{{0, 0}, {3, 0}, {5, 6}}`。 742 | 743 | ##### 3.2.2.1 维数解析 744 | 745 | 对于多维数组类型解析,如`int a[2][3][4]`,需要构造出3.1.1图片所示的链表`List`。`[2][3][4]`部分的产生式如下: 746 | 747 | ```c 748 | // LB = '[', RB = ']' 749 | constExp_rep -> constExp_rep LB ConstExp RB // for const array 750 | Exp_rep -> Exp_rep LB Exp RB // for array 751 | ``` 752 | 753 | 解析`Exp_rep`得到类型`List`的过程如下,`constExp_rep`基本相同: 754 | 755 | * 新建基础类型`Type`并分配内存,设置`kind`。 756 | * 解析最后一维的`Exp`得到`size`。 757 | * 将`Type`加到`List`头部,解析前面的`Exp_rep`,重复此过程,直到变成NULL。 758 | 759 | ##### 3.2.2.2 值解析 760 | 761 | SysY语言的数组定义初始化比较灵活,语义分析的重点在于两点: 762 | 763 | * 大括号嵌套层数不多于定义维数 764 | * 每一维的元素个数不多于对应维的元素个数 765 | 766 | 我们对这部分语法树进行深度优先搜索,过程中记录当前处于第几层`index`,已经初始化的元素个数`count`,到本层为止最多多少元素`limit`。搜索时可能会遇到左括号`{`、右括号`}`或者元素`number`,分别处理如下: 767 | 768 | * `{`: 769 | * 检查`index+1`是否超过数组维数;如果`count`不是下一层size的倍数,则需要隐式初始化,更新`count`;检查`count`是否超过`limit`; 770 | * `index`更新为`index+1`,`limit`更新为`count`加上下一层需要的元素个数,递归调用分析。 771 | * `}`: 772 | * 如果`count`不是本层size的倍数,需要隐式初始化,更新`count`。 773 | * `number` : 774 | * 检查`count`是否超过`limit`; 775 | * 将对应位置的地址赋值,`count++`。 776 | 777 | #### 3.2.3 函数定义 778 | 779 | 函数定义框架也和参数定义类似,需要检查是否有重复定义,并把函数`Func`插入符号表,不再赘述。我们用`vector`结构存储函数的形参,这里的重点在形参表中**有多维数组**时的处理。 780 | 781 | SysY语言中,函数形参是多维数组时第一维会留空,例如`void f(a[][2])`,则`a`可以匹配`x*2`大小的数组。所以这里形参数组的维数类型也要具体记录下来,和参数定义的维数解析类似,只不过第一维的维数没有限制,`size`写成`-1`。 782 | 783 | #### 3.2.4 函数调用 784 | 785 | 函数调用需要检查函数是否被定义,**实参类型是否与形参对应**。前者只需要查询函数表即可,后者需要将实参表和形参表比对参数类型,有两种情况: 786 | 787 | * 形参是数值 788 | 789 | 若实参也是一个简单数值,则匹配。若实参形如`a[2][3]`,则要检查它是定位到元素,即方括号个数和数组变量的维数相同。这里如果`a`是二维,则匹配。 790 | 791 | * 形参是多维数组 792 | 793 | 形参是多维数组时需要具体检查每一维是否匹配。例如`void f(a[][2])`,则`a`可以匹配`x*2`大小的数组,若有`int temp[4][3][2][2]`,则`temp[1][1]`就是`2*2`的数组,可以匹配。因此需要以下处理: 794 | 795 | * **得到实参所取的数组维数。**就上文例子来说,原变量`temp`类型`List`形如:`4->3->2->2`,调用`temp[1][1]`解析得到`List`形如`1->1`,即可得到`temp[1][1]`实际上对应的类型为`2->2`。实现接口: 796 | 797 | ```c 798 | List combineType(List defType, List callType); 799 | ``` 800 | 801 | * **检查维数是否匹配**。接上例子,检查`a[][2]`和`2->2` 的维数可以匹配即可,即第一维忽略,后面的`size`完全相同。 802 | 803 | #### 3.2.5 左值处理 804 | 805 | 左值`LVal`有两种情况: 806 | 807 | * 作为实参在**函数调用**时使用 808 | * 作为左值在**赋值语句**使用,形如`LVal '=' Exp; ` 809 | 810 | 其中,`LVal`只有在**函数调用**才能是多维数组,在**赋值语句**只能是非数组变量,或者定位到数组元素。因此在分析`LVal`时,需要一个flag判断属于哪种情况。 811 | 812 | 前者需要检查和形参是否匹配,分析办法在函数调用部分已经说明;后者只需要确定`LVal`对应的变量有定义且是数值即可。 813 | 814 | #### 3.2.6 循环语句 815 | 816 | 由于`break`和`continue`语句只有在循环语句的`block`中出现,所以这里需要特殊处理。定义全局变量`whileCnt`,在遇到`while`循环时+1,在离开时-1。所以如果分析到`break`或`continue`,检查`whileCnt`是否大于0即可。 817 | 818 | 819 | 820 | ### 3.3 错误处理 821 | 822 | 根据以上的语义分析过程,我们一共处理26种不同的语义错误: 823 | 824 | | error num | reason | info | 825 | | --------- | ---------------------------------------------- | ------------------------------------------------------------ | 826 | | 1 | 定义常量/变量类型不能是void | storage size of this variable isn't known | 827 | | 2 | 除运算和模运算的被除数不能是0 | division by zero | 828 | | 3 | 函数不能在常量表达式中调用 | function cannot be called in a constant expression, because the return value of a function is a variable | 829 | | 4 | 数组的维度必须是正数 | size of array is negative | 830 | | 5 | 声明数值变量,初始化类型是数组 | excess elements in scalar initializer | 831 | | 6 | 声明数组变量,初始化类型是数值 | invalid initializer | 832 | | 7 | 变量还未声明 | the variable has't been defined | 833 | | 8 | 数组变量初始化,大括号嵌套层数超过数组维数 | too many braces around scalar initializer | 834 | | 9 | 需要是const的地方类型不是const | const type variable is required here | 835 | | 10 | 数组变量初始化,同一维度元素数量超过限制 | excess elements in scalar initializer | 836 | | 11 | 变量/常量/函数声明时和保留字重名 | an identifier can not be the same as reserve names | 837 | | 12 | 变量/常量/函数重复定义 | repeated definition | 838 | | 13 | continue或者break语句不在循环体内 | the continue/break statement is not in while loop | 839 | | 14 | '!'只能出现在条件表达式 | NOT '!' operation can only appear in condition expressions | 840 | | 15 | 函数实参和函数形参类型有出入 | the actual parameter type is different from the formal parameter type defined by the function | 841 | | 16 | 函数声明时形参类型不能是void | function parameter type cannot be void | 842 | | 17 | return类型和函数返回类型对不上 | the return type is different from the return type defined by the function | 843 | | 18 | 左值作为函数实参调用,调用不合法 | when lvalue is passed as a function argument, the reference of the array variable is illegal | 844 | | 19 | 左值作为赋值语句调用,下标越界 | subscript out of bounds | 845 | | 20 | 左值作为函数实参调用,应该传入数组,输入是数值 | lvalue passed as a function argument here should be an array/constarray. | 846 | | 21 | 左值作为赋值语句调用,必须取到一个元素 | the lvalue in the assignment statement can only be a non-array variable, or locate an array element. | 847 | | 22 | 函数声明无参数,调用时传入参数 | too many function arguments | 848 | | 23 | 函数调用时参数过多 | too many function arguments | 849 | | 24 | 函数调用时未定义 | the function has't been defined | 850 | | 25 | 函数调用时缺少参数 | missing function arguments | 851 | 852 | 遇到语义错误不会立即停止程序,而是继续分析直到分析完成,从而能够尽可能多的找到语义错误。记录语义错误数量,大于0则不继续做中间代码生成。 853 | 854 | 855 | 856 | ## 第4章 中间代码生成 857 | 858 | ### 4.1 名词解释 859 | 860 | 中间代码(Intermediate Representation, IR)是目标代码的一种精简的形式化表达,它不仅将编译器的编写划分成前端和后端两大部分,更重要的是成为各种各样的源代码和目标代码之间的桥梁,当源代码、目标代码、目标体系架构以及运行时环境种类非常繁多的时候,相比于对于每一种源代码和目标环境之间都构造一种编译器,采用中间代码作为中介就可以大大减少需要的编译器的数目,从而减少工作量。 861 | 862 | 根据和目标代码的相近程度,中间代码可以被分为许多不同的等级。常用的中间代码有P-Code、Three-Address Code等。中间代码生成则是以抽象语法树(Abstract Syntax Tree, AST)为输入,产生中间代码的过程。 863 | 864 | 865 | 866 | ### 4.2 中间代码定义 867 | 868 | 本实验采用的中间代码定义如下: 869 | 870 | ``` 871 | LABEL x : 定义标号x 872 | FUNCTION f: 定义函数f 873 | x := y 赋值操作 874 | x := y + z 加法操作 875 | x := y - z 减法操作 876 | x := y * z 乘法操作 877 | x := y / z 除法操作 878 | x := y % z 模除操作 879 | x := &y 取y的地址赋给x 880 | x := *y 取以y值为地址的内存单元的内容赋给x 881 | *x := y 取y值赋给以x值为地址的内存单元 882 | GOTO x 无条件跳转至标号x 883 | IF x [relop] y GOTO z 如果x与y满足[relop]关系则跳转至标号z 884 | RETURN x 退出当前函数并返回x值 885 | DEC x [size] 内存空间申请, 大小为4的倍数 886 | ARG x 传实参 887 | x := CALL f 调用函数, 并将其返回值赋给x 888 | PARAM x 函数参数申明 889 | ``` 890 | 891 | **解释:** 892 | 893 | 1. 标号语句LABEL用于指定跳转目标,注意LABEL与x之间、x与冒号之间都被空格或制表符隔开。 894 | 2. 函数语句FUNCTION用于指定函数定义,注意FUNCTION与f之间、f与冒号之间都被空格或制表符隔开。 895 | 3. 赋值语句可以对变量进行赋值操作(注意赋值号前后都应由空格或制表符隔开)。赋值号左边的x一定是一个变量或者临时变量,而赋值号右边的y既可以是变量或临时变量,也可以是立即数。如果是立即数,则需要在其前面添加“#”符号。例如,如果要将常数5赋给临时变量t1,可以写成t1 := #5。 896 | 4. 算术运算操作包括加、减、乘、除四种操作(注意运算符前后都应由空格或制表符隔开)。赋值号左边的x一定是一个变量或者临时变量,而赋值号右边的y和z既可以是变量或临时变量,也可以是立即数。如果是立即数,则需要在其前面添加“#”符号。例如,如果要将变量a与常数5相加并将运算结果赋给b,则可以写成b := a + #5。 897 | 5. 赋值号右边的变量可以添加“&”符号对其进行取地址操作。例如,b := &a + #8代表将变量a的地址加上8然后赋给b。 898 | 6. 当赋值语句右边的变量y添加了“*”符号时代表读取以y的值作为地址的那个内存单元的内容,而当赋值语句左边的变量x添加了“*”符号时则代表向以x的值作为地址的那个内存单元写入内容。 899 | 7. 跳转语句分为无条件跳转和有条件跳转两种。无条件跳转语句GOTO x会直接将控制转移到标号为x的那一行,而有条件跳转语句(注意语句中变量、关系操作符前后都应该被空格或制表符分开)则会先确定两个操作数x和y之间的关系(相等、不等、小于、大于、小于等于、大于等于共6种),如果该关系成立则进行跳转,否则不跳转而直接将控制转移到下一条语句。 900 | 8. 返回语句RETURN用于从函数体内部返回值并退出当前函数,RETURN后面可以跟一个变量,也可以跟一个常数。 901 | 9. 变量声明语句DEC用于为一个函数体内的局部变量声明其所需要的空间,该空间的大小以字节为单位。这个语句是专门为数组变量和结构体变量这类需要开辟一段连续的内存空间的变量所准备的。例如,如果我们需要声明一个长度为10的int类型数组a,则可以写成DEC a 40。对于那些类型不是数组或结构体的变量,直接使用即可,不需要使用DEC语句对其进行声明。另外,在中间代码中不存在作用域的概念,因此不同的变量一定要避免重名。 902 | 10. 与函数调用有关的语句包括CALL、PARAM和ARG三种。其中PARAM语句在每个函数开头使用,对于函数中形参的数目和名称进行声明。例如,若一个函数func有三个形参a、b、c,则该函数的函数体内前三条语句为:PARAM a、PARAM b和PARAM c。CALL和ARG语句负责进行函数调用。在调用一个函数之前,我们先使用ARG语句传入所有实参,随后使用CALL语句调用该函数并存储返回值。仍以函数func为例,如果我们需要依次传入三个实参x、y、z,并将返回值保存到临时变量t1中,则可分别表述为:ARG z、ARG y、ARG x和t1 := CALL func。注意ARG传入参数的顺序和PARAM声明参数的顺序正好相反。ARG语句的参数可以是变量、以#开头的常数或以&开头的某个变量的地址。注意:当函数参数是数组时,ARG语句的参数为数组的地址(即以传引用的方式实现函数参数传递)。 903 | 904 | 905 | 906 | ### 4.3 数据结构定义 907 | 908 | 为了表示并储存中间代码,我们定义了以下数据结构: 909 | 910 | ```c 911 | typedef struct ArgList_* ArgList; // 函数实参链表 912 | typedef struct Variable_* Variable; // 变量 913 | typedef struct Operand_* Operand; // 操作数 914 | typedef struct InterCode_* InterCode; // 中间代码节点 915 | typedef struct CodeList_* CodeList; // 中间代码链表 916 | 917 | 918 | struct Operand_{ 919 | enum{ 920 | OP_VARIABLE, // 变量 921 | OP_CONSTANT, // 常量 922 | OP_ADDRESS, // 地址 923 | OP_LABEL, // 标签 924 | OP_TEMP // 暂时变量 925 | } kind; 926 | union{ 927 | int var_no; // 变量序号 928 | int label_no; // 代码label序号 929 | int val; // 用于常数 930 | int temp_no; // 暂时变量序号 931 | }u; //这些的作用就是作为唯一标示--每一个变量都是不同名的--从而解决作用域问题 932 | }; 933 | 934 | struct InterCode_{ 935 | enum{ 936 | IR_ASSIGN, // x := y 937 | IR_LABEL, // LABEL x : 938 | IR_PLUS, // x := y+z 939 | IR_MINUS, // x := y-z 940 | IR_MUL, // x := y*z 941 | IR_DIV, // x := y/z 942 | IR_MOD, // x : = y%z 943 | IR_FUNC, // FUNCTION f : 944 | IR_GOTO, // GOTO x 945 | IR_IFGOTO, // IF x [relop] y GOTO z 946 | IR_RET, // x = *y 947 | IR_DEC, // DEC x [size] 内存空间申请-大小为4的倍数 用于数组 948 | IR_ARG, // ARG x 949 | IR_CALL, // x := CALL f 950 | IR_PARAM, // PARAM x 951 | IR_READ, // 不用 952 | IR_WRITE, // 不用 953 | IR_RETURN, // RETURN x 954 | IR_CHANGE_ADDR, // *x := y 取y值以赋给x值为地址的内存单元 955 | IR_GET_ADDR // x := &y 取y的地址赋给x 956 | } kind; 957 | union{ 958 | Operand op; 959 | char *func; 960 | struct{Operand right, left; } assign; // 赋值 x := y 961 | struct{Operand result, op1, op2; } binop; // 双目 x := y + z 962 | struct{Operand x, y, z; char *relop;} if_goto; // IF x [relop] y GOTO z 963 | struct{Operand x; int size;} dec; // DEC x [size] 964 | struct{Operand result; char *func;} call; // x := CALL f 965 | }u; 966 | }; 967 | 968 | // 中间代码链表 969 | struct CodeList_{ 970 | InterCode code; 971 | CodeList prev, next; 972 | }; 973 | ``` 974 | 975 | **解释:** 976 | 977 | 1. `Operand`用于保存每一条中间代码涉及的操作数、常数、标识代码位置的Label等。`kind`储存`Operand`的分类,`u`则储存对应的编号。**按照用途,`Operand`可以分为变量、常量、地址、Label标签、临时变量五种。**其中: 978 | 979 | - 变量(`OP_VARIABLE`)主要用于表示非临时变量的变量,在中间代码中会被表示为`v1`、`v2`、......。对应地,`u`中的`var_no`储存变量的编号。 980 | - 常量(`OP_CONSTANT`)主要用于表示常数(立即数),在中间代码中会被表示为`#5`、`#7`、......。对应地,`u`中的`val`储存变量的编号。 981 | - 地址(`OP_ADDRESS`)和变量类似,但主要用于储存数组指针,与普通变量区分开来是为了便于分配空间与程序处理。 982 | - 标签(`OP_LABEL`)主要用于记录程序中的Label标签(主要用于跳转)。`u`中的`label_no`储存label的编号。 983 | - 临时变量(`OP_TEMP`)主要用于表示临时变量,在中间代码中会被表示为`t1`、`t2`、......。对应地,`u`中的`temp_no`储存变量的编号。 984 | 985 | **为了保证变量(常量、地址、标签等)之间互不冲突,我们规定IR生成部分中,所有的Operand都是不一样的,即每个变量(常量、地址、标签等)与某个Operand唯一对应。在目标代码生成中,再根据Operand分配内存或是寄存器,实现复用。** 986 | 987 | 2. `Intercode`用于保存每一条中间代码的具体内容,`kind`是中间代码的类型,`u`中存储中间代码的操作数,根据代码类型的不同,每一条中间代码可能具有1-3个操作数。 988 | 989 | 3. `CodeList`用于储存中间代码链表。这样处理是为了便于优化中间代码,如果在计算中间代码的同时就将中间代码直接输出,那么输出的中间代码就无法被修改和优化了,所以我们可以先把中间代码存在链表中,待优化完成后再进行输出。 990 | 991 | 992 | 993 | ### 4.4 问题分析与整体思路 994 | 995 | 首先,应当明确的是,IR生成部分的输入是通过了符号表类型检查的AST,输出是若干行中间代码。通过遍历输入的抽象语法树,我们可以仿照语义分析中计算属性的方法,来得出每一个节点对应的中间代码。 996 | 997 | 例如,假设下面是某棵抽象语法树的一部分: 998 | 999 | ```ada 1000 | AddExp 1001 | / | \ 1002 | AddExp ’+‘ MulExp 1003 | | 1004 | MulExp 1005 | ``` 1006 | 1007 | 根节点`AddExp`拥有两个孩子,分别为`AddExp`和`MulExp`。要想计算根节点对应的IR,我们只需要分别计算它的两个孩子的IR,储存到两个临时变量中,最后生成一条将两个临时变量相加的IR。 1008 | 1009 | 上述过程的伪代码如下: 1010 | 1011 | ```c 1012 | /*** 1013 | 生成以r为根的子树的中间代码,表达式的最终值储存在t2这个Operand中 1014 | ***/ 1015 | CodeList translate_AddExp(TreeNode r, Operand* t2){ 1016 | if(r == NULL) return NULL; 1017 | Node AddExp = r->child[0]; // left child 1018 | Node MulExp = r->child[2]; // right child 1019 | Node Op = r->child[1]; // Operator 1020 | t0 = new Operand(); 1021 | t1 = new Operand(); 1022 | CodeList c0 = translate_AddExp(AddExp, &t0); // generate IR for left sub-tree 1023 | CodeList c1 = translate_MulExp(MulExp, &t1); // generate IR for right sub-tree 1024 | if(Op->operator == '+') // plus 1025 | { 1026 | Intercode ir = generate_IR_plus(&t2, &t0, &t1); // generate IR of "t2 := t0 + t1" 1027 | CodeList c2 = new CodeList(ir); // put the IR above in a code list 1028 | } else { // minus 1029 | Intercode ir = generate_IR_plus(&t2, &t0, &t1); // generate IR of "t2 := t0 - t1" 1030 | CodeList c2 = new CodeList(ir); // put the IR above in a code list 1031 | } 1032 | return merge(merge(c0, c1), c2); // merge codelist c0, c1 and c2 to get the target code list of node r 1033 | } 1034 | ``` 1035 | 1036 | 可以看到,对`AddExp`这一节点的IR生成经历了左子树生成、右子树生成、所在节点代码生成三个步骤。类似地,所有的`AddExp`类型的节点都可以采用这一翻译模式。 1037 | 1038 | 上述分析告诉我们,**每一个种类的抽象语法树节点都可以采用相似的方式(模板)来生成中间代码**,并且这一过程与之前的语法制导翻译(SDT)具有一定的相似性。同时,SDT中的符号表(变量表、函数表)同样可以服务于中间代码部分。由于中间代码生成中,每个变量、常量、数组地址等等都被抽象为了Operand,而且同一个Operand可能在源程序的多个地方被调用,因此我们需要对Operand进行复用。解决的方案是构建符号表时同时插入符号对应的Operand,这样就能保证每个符号与某个Operand唯一对应。 1039 | 1040 | 因此,我们采用的基本方法为:对于每一种类型的节点(设类型为`X`),我们只需要调用函数`translate_X`对其进行语法制导翻译,套用一定的模板,将中间代码看做是节点的属性进行计算即可。对于SDT中使用的变量表和函数表,**我们在类型检查结束后仅保留函数表**(因为SysY语言中函数是全局的),**释放变量表**,并在IR的翻译过程中重新构建变量表,构建方法与SDT一致,但在构建的过程中还需要同时插入每一个符号对应的Operand。 1041 | 1042 | 下面我们针对一些典型的语法树结构的翻译“模板”进行说明。 1043 | 1044 | 1045 | 1046 | ### 4.5 模板 1047 | 1048 | #### 4.5.1 基本表达式与常量表达式 1049 | 1050 | 基本表达式`Exp`的翻译较为简单,可分为以下几种情况: 1051 | 1052 | - 如果`Exp`生成了一个立即数,则直接新建一个常量Operand,并将该立即数赋给这个常量即可。 1053 | - 如果`Exp`生成了一个左值表达式,则需要到符号表中进行查询得出左值表达式的值,再新建一个变量储存该值即可。 1054 | - 如果`Exp`生成了四则运算表达式,则先生成参与运算的Operand的中间代码,再生成一条计算表达式的IR即可。 1055 | - 条件表达式、赋值表达式也可仿照上一节的例子类似计算。 1056 | 1057 | 对于常量表达式,由于已经通过了类型检查,所以常量表达式可以采用与变量表达式相同的方法进行处理。 1058 | 1059 | #### 4.5.2 条件语句和循环语句 1060 | 1061 | SysY中条件语句和循环语句包括if语句、while语句,对于每种类型的语句,我们首先要计算出语句中涉及到的表达式、子语句的值,为此需要分别为其生成中间代码。由于条件语句和循环语句涉及到跳转,我们需要添加一系列label,为了能够根据条件的真假跳转到不同的位置,我们为`translate_Cond`函数添加两个参数`label_true`和`label_false`,将其当做继承属性计算,当条件表达式值为真时跳转到`label_true`的位置,否则跳转到`label_false`的位置。 1062 | 1063 | 以带`else`关键字的`if`语句为例。首先生成`label1`, `label2`, `label3`分别表示条件为真时的代码、条件为假时的代码和结束位置。若条件为真,则继续执行`label1`后的代码,否则跳转到`label2`的位置(这里的跳转在`translate_Cond`函数中实现,后文会详细介绍)。 当条件为真时的代码执行完成时,使用`GOTO label3`语句直接跳转到`if`语句结束的位置。 1064 | 1065 | 具体的翻译模式如下表所示。 1066 | 1067 | 在SysY中,条件语句和循环语句包括`if`语句、`while`语句,翻译模式如下: 1068 | 1069 | | Case Stmt of | translate_Stmt(Stmt, label_continue, label_break) | 1070 | | ----------------------------- | ------------------------------------------------------------ | 1071 | | IF LP Exp RP Stmt1 | label1 = new_label()
label2 = new_label()
code1 = translate_Cond(Exp, label1, label2)
code2 = translate_Stmt(Stmt1, label_continue, label_break)
return code1 + [LABEL label1] + code2 + [LABEL label2] | 1072 | | IF LP Exp RP Stmt1 ELSE Stmt2 | label1 = new_label()
label2 = new_label()
lebel3 = new_label()
code1 = translate_Cond(Exp, label1, label2)
code2 = translate_Stmt(Stmt1, label_continue, label_break)
code3 = translate_Stmt(Stmt2, label_continue, label_break)
return code1 + [LABEL label1] + code2 + [GOTO label3] + [LABEL label2] + code3 + [LABEL label3] | 1073 | | WHILE LP Exp RP Stmt1 | label1 = new_label()
label2 = new_label()
lebel3 = new_label()
code1 = translate_Cond(Exp, label2, label3)
code2 = translate_Stmt(Stmt1, label1, label3)
return [LABEL label1] + code1 + [LABEL label2] + code2 + [GOTO label1] + [LABEL label3] | 1074 | 1075 | #### 4.5.3 break和continue语句 1076 | 1077 | 注意到上表中`translate_Stmt`的参数中新增了两个参数,分别为`label_break`和`label_continue`,我们将其作为继承属性计算,分别表示当循环中遇到`continue`和`break`语句时应当跳转到的位置。`continue`和`break`的初始值都为空,当然,由于输入已经通过了类型检查,所以不会出现访问空地址的情况。当遇到`while`语句时,在翻译子语句时,我们将`label1`和`label3`的值分别赋给`label_break`和`label_continue`,表示循环开始和结束的位置。显然,`break`语句对应的IR为`[GOTO label_break]`,`continue`则对应 `[GOTO label_continue]`。 1078 | 1079 | #### 4.5.4 变量、常量定义 1080 | 1081 | 对于不带初始值的变量,变量的定义本身是不需要翻译成IR的,因为普通变量只需要在运行时分配内存即可,无需单独声明。对于带初始值的变量,只需要先生成计算变量初始值的中间代码,然后新建一个变量,并生成一条将变量的初始值赋给该变量的中间代码。 1082 | 1083 | 对于常量,由于输入已经通过了类型检查,所以可以按照和变量一样的方法处理。 1084 | 1085 | #### 4.5.5 数组定义 1086 | 1087 | 数组的情况则要复杂一些。仿照SDT部分中对数组的处理方式,我们同样采取与其他部分不一样的方法来生成数组的中间代码。 1088 | 1089 | 我们对这部分语法树进行深度优先搜索,同样在过程中记录当前处于第几层`index`,已经初始化的元素个数`count`,到本层为止最多多少元素`limit`。搜索时可能会遇到左括号`{`、右括号`}`或者元素`number`,分别处理如下: 1090 | 1091 | * `{`: 1092 | * 如果`count`不是下一层size的倍数,则需要隐式初始化,更新`count`; 1093 | * `index`更新为`index+1`,`limit`更新为`count`加上下一层需要的元素个数,递归调用分析。 1094 | * `}`: 1095 | * 如果`count`不是本层size的倍数,需要隐式初始化,更新`count`。 1096 | * `number` : 1097 | * 生成将对应位置的地址赋值的中间代码,并`count++`。由于这里的赋值涉及到数组下标作为左值的赋值,这部分代码的生成可以参考4.5.8节。 1098 | 1099 | 其中,隐式初始化可以通过在一开始将数组空间全部置为0来实现,这样在搜索的过程中就不需要再进行对应的操作了。 1100 | 1101 | #### 4.5.6 函数定义 1102 | 1103 | 由于在语法分析中已经构建好了函数表,所以对于函数定义的处理较为简单。对于不带参数的函数,只需要声明函数后直接翻译函数后的block即可。对于带参数的函数,还需要在声明函数后声明其参数。由于参数的名称及其类型已经储存在函数表中,翻译时只需要读取函数表中的对应条目,然后依次翻译参数即可。 1104 | 1105 | #### 4.5.7 函数调用 1106 | 1107 | 对于无参数的函数,直接查询符号表并生成一条调用该函数的代码即可。对于带函数的参数,我们还需要另外翻译其实参表。定义`arg_list`为函数的实参表,实参表由一系列表达式`Exp`构成,只需要对这些表达式逐个翻译即可。翻译模式如下表所示:(上表为函数调用的翻译模式,下表为函数实参表的翻译模式) 1108 | 1109 | | case UnaryExp of | translate_UnaryExp(UnaryExp, place) | 1110 | | ---------------- | ------------------------------------------------------------ | 1111 | | ID LP RP | function = lookup(SymTable, ID)
return [place := CALL function.name] | 1112 | | ID LP Args RP | function = lookup(SymTable, ID)
arg_list = NULL
code1 = translate_Args(Args, arg_list)
for i = 1 to length(arg_list) code2 = code2 + [ARG arg_list[i]]
return code1 + code2 + [place := CALL function.name] | 1113 | | ... | ... | 1114 | 1115 | | case Args of | translate_Args(Args, arg_list) | 1116 | | --------------- | ------------------------------------------------------------ | 1117 | | Exp | t1 = new_temp()
code1 = translate_Exp(Exp, t1)
arg_list = t1 + arg_list
return code1 | 1118 | | Exp COMMA Args1 | t1 = new_temp()
code1 = translate_Exp(Exp, t1)
arg_list = t1 +arg_list
code2 = translate_Args(Args1, arg_list)
return code1 + code2 | 1119 | 1120 | 1121 | 1122 | #### 4.5.8 左值 1123 | 1124 | 在SysY中,左值`LVal`对应的语法是`LVal -> ID Exp_rep`,其中`Exp_rep -> Exp_rep LB Exp RB | empty`. **由于函数实参支持传入数组指针,并且支持传入数组的部分维度作为指针**,因此左值也拥有较多的种类。具体而言,左值可以被分为以下几类: 1125 | 1126 | **1. 普通变量/常量** 1127 | 1128 | - **判断条件:**`ID`后无中括号,即`Exp_rep`为空,且`ID`在符号表中为普通变量/常量。 1129 | - **解决方案**:从符号表中查询`ID`对应的Operand,并生成一条IR将Operand中的值赋给目标变量。 1130 | 1131 | **2. 数组指针** 1132 | 1133 | 数组指针又可分为两类:以数组`a[3][4][5]`为例,第一类是以数组的名字作为指针,即以`a`作为实参;第二类是以数组的部分维度(**但不能是全部维度**)作为指针,如以`a[1]`、`a[1][2]`作为实参。 1134 | 1135 | - **判断条件:**(1)`ID`后无中括号,即`Exp_rep`为空,且`ID`在符号表中为常量数组/变量数组。(2)`ID`后有中括号,`ID`在符号表中为常量数组/变量数组,且中括号的数量小于数组的维数。 1136 | 1137 | - **解决方案**:从符号表中查询`ID`对应的Operand,得到`ID`对应数组的基地址,记为`Base_addr`。由于数组空间在内存中是连续的,我们只需要根据下标结合基地址算出指针对应的位置。例如,仍以数组`a[3][4][5]`为例,要计算`a[1][2]`对应的地址,只需要先算出`a[0]`的大小,即`4*5=20`,然后计算`a[1][0]`,`a[1][1]`的大小,即`5*2=10`(数组最后一维度的大小\*下标)。两者相加,再加上原数组基地址,由此得出`a[1][2]`对应的地址为`Base_addr+30`。 1138 | 1139 | 概括地讲,设要计算`a[i][j][k]`对应的地址,我们可以采用以下的公式进行计算: 1140 | $$ 1141 | ADDR(a[i][j][k])=ADDR(a)+\sum_{t=0}^{i-1}sizeof(a[t]) + \sum_{t=0}^{j-1}sizeof(a[i][t])+\sum_{t=0}^{k-1}sizeof(a[i][j][t]) 1142 | $$ 1143 | 上式很容易推广到任意维数组的情况。 1144 | 1145 | **3. 数组元素值** 1146 | 1147 | - **判断条件:**`ID`后有中括号,`ID`在符号表中为常量数组/变量数组,且中括号的数量等于数组的维数。 1148 | - **解决方案**:同数组指针的处理方法,但在处理完成后需要增加一步取值操作。具体为:设数组指针对应的地址储存在`t1`中,目标变量为`place`,则需要新增一条中间代码 `[place := *t1]`. 1149 | 1150 | 1151 | 1152 | ### 4.6 代码优化 1153 | 1154 | 目前主要完成了以下几种中间代码的优化 1155 | 1156 | * 冗余跳转的删除 1157 | * 删除未被指向的label 1158 | * 直接计算常数 1159 | 1160 | 1161 | 1162 | #### 4.6.1 冗余跳转的删除 1163 | 1164 | 采用`IF_False`的结构进行优化, 从而减少`LABEL`数量。对于单`if`语句的翻译,一般结果如下: 1165 | 1166 | ``` 1167 | IF x [relop] y GOTO label_true ; 1168 | GOTO label_out 1169 | LABEL label_true ; 1170 | code_true ; 1171 | LABEL label_out ; 1172 | ``` 1173 | 1174 | 对于`if-else`语句的翻译 一般结果如下 1175 | 1176 | ``` 1177 | IF x [relop] y GOTO label_true ; 1178 | GOTO label_false ; 1179 | LABEL label_true ; 1180 | code_true ; 1181 | GOTO label_out ; 1182 | LABEL label_false 1183 | code_false ; 1184 | LABEL label_out ; 1185 | ``` 1186 | 1187 | 对于单`if`语句, 使用了两个`label`, 对于`if-else`语句, 使用了3个`label`。而采用`if_false`的方式, 对单`if`只需要一个`label`, 对`if-else`只需要两个`label`。 因此该优化就是将原来的if语句通过将内部逻辑区取反的方式转化为`if_false`。 1188 | 1189 | 优化后为: 1190 | 1191 | - 单`if`语句 1192 | 1193 | ``` 1194 | IF x ![relop] y GOTO label_out ; 1195 | code_true ; 1196 | LABEL label_out ; 1197 | ``` 1198 | 1199 | - `if-else`语句 1200 | 1201 | ``` 1202 | IF x ![relop] y GOTO label_false ; 1203 | code_true ; 1204 | GOTO label_out ; 1205 | LABEL label_false ; 1206 | code_false ; 1207 | LABEL label_out 1208 | ``` 1209 | 1210 | 可以看到有三处修改: 1211 | 1212 | 1. 将`[relop] `转化为了 `![relop]`, 同时将`label_true`改为了`label_out`或者`label_false` 1213 | 2. 删除第二条`GOTO`语句 1214 | 3. 删除第三条`LABEL`语句 1215 | 1216 | 同时对于某种条件下可能存在的如下情况 1217 | 1218 | ``` 1219 | GOTO label1 ; 1220 | LABEL label1 ; 1221 | ``` 1222 | 1223 | 我们可以将这个多余的`GOTO`语句直接删除。 1224 | 1225 | #### 4.6.2 删除未被指向的label 1226 | 1227 | 基本思想: 对中间代码双向链表进行遍历; 对`Label`类型的代码, 判断是否会跳转到此`Label`; 若无, 则为未被指向的`label`, 需要删除。 1228 | 1229 | #### 4.6.3 直接计算常数(常量折叠) 1230 | 1231 | 基本思想: 对中间代码双向链表进行遍历; 对于计算类型的操作, 判断左右侧是否为常量; 如果均是常量, 则将该代码替换为lhs, rhs计算结果的常量。 1232 | 1233 | #### 4.6.4 替换相同的右部表达式的变量(公共子表达式删除) 1234 | 1235 | 例如:` t3 = t1 + t2; t4 = t1 + t2; v2 = t4 + #2; v5 = t3 + t4; ` 1236 | 1237 | 然后`t4`在其他地方参与运算,这将所有的`t4`都替换成`t3`, 然后删除`t4`的计算语句, 从而减少了不必要的运算。 1238 | 1239 | #### 4.6.5 复制传播 1240 | 1241 | 在赋值语句`x=y`之后尽可能用`y`代替`x`。 好处就是后面在目标代码生成的时候更能体现 不需要`x`和`y`在寄存器里面换来换去。 1242 | 1243 | 1244 | 1245 | ## 第5章 测试用例 1246 | 1247 | ### 5.1 Lexer 词法分析器 1248 | 1249 | Token列表已经在[Token定义](#§1.2 Token定义)中给出,我们写了一个包含所有可能tokens的文件用于测试我们的词法分析器。 1250 | 1251 | test_lexer.sh 是我们用于测试语法分析器的脚本。在进入从主文件目录myCompiler下进入testCase/lexTest目录下运行脚本命令如下 1252 | 1253 | ```shell 1254 | bash lexTest.sh 1255 | ``` 1256 | 1257 | * **输入**:需要词法分析的文件。注意路径 1258 | * **输出**:Tokens(格式为`LexToken(,,,)`). 1259 | 1260 | 测试例子 1261 | 1262 | 1. **关键字** 1263 | 1264 | 输入: 1265 | 1266 | ``` 1267 | int void 1268 | if else 1269 | else if 1270 | while 1271 | continue 1272 | break 1273 | return 1274 | const 1275 | ``` 1276 | 1277 | 输出: 1278 | 1279 | 1280 | 1281 | Image text 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 2. **标识符** 1288 | 1289 | 输入: 1290 | 1291 | ``` 1292 | IAmIdentifier 1293 | I2 1294 | Id_is 1295 | It000 1296 | ``` 1297 | 1298 | 输出: 1299 | 1300 | Image text 1301 | 1302 | 1303 | 1304 | 3. **常量** 1305 | 1306 | 输入: 1307 | 1308 | ``` 1309 | 996 1310 | 007 1311 | 0x3E4 1312 | 0X3E4 1313 | 01744 1314 | ``` 1315 | 1316 | 输出: 1317 | 1318 | Image text 1319 | 1320 | 1321 | 1322 | 这里数据成功的将十六进制、八进制等都转换为了十进制。 1323 | 1324 | 4. 运算符 1325 | 1326 | 输入: 1327 | 1328 | ``` 1329 | + - * / % 1330 | < > <= >= == != 1331 | && || ! 1332 | = 1333 | ``` 1334 | 1335 | 输出 1336 | 1337 | Image text 1338 | 1339 | 1340 | 1341 | 5. 分界符 1342 | 1343 | 输入: 1344 | 1345 | ``` 1346 | ( ) 1347 | [ ] 1348 | { } 1349 | , ; 1350 | ``` 1351 | 1352 | 输出: 1353 | 1354 | Image text 1355 | 1356 | 总结,我们编写的lex文件`syntax.l`正确,能够生成预期的词法分析器,完成词法分析任务。测试通过。 1357 | 1358 | printf("LexToken(%s,%s,%d,%d)","",yytext,) 1359 | 1360 | 1361 | 1362 | ### 5.2 Yacc 文法分析器 1363 | 1364 | SysY语言的文法产生式已经在[SysY语言BNF定义](###§2.2 SysY语言文法BNF定义)中给出。 1365 | 1366 | 下面给出相关文法的测试用例。 1367 | 1368 | **输入:** 1369 | 1370 | ```C 1371 | /* 多行注释测试 */ 1372 | /** 1373 | * @file syntaxRight.c 1374 | * @note 这个文件测试SysY语言的所有文法要素, 用于检查生成的文法分析器的正确性。 1375 | * 最终的结果是能够正确解析该文件并输出语法书。有关测试内容在下面给出注释。 1376 | */ 1377 | /* CompUnit */ 1378 | /* 全局声明 */ 1379 | int a; 1380 | /* 全局声明与定义初始化 */ 1381 | int b = 0; 1382 | 1383 | /* 连续声明与定义初始化 */ 1384 | int ch = 5, d = 1, e; 1385 | /* 多维数组声明 */ 1386 | int thisIsAnArray[19][20][21]; 1387 | /* 常量的全局声明 */ 1388 | const int aa = 2; 1389 | const int brr[4] = {1,2,3,4}; 1390 | const int z[2][2] = {{5}, 8, 9}; 1391 | /* Function 2, void Return Value, void Parameter */ 1392 | /* 函数2 返回void 参数也是空*/ 1393 | void HelloWorld() { 1394 | /* 库函数调用-参见SysY运行时库 */ 1395 | //printf("Hello, SysY!"); 1396 | 1397 | /* 空返回 */ 1398 | return; 1399 | } 1400 | /* 函数3 多个参数 有int类型返回值 */ 1401 | int max(int a, int b) { 1402 | // return exp 1403 | return a; 1404 | } 1405 | // 函数 1 1406 | int main() { 1407 | /* 局部变量声明与初始化 */ 1408 | int i=0, j, t, controller = 1, condition = 0; 1409 | /** 1410 | * @note Statements, Control Flows, Scopes 1411 | **/ 1412 | /* 空循环 */ 1413 | while (1); 1414 | while (1) { } // 空语句块 1415 | 1416 | /* 嵌套循环 */ 1417 | while ( 1 ) { 1418 | while ( controller ) { 1419 | controller = controller+1; 1420 | /* If-else 语句 */ 1421 | if ( controller < 10) 1422 | continue; // continue语句 1423 | else { 1424 | HelloWorld(); 1425 | break; // break语句 1426 | } 1427 | } 1428 | 1429 | } 1430 | /* else 悬挂 */ 1431 | if ( 1 ) 1432 | if ( 2 ) i = 333; 1433 | else i = 955; 1434 | else if ( 3 ) i = 666; 1435 | else i = 233; 1436 | /* 语句块嵌套 */ 1437 | t = -5; 1438 | { int t = 6; 1439 | { int t = 10; 1440 | { int t = 0; 1441 | t = t * 10; // 乘除加减模运算 + 赋值 1442 | t = t / 10; 1443 | t = t + 10; 1444 | t = t - 10; 1445 | t = t % 5; 1446 | } 1447 | } 1448 | } 1449 | /* 空 */ 1450 | ;;;;;; 1451 | /** 1452 | * @note 表达式 1453 | **/ 1454 | 1455 | /* 运算符 */ 1456 | 1457 | // 逻辑运算 SysY语言中逻辑运算必须在Cond或while语句中 1458 | if (1 && 2) { 1459 | if (3 || 0) { 1460 | // 比较运算符 1461 | while( i !=0 && j >= 0 ) { 1462 | i = i - 1; 1463 | j = j - 1; 1464 | } 1465 | } 1466 | } 1467 | // 其他的比较运算符 1468 | if (a > 2) 1469 | if (a <10) 1470 | if(a >= 5) 1471 | if(a <= 8) 1472 | a = 4; 1473 | 1474 | // 单目运算符 1475 | thisIsAnArray[0][0][1] = max(1,2); 1476 | thisIsAnArray[0][0][1]; 1477 | -thisIsAnArray[0][0][1]; 1478 | (thisIsAnArray[0][0][1]); 1479 | (3+4 * thisIsAnArray[0][0][1]); 1480 | 1481 | /* 运算符优先级 */ 1482 | // SysY语言文法本身就体现了优先级和结合性 1483 | if(0 && 1) { 1484 | i = 0; 1485 | } 1486 | if (1 || 0) { 1487 | i = 2 - 1 * -1; 1488 | } 1489 | return 0; 1490 | } 1491 | ``` 1492 | 1493 | **语法分析的结果:**可视化语法树(部分) 1494 | 1495 | Image text 1496 | 1497 | 1498 | 1499 | 语法树可视化工具采用**graphviz**将**语法树**的**dot文件转换为结构图**([在线转换工具](https://dreampuf.github.io/GraphvizOnline))。 1500 | 1501 | 其中将内存中的语法树转换为dot文件的代码在**visast.c**中。 1502 | 1503 | 1504 | 1505 | 在用我们复杂的测试输入下得到以上复杂的树,我们仔细的检查了输出的每一个部分。结果是**所有的文法成分都按预期解析**,有合理的优先级和结合性。由此,**我们可以论定我们的语法分析程序通过测试**。 1506 | 1507 | 1508 | 1509 | ### 5.3 语义分析 1510 | 1511 | 语义分析部分包括符号表的创建、查找、删除,scope的解析,以及类型检查。 1512 | 1513 | 下面给出相关测试用例。 1514 | 1515 | 每个用例仅在其中一行含有语义错误。某些语义错误可能会产生连锁反应。 1516 | 1517 | #### 样例1 1518 | 1519 | **输入:** 1520 | 1521 | ```C 1522 | int get(int x) { 1523 | x2 = 1; // 变量未定义 1524 | } 1525 | ``` 1526 | 1527 | **输出:** 1528 | 1529 | sem_test1 1530 | 1531 | 1532 | 1533 | #### 样例2 1534 | 1535 | **输入:** 1536 | 1537 | ```C 1538 | int cmp(int x, int y) { 1539 | int b = max(x,y); // 未定义函数 1540 | if(b == x) { 1541 | return 1; 1542 | } 1543 | else 1544 | return 0; 1545 | } 1546 | ``` 1547 | 1548 | **输出:** 1549 | 1550 | sem_test2 1551 | 1552 | 1553 | 1554 | #### 样例3 1555 | 1556 | **输入:** 1557 | 1558 | ```C 1559 | int Inf() { 1560 | return 10000; 1561 | } 1562 | int Inf() { 1563 | return -10000; 1564 | } // 函数重名 1565 | ``` 1566 | 1567 | **输出:** 1568 | 1569 | sem_test3 1570 | 1571 | 1572 | 1573 | #### 样例4 1574 | 1575 | **输入:** 1576 | 1577 | ```C 1578 | void func() { 1579 | return 5; //实际返回值类型和声明的返回值类型int不一致 1580 | } 1581 | ``` 1582 | 1583 | **输出:** 1584 | 1585 | ![sem_test4](实验报告.assets/sem_test4.png) 1586 | 1587 | 1588 | 1589 | #### 样例5 1590 | 1591 | **输入:** 1592 | 1593 | ```C 1594 | int maxThree(int a, int b, int c) { 1595 | return a; 1596 | } 1597 | int main() { 1598 | int b = maxThree(1,2); // 实参数目与形参不符 1599 | } 1600 | ``` 1601 | 1602 | **输出:** 1603 | 1604 | sem_test5 1605 | 1606 | 1607 | 1608 | #### 样例6 1609 | 1610 | **输入:** 1611 | 1612 | 下面的测试用例包含**多个语义错误**。同一个语义错误可能会有连锁反应。 1613 | 1614 | ```C 1615 | void x = 1; // 定义变量类型不能是void 1616 | int y = 1/0; // 除运算, 被除数不能是0 1617 | int a = 1, b = 2; 1618 | int add(int a, int b) { 1619 | return a+b; 1620 | } 1621 | const int c = add(a,b); // 常量表达式中不能出现函数 1622 | int mulDimArr[4][5][-1]; //数组的维度必须是正数 1623 | 1624 | int func(void a) { // 函数形参不能是void 1625 | return 1; 1626 | } 1627 | ``` 1628 | 1629 | **输出:** 1630 | 1631 | sem_test6 1632 | 1633 | 1634 | 1635 | ### 5.4 IR生成 1636 | 1637 | 我们使用5.2节第1部分的样例(语法正确,包含SysY所有语法细节)对我们的程序进行了测试,结果显示我们的程序能够成功且正确地输出中间代码。**但由于生成结果长达300+行,限于篇幅,我们此处仅通过一些小的样例来展示IR生成的结果。** 1638 | 1639 | #### 样例1 1640 | 1641 | **输入:** 1642 | 1643 | ```c 1644 | int x = 3; 1645 | int b(int x) 1646 | { 1647 | return x; 1648 | } 1649 | int main() 1650 | { 1651 | int x=5; 1652 | while(x==1){ 1653 | if(!x) { 1654 | int c = b(x); 1655 | break; 1656 | } else { 1657 | x; 1658 | } 1659 | continue; 1660 | } 1661 | return b(x); 1662 | } 1663 | ``` 1664 | 1665 | **样例目的:** 1666 | 1667 | 测试`if`及`while`循环、`break`及`continue`语句,函数调用、局部变量和全局变量。 1668 | 1669 | **输出:** 1670 | 1671 | ``` 1672 | v1 := #3 1673 | FUNCTION b : 1674 | PARAM v2 1675 | t1 := v2 1676 | RETURN t1 1677 | FUNCTION main : 1678 | v3 := #5 1679 | LABEL label1 : 1680 | t2 := v3 1681 | t3 := #1 1682 | IF t2 == t3 GOTO label2 1683 | GOTO label3 1684 | LABEL label2 : 1685 | t4 := #0 1686 | t5 := v3 1687 | IF t5 != #0 GOTO label7 1688 | t4 := #1 1689 | LABEL label7 : 1690 | IF t4 != #0 GOTO label4 1691 | GOTO label5 1692 | LABEL label4 : 1693 | t6 := v3 1694 | ARG t6 1695 | v4 := CALL b 1696 | GOTO label3 1697 | GOTO label6 1698 | LABEL label5 : 1699 | t7 := v3 1700 | LABEL label6 : 1701 | GOTO label1 1702 | GOTO label1 1703 | LABEL label3 : 1704 | t9 := v3 1705 | ARG t9 1706 | t8 := CALL b 1707 | RETURN t8 1708 | ``` 1709 | 1710 | **解释:** 1711 | 1712 | 第1行的`v1 := #3`对应全局变量定义`int x = 3;` 1713 | 1714 | 第2-5行对应`int b(int x)`函数,它首先定义了函数`b`和其参数`x`,然后定义将`x`的值赋给一临时变量并返回。 1715 | 1716 | 第6行起对应`int main()`函数。 1717 | 1718 | 第7行对应函数内的变量定义`int x=5`。 1719 | 1720 | 第8-13、32行对应`while`循环。第9-11行判断变量`x`的值是否为1,若是则执行`label2`之后的部分,否则执行`label3`之后的部分。 1721 | 1722 | 第14行开始对应`if`部分。第14-17行计算了`!x`。第19行判断`!x`是否为非0数,若是则跳转到`label4`执行`if`体中的部分,否则跳转到`label5`执行`else`中的部分。第22-24行实现了调用函数`b`的部分。第25行对应`break`语句。第28行执行了语句`x;`,即将x的值赋给一临时变量后不做任何操作。第30行对应`continue`语句。 1723 | 1724 | 第33-36行对应`return b(x)`。 1725 | 1726 | 1727 | 1728 | #### 样例2 1729 | 1730 | **输入:** 1731 | 1732 | ```c 1733 | int main() 1734 | { 1735 | int i; 1736 | /* else 悬挂 */ 1737 | if ( 1 ) 1738 | if ( 2 ) i = 333; 1739 | else i = 955; 1740 | else if ( 3 ) i = 666; 1741 | else i = 233; 1742 | } 1743 | ``` 1744 | 1745 | **样例目的:** 1746 | 1747 | 测试`else`悬挂。 1748 | 1749 | **输出:** 1750 | 1751 | ``` 1752 | FUNCTION main : 1753 | t1 := #1 1754 | IF t1 != #0 GOTO label1 1755 | GOTO label2 1756 | LABEL label1 : 1757 | t2 := #2 1758 | IF t2 != #0 GOTO label4 1759 | GOTO label5 1760 | LABEL label4 : 1761 | t3 := #333 1762 | v1 := t3 1763 | GOTO label6 1764 | LABEL label5 : 1765 | t4 := #955 1766 | v1 := t4 1767 | LABEL label6 : 1768 | GOTO label3 1769 | LABEL label2 : 1770 | t5 := #3 1771 | IF t5 != #0 GOTO label7 1772 | GOTO label8 1773 | LABEL label7 : 1774 | t6 := #666 1775 | v1 := t6 1776 | GOTO label9 1777 | LABEL label8 : 1778 | t7 := #233 1779 | v1 := t7 1780 | LABEL label9 : 1781 | LABEL label3 : 1782 | ``` 1783 | 1784 | **解释:** 1785 | 1786 | 第2-4行对应第一个`if`的判断,条件为真时的程序体对应第5-17行,条件为假时的程序体对应第18-29行。 1787 | 1788 | 第6-8行对应`if(2)`的判断,条件为真时的程序体对应第9-12行,条件为假时的程序体对应第13-16行。第17行跳转到`label3`退出`if`部分。 1789 | 1790 | 第19-21行对应`else if(3)`的判断,条件为真时的程序体对应第22-25行,条件为假时执行`else`部分,对应第26-28行。 1791 | 1792 | 1793 | 1794 | #### 样例3 1795 | 1796 | **输入:** 1797 | 1798 | ```c 1799 | int t=3; 1800 | int a(int t) 1801 | { 1802 | t=014; 1803 | { int t = 0x16; 1804 | { int t = 10; 1805 | { int t = 0; 1806 | t = t * 10; // 乘除加减模运算 + 赋值 1807 | t = t / 10; 1808 | t = t + 10; 1809 | t = t - 10; 1810 | t = t % 5; 1811 | } 1812 | } 1813 | } 1814 | } 1815 | ``` 1816 | 1817 | **样例目的:** 1818 | 1819 | 测试四则运算、不同block中的同名变量、八进制和十六进制数。 1820 | 1821 | **输出:** 1822 | 1823 | ``` 1824 | v1 := #3 1825 | FUNCTION a : 1826 | PARAM v2 1827 | t1 := #12 1828 | v2 := t1 1829 | v3 := #22 1830 | v4 := #10 1831 | v5 := #0 1832 | t3 := v5 1833 | t4 := #10 1834 | t2 := t3 * t4 1835 | v5 := t2 1836 | t6 := v5 1837 | t7 := #10 1838 | t5 := t6 / t7 1839 | v5 := t5 1840 | t9 := v5 1841 | t10 := #10 1842 | t8 := t9 + t10 1843 | v5 := t8 1844 | t12 := v5 1845 | t13 := #10 1846 | t11 := t12 - t13 1847 | v5 := t11 1848 | t15 := v5 1849 | t16 := #5 1850 | t14 := t15 % t16 1851 | v5 := t14 1852 | ``` 1853 | 1854 | **解释:** 1855 | 1856 | 第1行对应全局变量`t`,对应的变量名为`v1`。 1857 | 1858 | 第3-5行是对函数`a`的参数`t`进行赋值,对应的变量名为`v2`。值为12(八进制数014)。 1859 | 1860 | 第6行对应第一个block中的`t`,对应的变量名为`v3`。值为22(十六进制数0x16)。 1861 | 1862 | 第7行对应第二个block中的`t`,对应的变量名为`v4`。值为10。 1863 | 1864 | 第8行对应第二个block中的`t`,对应的变量名为`v5`。值为0。 1865 | 1866 | 第9-28行为运算,分为乘、除、加、减、模共五种运算,每种运算对应4行(获取运算符两边的值、做运算、将结果赋给对应变量)。 1867 | 1868 | 1869 | 1870 | #### 样例4 1871 | 1872 | **输入:** 1873 | 1874 | ```c 1875 | const int z[3][2] = {1, {5}, 8, 9}; 1876 | ``` 1877 | 1878 | **样例目的:** 1879 | 1880 | 测试数组初始化和常量数组。 1881 | 1882 | **输出:** 1883 | 1884 | ``` 1885 | DEC v1 24 1886 | t1 := #1 1887 | t2 := v1 + #0 1888 | *t2 := t1 1889 | t3 := #5 1890 | t4 := v1 + #8 1891 | *t4 := t3 1892 | t5 := #8 1893 | t6 := v1 + #16 1894 | *t6 := t5 1895 | t7 := #9 1896 | t8 := v1 + #20 1897 | *t8 := t7 1898 | ``` 1899 | 1900 | **解释:** 1901 | 1902 | 样例中的数组的初始值应当为`{{1, 0}, {5, 0}, {8, 9}}`。 1903 | 1904 | 第1行声明数组,大小为24(数组大小为6个`int`),数组基地址储存在`v1`中。 1905 | 1906 | 第2-4行进行赋值,`v[0]=1`。 1907 | 1908 | 第5-7行进行赋值,`v[2]=5`。 1909 | 1910 | 第8-10行进行赋值,`v[4]=8`。 1911 | 1912 | 第11-13行进行赋值,`v[5]=9`。 1913 | 1914 | 1915 | 1916 | #### 样例5 1917 | 1918 | **输入:** 1919 | 1920 | ```c 1921 | const int b = 2; 1922 | const int z[3][b] = {1, {5}, 0, b}; 1923 | ``` 1924 | 1925 | **样例目的:** 1926 | 1927 | 测试数组下标和初值中含有常量的情况。 1928 | 1929 | **输出:** 1930 | 1931 | ``` 1932 | v1 := #2 1933 | DEC v2 24 1934 | t1 := #1 1935 | t2 := v2 + #0 1936 | *t2 := t1 1937 | t3 := #5 1938 | t4 := v2 + #8 1939 | *t4 := t3 1940 | t5 := #0 1941 | t6 := v2 + #16 1942 | *t6 := t5 1943 | t7 := v1 1944 | t8 := v2 + #20 1945 | *t8 := t7 1946 | ``` 1947 | 1948 | **解释:** 1949 | 1950 | 第1行对常量b赋值。 1951 | 1952 | 第2行声明数组大小,由于这里声明的数组大小为(3*2)个`int`,所以IR中声明的大小为24字节。 1953 | 1954 | 第3-14行为数组初值的赋值,第3-5行对应`z[0][0]=1`,第6-8行对应`z[1][0]=5`,第9-11行对应`z[2][0]=0`,第12-14行对应`z[3][0]=b`。 1955 | 1956 | 1957 | 1958 | #### 样例6 1959 | 1960 | **输入:** 1961 | 1962 | ```c 1963 | int b(int a[]){ 1964 | return a[1]; 1965 | } 1966 | int main(){ 1967 | int a[2][2] = {}; 1968 | int c = b(a[1]); 1969 | } 1970 | ``` 1971 | 1972 | **样例目的:** 1973 | 1974 | 测试数组的一部分作为函数参数的情况。 1975 | 1976 | **输出:** 1977 | 1978 | ``` 1979 | FUNCTION b : 1980 | PARAM v1 1981 | DEC v2 4 1982 | t2 := #1 1983 | t3 := v2 + #0 1984 | *t3 := t2 1985 | t5 := #0 1986 | t4 := #0 + v2 1987 | t4 := *t4 1988 | t4 := t4 * #1 1989 | t5 := t5 + t4 1990 | t5 := t5 * #4 1991 | t1 := v1 + t5 1992 | t1 := *t1 1993 | RETURN t1 1994 | FUNCTION main : 1995 | DEC v3 16 1996 | DEC v5 8 1997 | t7 := #1 1998 | t8 := v5 + #0 1999 | *t8 := t7 2000 | t10 := #0 2001 | t9 := #0 + v5 2002 | t9 := *t9 2003 | t9 := t9 * #2 2004 | t10 := t10 + t9 2005 | t10 := t10 * #4 2006 | t6 := v3 + t10 2007 | ARG t6 2008 | v4 := CALL b 2009 | ``` 2010 | 2011 | **解释:** 2012 | 2013 | 可以看到中间代码分为函数`b`(1-15行)和函数`main`两部分(16-30行)。 2014 | 2015 | 第`3-6`行是处理`a[1]`的维数,由于`a[1]`只有1维,大小即1,所以令`v2[0]=1`。 2016 | 2017 | 第`7-15`行则是计算出`a[1]`的地址,并取其中的值返回。 2018 | 2019 | 第`18-21`行是处理`main`函数中的`a[1]`的维数,原理同第`3-6`行。 2020 | 2021 | 第`22-28`行则是算出`a[1]`的地址,并作为实参。第`29-30`行调用`b`函数,将返回值储存于`c`(对应`v4`)中。 2022 | 2023 | 2024 | 2025 | 2026 | 2027 | #### 样例7 2028 | 2029 | **输入:** 2030 | 2031 | ```c 2032 | int main(){ 2033 | int a=1,b=1; 2034 | if(a && b) { 2035 | return 11; 2036 | } else { 2037 | return 22; 2038 | } 2039 | } 2040 | ``` 2041 | 2042 | **样例目的:** 2043 | 2044 | 测试关系运算符。 2045 | 2046 | **输出:** 2047 | 2048 | ``` 2049 | FUNCTION main : 2050 | v1 := #1 2051 | v2 := #1 2052 | t1 := v1 2053 | IF t1 != #0 GOTO label4 2054 | GOTO label2 2055 | LABEL label4 : 2056 | t2 := v2 2057 | IF t2 != #0 GOTO label1 2058 | GOTO label2 2059 | LABEL label1 : 2060 | t3 := #11 2061 | RETURN t3 2062 | GOTO label3 2063 | LABEL label2 : 2064 | t4 := #22 2065 | RETURN t4 2066 | LABEL label3 : 2067 | ``` 2068 | 2069 | **解释:** 2070 | 2071 | 第`1-2`行对`a`、`b`赋值。 2072 | 2073 | 第`4-5`行首先判断`a`是否为非0数(即为真),若是则跳转到`label4`,否则跳转到`label2`(对应`else`内的部分)。在`label4`中,第`8-9`行判断`b`是否为非0数(即为真),若是则跳转到`label1`,否则跳转到`label2`(对应`else`内的部分)。 2074 | 2075 | 2076 | 2077 | ## 第6章 团队分工 2078 | 2079 | **组长:**黄彦玮 2080 | 2081 | **组员:**田原 鲍奕帆 2082 | 2083 | **具体分工:** 2084 | 2085 | - **Flex+Bison:** 田原、鲍奕帆 2086 | 2087 | - **符号表+类型检查:**田原、黄彦玮 2088 | 2089 | - **IR生成及优化:**鲍奕帆、黄彦玮 2090 | 2091 | - **测试:**黄彦玮 2092 | 2093 | 2094 | 2095 | 本项目采用gitlab进行代码管理,详情见https://gitlab.eduxiji.net/aison/mycompiler.git 2096 | 2097 | type_array 2098 | 2099 | 2100 | 2101 | 2102 | 2103 | 2104 | 2105 | 2106 | 2107 | --------------------------------------------------------------------------------