├── README.md ├── img ├── error0.png ├── error1.png ├── error2.png ├── menu.png ├── tiny+Syntax.png └── tinySyntax.png ├── src ├── global.h ├── lexer.c ├── lexer.h ├── main.c ├── parser.c ├── parser.h ├── util.c └── util.h └── tiny └── test.tiny /README.md: -------------------------------------------------------------------------------- 1 | # TINY+词法分析、语法分析程序实验 2 | 3 | ### 实验概述 4 | 5 | #### 目的 6 | 7 | 扩充已有的样例语言TINY,为扩展TINY语言TINY+构造词法分析和语法分析程序,从而掌握词法分析和语法分析程序的构造方法 8 | 9 | #### 内容 10 | 11 | 了解样例语言TINY及TINY编译器的实现,了解扩展TINY语言TINY+,用EBNF描述TINY+的语法,用C语言扩展TINY的词法分析和语法分析程序,构造TINY+的递归下降语法分析器。 12 | 13 | #### 要求 14 | 15 | 将TINY+源程序翻译成对应的TOKEN序列,并能检查一定的词法错误。将TOKEN序列转换成语法分析树,并能检查一定的语法错误。 16 | 17 | ### TINY语言 18 | 19 | #### lexicon 20 | 21 | + Keywords: **IF ELSE WRITE READ RETURN BEGIN END MAIN INT REAL** 22 | 23 | + Single-character separators:` ;` `,` `(` `)` 24 | 25 | + Single-character operators:`+` `-` `*` `/` 26 | 27 | + Multi-character operators:`:=` `==` `!=` 28 | 29 | + Identifier: An identifier consists of a letter followed by any number of letters or digits. The following are examples of identifiers: x, x2, xx2, x2x, End, END2. Note that **End** is an identifier while **END** is a keyword. The following are not identifiers: 30 | + `IF, WRITE, READ, ...` (keywords are not counted as identifiers) 31 | + `2x `(identifier can not start with a digit) 32 | + Strings in comments are not identifiers. 33 | 34 | + Number is a sequence of digits, or a sequence of digits followed by a dot, and followed by digits. 35 | 36 | ``` 37 | Number -> Digits | Digits '.' Digits 38 | Digits -> Digit | Digit Digits 39 | Digit -> '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 40 | ``` 41 | 42 | + Comments: string between `/**` and `**/`. Comments can be longer than one line. 43 | 44 | #### The EBNF Grammar 45 | 46 | ##### High-level program structures 47 | 48 | ``` 49 | Program -> MethodDecl MethodDecl* 50 | MethodDecl -> Type [MAIN] Id '(' FormalParams ')' Block 51 | FormalParams -> [FormalParam ( ',' FormalParam )* ] 52 | FormalParam -> Type Id 53 | 54 | Type -> INT | REAL 55 | ``` 56 | 57 | ##### Statements 58 | 59 | ``` 60 | Block -> BEGIN Statement* END 61 | 62 | Statement -> Block 63 | | LocalVarDecl 64 | | AssignStmt 65 | | ReturnStmt 66 | | IfStmt 67 | | WriteStmt 68 | | ReadStmt 69 | 70 | LocalVarDecl -> INT Id ';' 71 | | REAL Id ';' 72 | 73 | AssignStmt -> Id := Expression ';' 74 | ReturnStmt -> RETURN Expression ';' 75 | IfStmt -> IF '(' BoolExpression ')' Statement 76 | | IF '(' BoolExpression ')' Statement ELSE Statement 77 | WriteStmt -> WRITE '(' Expression ',' QString ')' ';' 78 | ReadStmt -> READ '(' Id ',' QString ')' ';' 79 | QString is any sequence of characters except double quote itself, enclosed in double quotes. 80 | ``` 81 | 82 | ##### Expressions 83 | 84 | ``` 85 | Expression -> MultiplicativeExpr (( '+' | '-' ) MultiplicativeExpr)* 86 | MultiplicativeExpr -> PrimaryExpr (( '*' | '/' ) PrimaryExpr)* 87 | PrimaryExpr -> Num // Integer or Real numbers 88 | | Id 89 | | '(' Expression ')' 90 | | Id '(' ActualParams ')' 91 | BoolExpression -> Expression '==' Expression 92 | |Expression '!=' Expression 93 | ActualParams -> [Expression ( ',' Expression)*] 94 | ``` 95 | 96 | #### Sample program 97 | 98 | ``` 99 | /** this is a comment line in the sample program **/ 100 | INT f2(INT x, INT y ) 101 | BEGIN 102 | INT z; 103 | z := x*x - y*y; 104 | RETURN z; 105 | END 106 | INT MAIN f1() 107 | BEGIN 108 | INT x; 109 | READ(x, "A41.input"); 110 | INT y; 111 | READ(y, "A42.input"); 112 | INT z; 113 | z := f2(x,y) + f2(y,x); 114 | WRITE (z, "A4.otput"); 115 | END 116 | ``` 117 | 118 | ### TINY+ 119 | 120 | 基于上述TINY语言的定义,对于TINY语言进行以下内容的扩充,构造扩展TINY语言TINY+: 121 | 122 | #### 增加内容 123 | 124 | + Keywords: **WHILE** 、**DO**、**FOR**、**UPTO**、**DOWNTO** 125 | + Single-character operators:`%`(求余运算),`<`,`>`(比较运算符) 126 | 127 | #### New EBNF Grammar 128 | 129 | 以下仅列出与TINY语法相比,有修改的部分: 130 | 131 | ``` 132 | Statement -> Block 133 | | LocalVarDecl 134 | | AssignStmt 135 | | ReturnStmt 136 | | IfStmt 137 | | WriteStmt 138 | | ReadStmt 139 | | WhileStmt 140 | | DoWhileStmt 141 | | ForStmt 142 | 143 | WhileStmt -> WHILE '(' BoolExpression ')' Statement 144 | DoWhileStmt -> DO Statement WHILE '(' BoolExpression ')' 145 | ForStmt -> For AssignStmt UPTO Expression DO Statement 146 | | For AssignStmt DOWNTO Expression DO Statement 147 | 148 | MultiplicativeExpr -> PrimaryExpr (( '*' | '/' | '%' ) PrimaryExpr)* 149 | BoolExpression -> Expression '==' Expression 150 | | Expression '!=' Expression 151 | | Expression '>' Expression 152 | | Expression '<' Expression 153 | ``` 154 | 155 | ### 实验环境 156 | 157 | + OS: Windows 10 158 | + IDE: Visual Studio 2017 159 | + Language: C 160 | 161 | ### 具体实现 162 | 163 | 以下会对于程序做一个简单的分析,完整代码见`src`文件 164 | 165 | #### 词法分析 166 | 167 | 词法分析器的主要工作就是从输入中读取字符,按照预设的规则来识别它们,得到“词法单元对象”——`TOKEN`,然后打印输出即可。 168 | 169 | ##### TOKEN类型 170 | 171 | 基于上文Tiny+程序的定义,可以对于程序中可能会出现的字划分类别,并分别给他们一个标识符,方便我们对于token的操作。 172 | 173 | ```c 174 | // token类型 175 | typedef enum { 176 | // 保留字 177 | IF, ELSE, WRITE, READ, RETURN, BEGIN, END, MAIN, INT, REAL, WHILE, DO, FOR, UPTO, DOWNTO, 178 | 179 | // 分隔符 180 | SEMI, COMMA, LEFTPAREN, RIGHTPAREN, 181 | 182 | // 运算符 183 | ADD, SUB, MUL, DIV, MOD, ASSIGN, EQUAL, UNEQUAL, GT, LT, 184 | 185 | // ID NUM 186 | ID, NUM, QSTR, 187 | 188 | // other 189 | ERROR, ENDFILE 190 | }TokenType; 191 | ``` 192 | 193 | ##### DFA 194 | 195 | 识别Token的主要过程是在确定的有限自动机的状态之间进行切换,通过检查下一个扫描的字符决定跳转到哪个状态。 196 | 197 | 例如,初始状态为`STATUS_START`,此时如果读取到的下一个字符为数字,根据Tiny+语言的词法定义,以数字开头的只可能为数字,所以,我们跳转到`STATUS_NUMBER`状态。进入该状态后,如果下一个字符还是数字,意味着这个数字还没结束,因此保持当前DFA状态不变。当得到的下一个字符为小数点`.`,就跳转到`STATUS_REAL`状态,表示可以确定这个数为小数;如果既不是数字也不是小数点,而是字母,这就意味着违反了标识符不能以数字开头的规定,把当前`token`设为`ERROR`,否则设为 `NUM` ,跳转到`STATUS_DONE`状态,意味着当前的`TOKEN`读取完毕,打印当前`TOKEN`即可,或对于`ERROR`进行处理。 198 | 199 | 在`STATUS_REAL`状态中,我们只要读取到不是数字就马上结束,跳转到`STATUS_DONE`状态,因为不会有两个小数点。 200 | 201 | 又例如,对于像`+`,`-`,`*`,`/`等操作符的读取,实际上是不需要给定一个状态的,因为它只有一个字符,读取后直接跳转到结束状态 202 | 203 | 特别的,在状态机中,我们不特别区分标识符和保留字,而是统一的跳转到`STATUS_ID`状态,只需要在最后查找一下识别得到的字符串是不是保留字即可。 204 | 205 | 本程序中所有的DFA状态如下: 206 | 207 | ```c 208 | // DFA的状态 209 | typedef enum { 210 | STATUS_START, 211 | STATUS_ASSIGN, 212 | STATUS_EQUAL, 213 | STATUS_UNEQUAL, 214 | STATUS_COMMENT, 215 | STATUS_NUMBER, 216 | STATUS_REAL, 217 | STATUS_STR, 218 | STATUS_ID, 219 | STATUS_DONE 220 | }lexStatus; 221 | ``` 222 | 223 | ##### 主函数`getToken` 224 | 225 | 主函数比较长,这里就不贴出了,主要的实现原理在上文已经做了解释,即通过DFA状态转换判断`TOKEN`类型,然后交由打印函数根据`TOKEN`类型进行打印即可。 226 | 227 | 本程序中,`getToken`函数只处理单个`TOKEN`,注意到,我们在之前的`TOKEN`类型定义中,有`ENDFILE`类型,当我们读取到文件末尾时得到的`TOKEN`类型就是`ENDFILE`。所以在外面套一层`while`循环,判断源文件是否结束,即可处理整个程序文件,如下: 228 | 229 | ```c 230 | while (getToken() != ENDFILE); 231 | ``` 232 | 233 | #### 语法分析 234 | 235 | 语法分析采用自顶向下分析法。通过预测分析法,即向前看一个词法单元的形式,确定对于某个非终结符号将要选择的产生式,并采取递归的方式不断的对于非终结符号展开其产生式,最终得到一颗语法生成树。 236 | 237 | ##### 数据结构定义 238 | 239 | 由于我们最终的目标是生成一颗语法分析树,所以有必要对于树节点的类型进行定义,以便于我们在写程序时进行区分。以下是本程序的树节点类型以及节点结构体定义: 240 | 241 | ```c 242 | typedef enum { MethodK, TypeK, ParamK, StmtK, ExpK } NodeKind; 243 | typedef enum { MainK, NormalK } MethodKind; 244 | typedef enum { FormalK, ActualK, NoneK } ParamKind; 245 | typedef enum { ReturnTypeK, IntTypeK, RealTypeK } TypeKind; 246 | typedef enum { IfK, WhileK, DoWhileK, ForK, ReturnK, AssignK, ReadK, WriteK, IntDeclareK, RealDeclareK } StmtKind; 247 | typedef enum { OpK, ConstK, IdK, MethodCallK} ExpKind; 248 | 249 | // 语法分析树结构体 - 多叉树 250 | typedef struct 251 | { 252 | struct TreeNode* child[MAXCHILDREN]; // 当前函数子树 253 | struct TreeNode* sibling; // 指向下一个函数 254 | NodeKind nodekind; // 节点类型 255 | union { MethodKind method; TypeKind type; StmtKind stmt; ExpKind exp; } kind; // 子类型 256 | union { 257 | TokenType token; 258 | int val; 259 | char * name; 260 | } attr; 261 | }TreeNode; 262 | ``` 263 | 264 | ##### 树节点的构建 265 | 266 | 在本程序中,当选择语法分析功能时,语法分析树节点的构建与词法分析同步进行,也就是说,词法分析每得到一个`TOKEN`,就同时检查这个`TOKEN`是否符合语法。 267 | 268 | 树的构造使用递归的方法,主函数如下: 269 | 270 | ```c 271 | TreeNode* parse(void) { 272 | TreeNode * root; 273 | token = getToken(); 274 | root = MethodDecl_Sequence(); 275 | if (token != ENDFILE) { 276 | syntaxError("Code ends before file"); 277 | } 278 | return root; 279 | } 280 | ``` 281 | 282 | 通过分析Tiny+语法我们可以得知,Tiny+程序的主体就是一个一个函数组成的,所以,我们在主函数中,调用了`MethodDecl_Sequence()`函数,该函数会调用`MethodDecl()`函数,创建函数串联起来,而`MethodDecl()`函数,又会向下进一步调用`Block()`……通过这样的方式,我们就实现了自顶向下的语法分析。 283 | 284 | 以下面这个函数说明预测分析的实现: 285 | 286 | ```c 287 | static TreeNode* Statement(void) { 288 | TreeNode* t = NULL; 289 | switch (token) { 290 | case BEGIN: t = Block(); break; 291 | case INT: t = IntLocalVarDeclStmt(); break; 292 | case REAL: t = RealLocalVarDeclStmt(); break; 293 | case ID: t = AssignStmt(); break; 294 | case RETURN: t = ReturnStmt(); break; 295 | case IF: t = IfStmt(); break; 296 | case WHILE: t = WhileStmt(); break; 297 | case DO: t = DoWhileStmt(); break; 298 | case FOR: t = ForStmt(); break; 299 | case WRITE: t = WriteStmt(); break; 300 | case READ: t = ReadStmt(); break; 301 | default: 302 | syntaxError("Unexpected token"); 303 | break; 304 | } 305 | return t; 306 | } 307 | ``` 308 | 309 | 可以看到,该函数用于展开`Statement`,经过对于语法的分析,对于以`Statement`为产生式头的产生式体,不存在左公因子,这也就意味着,我们通过向前看一位(即预测)的方式,就可以确定使用哪个产生式,进而进一步展开了。上述函数的实现就是这个道理,函数中`token`已经是预测得到的结果。而对于产生式体中不存在的`token`,会直接报错。 310 | 311 | ##### 语法树的打印 312 | 313 | 对于整棵树的打印,我按照类似于先序遍历的方式打印节点,这样的顺序可以较好的还原源程序的执行顺序,同时所有的子节点会相对于父节点有一定的缩进,以更好的显示树的层次。具体见源代码中的`printTree()`函数,该函数根据不同的节点类型,执行不同的打印策略。 314 | 315 | 打印的具体结果见后文。 316 | 317 | #### 错误检测与定位 318 | 319 | 本程序在实现上述词法分析和语法分析两大功能的同时,还实现了对于错误的一定程度上的检测,不仅可以提示错误的相关类型,还可以定位错误到行、列。 320 | 321 | 上文提到语法分析和词法分析可以同步进行,得到一个`TOKEN`就进行分析,这同时也方便了我们对于错误的定位,因为本程序正是通过在扫描字符的同时记录当前的行号和列号实现定位功能。 322 | 323 | ### 测试 324 | 325 | 测试文件使用了绝对路径,若想要在自己机器上测试,请修改路径,或者修改`mian.c`中的宏定义`#define TEST TRUE`为`FALSE`,程序会提示要求手动输入TINY代码文件的路径。 326 | 327 | #### 主页面 328 | 329 | ![](./img/menu.png) 330 | 331 | #### TINY代码测试 332 | 333 | 首先,使用提供好的TINY样例代码进行测试:(具体代码见上文) 334 | 335 | ##### 词法分析结果 336 | 337 | 由于结果太长,无法截图,所以对结果进行了复制。 338 | 339 | ```/ 340 | [INPUT] Please enter your choice: 1 341 | [INFO] Lexical analysis start. 342 | (KEYWORD, INT) 343 | (ID, f2) 344 | (SEP, () 345 | (KEYWORD, INT) 346 | (ID, x) 347 | (SEP, ,) 348 | (KEYWORD, INT) 349 | (ID, y) 350 | (SEP, )) 351 | (KEYWORD, BEGIN) 352 | (KEYWORD, INT) 353 | (ID, z) 354 | (SEP, ;) 355 | (ID, z) 356 | (OP, :=) 357 | (ID, x) 358 | (OP, *) 359 | (ID, x) 360 | (OP, -) 361 | (ID, y) 362 | (OP, *) 363 | (ID, y) 364 | (SEP, ;) 365 | (KEYWORD, RETURN) 366 | (ID, z) 367 | (SEP, ;) 368 | (KEYWORD, END) 369 | (KEYWORD, INT) 370 | (KEYWORD, MAIN) 371 | (ID, f1) 372 | (SEP, () 373 | (SEP, )) 374 | (KEYWORD, BEGIN) 375 | (KEYWORD, INT) 376 | (ID, x) 377 | (SEP, ;) 378 | (KEYWORD, READ) 379 | (SEP, () 380 | (ID, x) 381 | (SEP, ,) 382 | (QString, A41.input) 383 | (SEP, )) 384 | (SEP, ;) 385 | (KEYWORD, INT) 386 | (ID, y) 387 | (SEP, ;) 388 | (KEYWORD, READ) 389 | (SEP, () 390 | (ID, y) 391 | (SEP, ,) 392 | (QString, A42.input) 393 | (SEP, )) 394 | (SEP, ;) 395 | (KEYWORD, INT) 396 | (ID, z) 397 | (SEP, ;) 398 | (ID, z) 399 | (OP, :=) 400 | (ID, f2) 401 | (SEP, () 402 | (ID, x) 403 | (SEP, ,) 404 | (ID, y) 405 | (SEP, )) 406 | (OP, +) 407 | (ID, f2) 408 | (SEP, () 409 | (ID, y) 410 | (SEP, ,) 411 | (ID, x) 412 | (SEP, )) 413 | (SEP, ;) 414 | (KEYWORD, WRITE) 415 | (SEP, () 416 | (ID, z) 417 | (SEP, ,) 418 | (QString, A4.output) 419 | (SEP, )) 420 | (SEP, ;) 421 | (KEYWORD, END) 422 | 423 | [INFO] Lexical analysis finished. 424 | ``` 425 | 426 | ##### 语法分析结果 427 | 428 | ![](./img/tinySyntax.png) 429 | 430 | #### TINY+代码测试 431 | 432 | 向原TINY样例代码中加入我们新增的一些关键字和语法,产生如下TINY+测试代码: 433 | 434 | ```/ 435 | /** this is a comment line in the sample program **/ 436 | INT f2(INT x, INT y ) 437 | BEGIN 438 | INT z; 439 | z := 10; 440 | WHILE (z > 0) 441 | z := z % 2; 442 | RETURN z; 443 | END 444 | INT MAIN f1() 445 | BEGIN 446 | INT x; 447 | READ(x, "A41.input"); 448 | INT y; 449 | READ(y, "A42.input"); 450 | INT z; 451 | z := f2(x,y) + f2(y,x); 452 | FOR x := 10; DOWNTO 5 DO y := x; 453 | WRITE (z, "A4.output"); 454 | END 455 | ``` 456 | 457 | ##### 词法分析结果 458 | 459 | ```/ 460 | [INPUT] Please enter your choice: 1 461 | [INFO] Lexical analysis start. 462 | 463 | (KEYWORD, INT) 464 | (ID, f2) 465 | (SEP, () 466 | (KEYWORD, INT) 467 | (ID, x) 468 | (SEP, ,) 469 | (KEYWORD, INT) 470 | (ID, y) 471 | (SEP, )) 472 | (KEYWORD, BEGIN) 473 | (KEYWORD, INT) 474 | (ID, z) 475 | (SEP, ;) 476 | (ID, z) 477 | (OP, :=) 478 | (NUM, 10) 479 | (SEP, ;) 480 | (KEYWORD, WHILE) 481 | (SEP, () 482 | (ID, z) 483 | (OP, >) 484 | (NUM, 0) 485 | (SEP, )) 486 | (ID, z) 487 | (OP, :=) 488 | (ID, z) 489 | (OP, %) 490 | (NUM, 2) 491 | (SEP, ;) 492 | (KEYWORD, RETURN) 493 | (ID, z) 494 | (SEP, ;) 495 | (KEYWORD, END) 496 | (KEYWORD, INT) 497 | (KEYWORD, MAIN) 498 | (ID, f1) 499 | (SEP, () 500 | (SEP, )) 501 | (KEYWORD, BEGIN) 502 | (KEYWORD, INT) 503 | (ID, x) 504 | (SEP, ;) 505 | (KEYWORD, READ) 506 | (SEP, () 507 | (ID, x) 508 | (SEP, ,) 509 | (QString, A41.input) 510 | (SEP, )) 511 | (SEP, ;) 512 | (KEYWORD, INT) 513 | (ID, y) 514 | (SEP, ;) 515 | (KEYWORD, READ) 516 | (SEP, () 517 | (ID, y) 518 | (SEP, ,) 519 | (QString, A42.input) 520 | (SEP, )) 521 | (SEP, ;) 522 | (KEYWORD, INT) 523 | (ID, z) 524 | (SEP, ;) 525 | (ID, z) 526 | (OP, :=) 527 | (ID, f2) 528 | (SEP, () 529 | (ID, x) 530 | (SEP, ,) 531 | (ID, y) 532 | (SEP, )) 533 | (OP, +) 534 | (ID, f2) 535 | (SEP, () 536 | (ID, y) 537 | (SEP, ,) 538 | (ID, x) 539 | (SEP, )) 540 | (SEP, ;) 541 | (KEYWORD, FOR) 542 | (ID, x) 543 | (OP, :=) 544 | (NUM, 10) 545 | (SEP, ;) 546 | (KEYWORD, DOWNTO) 547 | (NUM, 5) 548 | (KEYWORD, DO) 549 | (ID, y) 550 | (OP, :=) 551 | (ID, x) 552 | (SEP, ;) 553 | (KEYWORD, WRITE) 554 | (SEP, () 555 | (ID, z) 556 | (SEP, ,) 557 | (QString, A4.output) 558 | (SEP, )) 559 | (SEP, ;) 560 | (KEYWORD, END) 561 | 562 | [INFO] Lexical analysis finished. 563 | ``` 564 | 565 | ##### 语法分析结果 566 | 567 | ![](./img/tiny+Syntax.png) 568 | 569 | #### 错误测试 570 | 571 | 这里举出一个较为简单的错误,以显示本程序对于错误的检查能力。 572 | 573 | ##### 例一 574 | 575 | 将TINY+代码中,第五行的`z`标识符改为`2z`,由于标识符不允许以数字开头,所以在进行词法分析的时候会报如下错误: 576 | 577 | ![](./img/error0.png) 578 | 579 | ##### 例二 580 | 581 | 将TINY+代码中,第二行的`f2`函数的参数 `(INT x, INT y ) `错误的改为`(FLOAT x, INT y ) `,使用了未定义的类型,在进行语法分析的时候会报如下错误: 582 | 583 | ![](./img/error1.png) 584 | 585 | (注意,词法分析过程对于`FLOAT`并不会报错,因为它会认为这个用户自己定义的一个标识符) 586 | 587 | ##### 例三 588 | 589 | 将TINY+代码中,MAIN函数`f1`中`INT X;`的分号去掉,在进行语法分析的时候会报如下错误: 590 | 591 | ![](./img/error2.png) -------------------------------------------------------------------------------- /img/error0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/img/error0.png -------------------------------------------------------------------------------- /img/error1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/img/error1.png -------------------------------------------------------------------------------- /img/error2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/img/error2.png -------------------------------------------------------------------------------- /img/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/img/menu.png -------------------------------------------------------------------------------- /img/tiny+Syntax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/img/tiny+Syntax.png -------------------------------------------------------------------------------- /img/tinySyntax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/img/tinySyntax.png -------------------------------------------------------------------------------- /src/global.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/src/global.h -------------------------------------------------------------------------------- /src/lexer.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/src/lexer.c -------------------------------------------------------------------------------- /src/lexer.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/src/lexer.h -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/src/main.c -------------------------------------------------------------------------------- /src/parser.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/src/parser.c -------------------------------------------------------------------------------- /src/parser.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/src/parser.h -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielXuuuuu/Tiny_Plus_Compiler/bff34e5a38d638689fe370379cf26d93d15f8110/src/util.c -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #include "global.h" 5 | 6 | void printToken(TokenType token, const char* str); 7 | 8 | TreeNode* NewMethodNode(MethodKind); 9 | TreeNode* NewTypeNode(TypeKind); 10 | TreeNode* NewParamNode(TypeKind); 11 | TreeNode* newStmtNode(StmtKind); 12 | TreeNode* newExpNode(ExpKind); 13 | 14 | void printTree(TreeNode*); 15 | 16 | char* copyString(char*); 17 | void printSpaces(void); 18 | 19 | void menu(void); 20 | #endif // !UTIL_H 21 | -------------------------------------------------------------------------------- /tiny/test.tiny: -------------------------------------------------------------------------------- 1 | /** this is a comment line in the sample program **/ 2 | INT f2(INT x, INT y ) 3 | BEGIN 4 | INT z; 5 | z := 10; 6 | WHILE (z > 0) 7 | z := z % 2; 8 | RETURN z; 9 | END 10 | INT MAIN f1() 11 | BEGIN 12 | INT x; 13 | READ(x, "A41.input"); 14 | INT y; 15 | READ(y, "A42.input"); 16 | INT z; 17 | z := f2(x,y) + f2(y,x); 18 | FOR x := 10; DOWNTO 5 DO y := x; 19 | WRITE (z, "A4.output"); 20 | END --------------------------------------------------------------------------------