├── .gitignore ├── 100days.md ├── LICENSE ├── Makefile ├── README.md ├── inc ├── error_code.h ├── gen.h ├── lex.h ├── meo.h ├── parse.h └── symtable.h ├── sample ├── clgt.c ├── equal.c ├── fibonacci.c ├── for_stmt.c ├── func.c ├── if_stmt.c ├── local_variable.c ├── pointer.c ├── recursion.c ├── relational.c ├── s1.c ├── s2.c ├── s3.c ├── s4.c ├── variable.c └── while_stmt.c ├── src ├── ast.c ├── ast.h ├── gen.c ├── gen_internal.h ├── lex.c ├── log.c ├── log.h ├── meo.c ├── parse.c ├── parse_internal.h ├── symtable.c └── x86_64_asm.c ├── system_struct.png └── test ├── Makefile ├── ast ├── Makefile ├── ast_test.cpp ├── main.cpp └── mock_lex.cpp ├── gen ├── Makefile ├── gen_test.cpp ├── main.cpp └── mock_arch.cpp ├── inc ├── catch.hh └── common.h ├── intergration ├── Makefile ├── main.cpp ├── mock_arch.cpp └── parse_lex_test.cpp ├── lex ├── Makefile ├── lex_test.cpp └── main.cpp └── parse ├── Makefile ├── main.cpp ├── mock_arch.cpp ├── mock_lex.cpp ├── parse_test.cpp └── symtable_test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.out 2 | *.o 3 | *.s 4 | *#* 5 | *data* 6 | G* -------------------------------------------------------------------------------- /100days.md: -------------------------------------------------------------------------------- 1 | # Progress of 100DaysOfCode 2 | ### Day 1 3 | - Create this repo 4 | - Learn how to start the project. 5 | 6 | ### Day 2 7 | - Add templace code + makefile 8 | - Using catch2 framework for testing. 9 | - Study lexical analyzer. 10 | - https://github.com/DoctorWkt/acwj/tree/master/01_Scanner 11 | - https://holub.com/goodies/compiler/compilerDesignInC.pdf 12 | 13 | ### Day 3 14 | - Read "1.3 A Recursive-Descent Expression Compiler" of Compiler design in C 15 | - Add test case to confirm basic arithmetic token of Lexial Analyzer. 16 | - Lexial Analyzer support basic arithmetic token -> current test case PASS ^^ 17 | - TODO: study BNF form ... 18 | 19 | ### Day 4 20 | - Add some test case for lexial analyzer 21 | - Read "1.2 Representing Computer Languages" of Compiler design in C 22 | 23 | ### Day 5,6 24 | - Read "1.2 Representing Computer Languages" of Compiler design in C 25 | - Study parser by "1.3.2 The Basic Parser" & "1.3.3 Improving the Parser" of Compiler design in C 26 | - Prototype parser 27 | 28 | ### Day 7 29 | - Study parser by "1.3.2 The Basic Parser" & "1.3.3 Improving the Parser" of Compiler design in C 30 | - Prototype bare-bone of parser 31 | 32 | ## Day 8 33 | - Study more about parser, a lot of theory :-( 34 | - https://medium.com/basecs/leveling-up-ones-parsing-game-with-asts-d7a6fc2400ff 35 | - https://github.com/DoctorWkt/acwj/tree/master/02_Parser 36 | - "1.3.2 The Basic Parser" & "1.3.3 Improving the Parser" of Compiler design in C 37 | 38 | ## Day 9 39 | - Continue study parse by "Compiler design in C" book. 40 | - Add new test case for basic arithmetic expression with tentative parse API. These all of them are FAIL -> But it is OK because of TDD, add test first, API processing will be implemented later ^^ 41 | 42 | ## Day 10 43 | - Continue study parse by "Compiler design in C" book. 44 | - Scanning overview [Dragon book](https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools) 45 | - Add some new test case for parser. 46 | - Prototype code generate to combine with parse to try some arithmetic expression -> learning by doing. 47 | - Currently result, basic arithmetic expression is correctly parser but -> :bug: "Segmentation fault (core dumped)" -> that is task for Day 11. 48 | ``` 49 | $ echo "(1+2)*3*(4+5)*6;" > s.c 50 | $ cat s.c 51 | (1+2)*3*(4+5)*6; 52 | $ ./meo s.c 53 | r0 = 1 54 | r1 = 2 55 | r0 += r1 56 | r1 = 3 57 | r0 *= r1 58 | r1 = 4 59 | r2 = 5 60 | r1 += r2 61 | r0 *= r1 62 | r1 = 6 63 | r0 *= r1 64 | value = 486 65 | Number or identifier expected 66 | Missing semicolon 67 | Segmentation fault (core dumped) 68 | ``` 69 | 70 | ## Day 11, 12 71 | - Fix :bug: "Segmentation fault (core dumped)" 72 | - Add and excute test code-gen function. 73 | - Improve test parse by adding gen code mock 74 | - Now, **meo** has full modules of pass-2 : lexial analyzer + parser + gen code :laughing: 75 | - Still ton of unknowledge & unclear about compiler :worried: -> just keep SMALL step over and over by #100DaysOfCode. 76 | - Next todo list. 77 | - Fix lexical unit test fail :collision: wtf 78 | - Add intergration test 79 | - Add code to gen current result to x86-64 asm. 80 | 81 | ## Day 13 82 | - Fix lexical unit test fail. 83 | - Study X86-64 instruction 84 | - https://www.systems.ethz.ch/sites/default/files/file/COURSES/2014%20FALL%20COURSES/2014_Fall_SPCA/lectures/x86_64_asm_cheat_sheet.pdf 85 | - https://cs.brown.edu/courses/cs033/docs/guides/x64_cheatsheet.pdf 86 | 87 | ## Day 14 88 | - Support subtract, div operator. 89 | - Add gen asm on x86-64 of current result. 90 | - Using backend of gcc to generate asm to machine instruction. 91 | - Achieve the first milestone :satisfied: 92 | ``` 93 | $ cat sample/s4.c 94 | (2+3)/2*(7-5)+9/3; 95 | $ ./meo sample/s4.c 96 | $ ./a.out 97 | $ echo $? 98 | 7 99 | 100 | $ 101 | $ cat sample/s5.c 102 | (2+1)/2-(7-5)+9/3; 103 | $ ./meo sample/s5.c 104 | $ ./a.out 105 | $ echo $? 106 | 2 107 | ``` 108 | 109 | ## Day 15 110 | - Consider next step, it can be compile sample [s.c](sample/s.c) 111 | - Continue study chapper 2 "Input and Lexical Analysis" of "Compiler design in C" book. 112 | - Add new test case for lexical analyzer 113 | 114 | ## Day 16 115 | - Refine and add parser some identifier at lexical analyzer but ... -> :sleeping: 116 | ``` 117 | ------------------------------------------------------------------------------- 118 | lex test token: int type, L&R bracket, return 119 | ------------------------------------------------------------------------------- 120 | lex_test.cpp:233 121 | ............................................................................... 122 | 123 | lex_test.cpp:258: FAILED: 124 | REQUIRE( T.tok == t.tok ) 125 | with expansion: 126 | 33759920 (0x20322b0) == 5 127 | 128 | =============================================================================== 129 | test cases: 7 | 6 passed | 1 failed 130 | assertions: 107 | 106 passed | 1 failed 131 | ``` 132 | 133 | ## Day 17 134 | - Fix error of lexical analyzer to support more token to cover next step. 135 | - Study symbol table, parser ... It become more complicated. 136 | 137 | ## Day 18 138 | - Reading about parser. 139 | - Compiler design in C 140 | - Compilers: Principles, Techniques, and Tools. [a.k.a Dragon book] 141 | - Consider design Astract Syntax Tree 142 | - https://medium.com/basecs/leveling-up-ones-parsing-game-with-asts-d7a6fc2400ff 143 | 144 | ## Day 19 145 | - Reset from zero, refine knowlege. 146 | - Reading chapter 2 of Dragon book. 147 | 148 | ## Day 20 149 | - Reading "2.3. Syntax-Directed Translation" of Dragon book. 150 | - Consider design AST, add template code. 151 | 152 | ## Day 21 153 | - Implement AST bit by bit. 154 | 155 | ## Day 22 156 | - Continue study theory about parse. 157 | - Refactoring to integrate AST -> code gen. 158 | - Refactoring test to maping with new API of code gen. 159 | - Consider how to support variable 160 | 161 | ## Day 23 162 | - Add print to statement + interpreter support one. 163 | - Implementing symbol table to support variable. 164 | 165 | ## Day 24 166 | - Add simple version of symbol table (poor performance) 167 | - Support scan & parse Equal, Identifier token 168 | - Todo: 169 | - Gen code for Equal, Identifier to support simple version of variable. 170 | 171 | ## Day 25 172 | - Struggling how to process Identifier with specific type and arithmetic operator. -> Need refactor AST. 173 | 174 | ## Day 26 175 | - Supporting variable ... 176 | 177 | ## Day 27 178 | - Just finish firs step to support variable in case interpreter. 179 | 180 | ## Day 28 181 | - Add option to select interpreter or compiler. 182 | - Tentative add x86-64 call printf to display result. 183 | - https://montcs.bloomu.edu/~bobmon/Code/Asm.and.C/hello-asms.html 184 | - https://stackoverflow.com/questions/38335212/calling-printf-in-x86-64-using-gnu-assembler/38335743 185 | 186 | ## Day 29 187 | - Even still having alot of NG design and mess code, but currently variable is supported also compiler and interpreter. 188 | 189 | ## Day 30 190 | - Add log function. 191 | - Maintain test and consider add integration test. 192 | - Consider refine current result. 193 | 194 | ## Day 31 195 | - Add more mock function of ARCH to test parse. 196 | 197 | ## Day 32 198 | - Remove interpreter, consider later if interest. 199 | - Refine lexical analyzer. 200 | - Add intergration test, with pseudo ASM code. 201 | 202 | ## Day 33 203 | - Consider support COMPARISONS. 204 | - Studying "5 Syntax-Directed Translation" of Dragon book. 205 | 206 | ## Day 34 207 | - Update parse to support COMPARISONS (ex: relational operators <, <=, >, >=) 208 | - Study by reading https://github.com/rui314/9cc 209 | 210 | ## Day 35 211 | - Add gen ASM for relational operators <, <=, >, >= 212 | - Support equal op ==, != 213 | - Slightly refactor parse syntax. 214 | - Add parse token: if, else, while, do, for. 215 | 216 | ## Day 36 217 | - Study how to parse IF statement? 218 | 219 | ## Day 37 220 | - Tag v0.2 https://github.com/truongpt/meo/releases/tag/v0.2 221 | 222 | ## Day 38 223 | - Add compiler option to prevent stupid mistake. 224 | - Refactoring parser to prepare support IF statement. 225 | 226 | ## Day 39 227 | - Support parse If statements. 228 | - TODO: code gen for If statements. 229 | 230 | ## Day 40 231 | - code gen for If statements. 232 | - TODO: fix case if (1) {}; 233 | 234 | ## Day 41 235 | - Fix case if (1) {}; 236 | - Support WHILE statement. 237 | 238 | ## Day 42 239 | - Support FOR statement. 240 | - Support initialize when declare variable. 241 | - Fix issue of Assignment operator. 242 | 243 | ## Day 43 244 | - Support compile function step 1. 245 | 246 | ## Day 44 247 | - Study how to return, how to pass parameter to function. 248 | - prototype to confirm return executing. 249 | 250 | ## Day 45 251 | - Update test case to compliane with C syntax. 252 | 253 | ## Day 46 254 | - Fix memory leak -> pass valgrind test. 255 | - Token analizer + Parser for bitwise + logic operator. 256 | 257 | ## Day 47 258 | - Gen asm for bitwise + logic operator. 259 | - Token analizer for string -> prepare for calling printf :D 260 | 261 | ## Day 48 262 | - Consider how to implement function call. 263 | 264 | ## Day 49 265 | - Parse function call. 266 | - TODO: gen ASM of function call. 267 | 268 | ## Day 50 269 | - Support simple version function call, support max 6 input parameters. 270 | - Remove tentative print statement, because now it can be link libc to call printf function. 271 | 272 | ## Day 51 273 | - Study how to support local variable. 274 | 275 | ### Day 52 276 | - Reading "2.7 Symbol Tables" p.85 Dragon book. 277 | - How to manage local variable and global variable? need multi symbol table? 278 | - How to manage local variable following to scope. 279 | - How to generate asm code for local variable ? 280 | 281 | ### Day 53 282 | - **Done** 283 | - Global variable: + slightly update, meo supported global variable. 284 | - Local variable: need alot of work. 285 | - Add member of AstNode to separate global & local variable. 286 | - Update symbol table. 287 | - Manage local variable following to specific scope. 288 | - Mapping variable name with symbol from asm code. 289 | - **Todo** 290 | - Consider how to calculate necessary stack size of function. 291 | - Support local variable. 292 | - Initialize global variable. 293 | 294 | ### Day 54 295 | - **Done** 296 | - Add level for symbol table to manage specific scope. 297 | - Generate asm code for symbol variable. 298 | - error -> debugging. 299 | 300 | - **Todo** 301 | - How to manage local variable at gen code? need more mapping table or shared currently symbol table? good design? 302 | - Don't use symbol table, because target is difference. 303 | - Consider how to calculate necessary stack size of function. 304 | - Support local variable. 305 | - Initialize global variable. 306 | - Maintain test? don't following to TDD :/ 307 | 308 | - **Note** 309 | - Support complete input parameter, now only input variable but not checking it is invalid or not? 310 | - What is good design? 311 | - Parkinson law? only 2x25 minutes/day for meo 312 | - Need improve processing declare varialbe. now it is stupid 313 | 314 | ### Day 55 315 | - Fix mistake local variable, current asm is using 64bit register -> stack area for each buffer must be 8.? 316 | 317 | ### Day 56 318 | - **Done** 319 | - Terminated processing of the function, ret -> todo end label. 320 | - Fix problem not goto exit label in case IF statements. 321 | - Refactoring variable declare 322 | 323 | - **Todo** 324 | - Reduce redundance ASM code in case variable. Notice for compare instruction. 325 | 326 | ### Day 57 327 | - **Done** 328 | - Fix problem variable at pre condition of FOR loop, handle it as local variable. 329 | - Allocated stack size base on local variable. 330 | - **Todo** 331 | - stack size = alignment of 16? need investigate 332 | 333 | ### Day 58 334 | - **Done** 335 | - Support call function without input -> function(void). 336 | - Support received return value of function. 337 | - **Doing** 338 | - Implementing funciton with non-void argument. 339 | 340 | ### Day 59 341 | - **Done** 342 | - Support function (just < 6 input parameters). 343 | - **Todo** 344 | - Support pass expression to function -> re-chec ast_compile_arg 345 | - **Node** 346 | - Careful of left var vs right var. 347 | 348 | ### Day 60 349 | - **Done** 350 | - Support pass expression to function. 351 | - **Todo** 352 | - How to backup register when calling function. 353 | 354 | ### Day 61 355 | - **Done** 356 | - Fix problem because lack free register when return operator. 357 | - **Todo** 358 | - Study call convention of x86-64. 359 | - Free register in case unary tree, example int main() {5;6;} 360 | - **Node** 361 | - https://stackoverflow.com/questions/18024672/what-registers-are-preserved-through-a-linux-x86-64-function-call 362 | 363 | ### Day 62 364 | - Study x86: https://stackoverflow.com/tags/x86/info 365 | - Consider improve ASM code, current it seems stupid. 366 | - Consider how to release register in case unary tree. 367 | 368 | ### Day 63 369 | - Fix bug leak register when compile unary tree. 370 | 371 | ### Day 64 372 | - How to backup register? 373 | - What is call convention of x86-64. 374 | - https://stackoverflow.com/questions/63865026/what-does-it-mean-that-registers-are-preserved-across-function-calls 375 | - https://stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-and-user-space-f 376 | 377 | ### Day 65. 378 | - Continue study call convention. 379 | 380 | ### Day 66 381 | - Do nothing 382 | 383 | ### Day 67 384 | - Add backup/restore register, need more study but tentative backup all register :-) 385 | - https://aaronbloomfield.github.io/pdr/book/x86-64bit-ccc-chapter.pdf 386 | 387 | ### Day 68 388 | - Consider how to process for local variable same name with diff scope. 389 | - **Todo** 390 | - [ ] Support local variable can be same name. 391 | 392 | ### Day 69 393 | - Support local variable can be same name, they are separeted by scope. 394 | - **Todo** 395 | - [ ] Support input arg by directly function return -> f(g(a)); 396 | - [ ] Support: int a, b, c = 1, d = 2; 397 | 398 | ### Day 70 - How to support pointer? 399 | - Check ASM by compiler explore: https://godbolt.org 400 | - https://github.com/DoctorWkt/acwj/tree/master/15_Pointers_pt1 401 | - int *p, k; p = & k; k = k + * p; 402 | - Lexical can not separated dereference vs mul 403 | - Space is always ignored. 404 | - int* p, q; int a = 10; a = a ** p; 405 | - p is int pointer, but q is still int; 406 | 407 | ### Day 71 408 | - Maintain unit test. 409 | - Consider new test case for pointer 410 | 411 | ### Day 72 412 | - Fix bug pass mistake symbol to get ID 413 | - Add new test case to confirm bug (may be clear variable is not enought) 414 | 415 | ### Day 73 416 | - Debugging 417 | 418 | ### Day 74 419 | - Debugging 420 | - Why only integration test error, meo is still with the user case. 421 | - if using variable name "a" -> error, "a1" -> OK 422 | 423 | ### Day 75 424 | - Bug is fixed: lacking initilize variable :/ 425 | - Add new test case to prepare support pointer 426 | 427 | ### Day 76 428 | - Continue study to support pointer 429 | - https://stackoverflow.com/questions/1372811/how-are-array-and-pointer-types-handled-internally-in-c-compilers-int-a-vs 430 | - Reading dragon book 431 | 432 | ### Day 77 433 | - Consider how implement to support pointer 434 | 435 | ### Day 78 436 | - Add parameter to manage pointer level for each symbol item of symbol table to support pointer. 437 | - Considering how to support pointer. 438 | 439 | ### Day 79 440 | - Still pointer 441 | 442 | ### Day 80 443 | - Update parser to support parsing pointer + dereference 444 | 445 | ### Day 81 446 | - Study how to generate ASM for pointer 447 | 448 | ### 2020/10/10: Temporary suspend 449 | - I tentative suspend project to focus more priority task, but I will back and continue until meo becomes self-hosting compiler -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -Werror 2 | LD = gcc 3 | LDFLAGS += 4 | CMNFLAGS := -g -O0 5 | 6 | TARGET = meo 7 | TOP_SRC = src 8 | INC := -Iinc 9 | 10 | SRC := $(TOP_SRC)/meo.c 11 | SRC += $(TOP_SRC)/lex.c 12 | SRC += $(TOP_SRC)/parse.c 13 | SRC += $(TOP_SRC)/symtable.c 14 | SRC += $(TOP_SRC)/ast.c 15 | SRC += $(TOP_SRC)/gen.c 16 | SRC += $(TOP_SRC)/x86_64_asm.c 17 | SRC += $(TOP_SRC)/log.c 18 | 19 | CFLAGS += $(INC) 20 | 21 | # generate dependence file 22 | OBJDIR = . 23 | OBJ += $(SRC:%.c=$(OBJDIR)/%.o) 24 | 25 | # Add target to build library 26 | all:TARGET 27 | 28 | TARGET:$(TARGET) 29 | 30 | $(TARGET):$(OBJ) 31 | $(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) 32 | 33 | $(OBJDIR)/%.o : %.c 34 | $(CC) $(CMNFLAGS) $(CFLAGS) -c $< -o $@ 35 | 36 | clean: 37 | -rm $(OBJ) 38 | -rm $(TARGET) 39 | 40 | .PHONY:clean all TARGET 41 | 42 | -include $(shell mkdir $(OBJDIR) 2>/dev/null) $(wildcard $(OBJDIR)/*.d) 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Meo subset c compiler 2 | 3 | ## Let's start 4 | - **meo** is :cat: in Vietnamese, but now it is subset c compliler 5 | - The project is mainly used to study compiler. 6 | - I use [100DaysOfCode](https://github.com/kallaway/100-days-of-code) strategy, that will make [small step](100days.md) everyday by [rule](https://github.com/kallaway/100-days-of-code/blob/master/rules.md) 7 | - I study base on following. 8 | - Reading [Compiler design in C - Allen I.Holub](https://holub.com/goodies/compiler/compilerDesignInC.pdf) 9 | - Reading [Dragon book](https://www.amazon.com/Compilers-Principles-Techniques-Tools-2nd/dp/0321486811) 10 | - Reference [A Compiler Writing Journey](https://github.com/DoctorWkt/acwj) 11 | 12 | ## Design 13 | - Using design as [four-pass compiler](system_struct.png), which is refered from [Compiler design in C - Allen I.Holub](https://holub.com/goodies/compiler/compilerDesignInC.pdf) 14 | - Each module lexical analyzer, parser, code generation are designed as independent module, it can be easy to replace without any effect other part. 15 | - Each module is designed as multi instance, I plan supporting paralell compiler to increase performance. 16 | 17 | ## Implementation 18 | - First step: only supporting X86-64 + pass 2 (lexical analyzer, parser, code generation). 19 | - Using back end of GCC to generate executed code. 20 | - Using TDD with [catch2](https://github.com/catchorg/Catch2). 21 | - Using [Google coding convention](https://google.github.io/styleguide/cppguide.html). 22 | 23 | ## Current status. 24 | - Can compile all files in [sample](sample), ex [fibonacci.c](sample/fibonacci.c) 25 | - Can compiler recursion, as the fibonacci recursion version [recursion.c](sample/recursion.c) 26 | 27 | ## Todo list 28 | - [x] Support function. 29 | - [x] Function call. 30 | - [x] Global variable & local variable. 31 | - [ ] Structure type. 32 | - [ ] Pointer. 33 | - [ ] Function pointer. 34 | - [ ] All [operator](https://en.cppreference.com/w/c/language/operator_precedence). 35 | - [ ] v..v... 36 | - [ ] Self compile. 37 | -------------------------------------------------------------------------------- /inc/error_code.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #ifndef _ERROR_CODE_H_ 7 | #define _ERROR_CODE_H_ 8 | 9 | enum ErrorCode { 10 | Success, 11 | InParameterInvalid, 12 | OpenFileError, 13 | SyntaxError, 14 | TokenError, 15 | SymbolNotFound, 16 | SymbolTableOver, 17 | VariableDeclared, 18 | LexLimitResource, 19 | ParseLimitResource, 20 | GenLimitResource 21 | }; 22 | #endif // _ERROR_CODE_H_ 23 | -------------------------------------------------------------------------------- /inc/gen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include "meo.h" 9 | 10 | #ifndef _GEN_ASM_H_ 11 | #define _GEN_ASM_H_ 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | enum GenArch { 18 | GenX86_64, 19 | GenArm 20 | }; 21 | 22 | int32_t GenCreate(void); 23 | int32_t GenDestroy(void); 24 | int32_t GenOpen(void** gen_prm, int32_t arch, char* out_file); 25 | int32_t GenClose(void* gen_prm); 26 | 27 | int32_t GenGetLabel(void* gen_prm); 28 | char* GenLoad(void* gen_prm, int32_t value); 29 | char* GenFree(void* gen_prm, char* r); 30 | 31 | char* GenPlus(void* gen_prm, char* r1, char* r2); 32 | char* GenMinus(void* gen_prm, char* r1, char* r2); 33 | char* GenMul(void* gen_prm, char* r1, char* r2); 34 | char* GenDiv(void* gen_prm, char* r1, char* r2); 35 | 36 | char* GenLT(void* gen_prm, char* r1, char* r2); 37 | char* GenLE(void* gen_prm, char* r1, char* r2); 38 | char* GenGE(void* gen_prm, char* r1, char* r2); 39 | char* GenGT(void* gen_prm, char* r1, char* r2); 40 | char* GenEQ(void* gen_prm, char* r1, char* r2); 41 | char* GenNE(void* gen_prm, char* r1, char* r2); 42 | 43 | char* GenOr(void* gen_prm, char* r1, char* r2); 44 | char* GenAnd(void* gen_prm, char* r1, char* r2); 45 | char* GenBitOr(void* gen_prm, char* r1, char* r2); 46 | char* GenBitXor(void* gen_prm, char* r1, char* r2); 47 | char* GenBitAnd(void* gen_prm, char* r1, char* r2); 48 | 49 | char* GenLtJump(void* gen_prm, char* r1, char* r2, char* label); 50 | char* GenLeJump(void* gen_prm, char* r1, char* r2, char* label); 51 | char* GenGeJump(void* gen_prm, char* r1, char* r2, char* label); 52 | char* GenGtJump(void* gen_prm, char* r1, char* r2, char* label); 53 | char* GenEqJump(void* gen_prm, char* r1, char* r2, char* label); 54 | char* GenNeJump(void* gen_prm, char* r1, char* r2, char* label); 55 | char* GenJump(void* gen_prm, char* label); 56 | char* GenZeroJump(void* gen_prm, char* r, char* label); 57 | char* GenLabel(void* gen_prm, char* label); 58 | char* GenStrLabel(void* gen_prm, char* label, char* str); 59 | char* GenFunc(void* gen_prm, char* name, int stack_size); 60 | char* GenFuncArg(void* gen_prm, int arg_order); 61 | char* GenFuncExit(void* gen_prm, char* exit_label, int stack_size); 62 | char* GenFuncCall(void* gen_prm, char* name); 63 | char* GenArg(void* gen_prm, char* arg, int idx); 64 | 65 | void GenOut(void* gen_prm, char* r); 66 | char* GenGlobalVar(void* gen_prm, char* var); 67 | char* GenLocalVar(void* gen_prm, char* var, int size); 68 | char* GenStore(void* gen_prm, char* var, char* r); 69 | char* GenLoadVar(void* gen_prm, char* var); 70 | char* GenReturn(void* gen_prm, char* r, char* exit_label); 71 | 72 | char* GenRegBackup(void* gen_prm); 73 | char* GenRegRestore(void* gen_prm); 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /inc/lex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #ifndef _LEX_H_ 7 | #define _LEX_H_ 8 | 9 | #include 10 | #include 11 | #include "meo.h" 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | int32_t LexCreate(void); 18 | int32_t LexDestroy(void); 19 | int32_t LexOpen(void** lex_prm, const char* file); 20 | int32_t LexClose(void* lex_prm); 21 | int32_t LexProc(void* lex_prm, Token *t); 22 | int32_t LexGetLine(void* lex_prm); 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /inc/meo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef _MEO_H_ 11 | #define _MEO_H_ 12 | 13 | #define MAX_IDENT_LEN 32 14 | #define MAX_STR_LEN 100 // todo: need dynamic 15 | #define MAX_IDENT_CNT 1000 16 | #define MAX_LABEL_LEN 10 17 | 18 | typedef struct Token { 19 | int32_t tok; 20 | union { 21 | int32_t value; 22 | struct { 23 | char id_str[MAX_IDENT_LEN]; 24 | bool left_value; 25 | }; 26 | char str[MAX_STR_LEN]; 27 | }; 28 | int32_t var_id; 29 | } Token; 30 | 31 | enum TokenType{ 32 | TokenEof, 33 | 34 | // operator 35 | TokenPlus, 36 | TokenMinus, 37 | TokenMul, 38 | TokenStar = TokenMul, // for pointer 39 | TokenDiv, 40 | TokenEQ, 41 | TokenNE, 42 | TokenLT, 43 | TokenLE, 44 | TokenGT, 45 | TokenGE, 46 | 47 | // Bitwise 48 | TokenBitAnd, 49 | TokenDereference = TokenBitAnd, // for dereference of pointer 50 | TokenBitOr, 51 | TokenBitXor, 52 | 53 | // Logical 54 | TokenAnd, 55 | TokenOr, 56 | 57 | // loop 58 | TokenIf, 59 | TokenElse, 60 | TokenWhile, 61 | TokenDo, 62 | TokenFor, 63 | 64 | // data type 65 | TokenIntType, 66 | TokenVoidType, 67 | TokenLongType, 68 | 69 | TokenString, 70 | 71 | TokenNumber, 72 | TokenLP, 73 | TokenRP, 74 | TokenLBracket, 75 | TokenRBracket, 76 | TokenComma, 77 | TokenAssign, 78 | 79 | TokenReturn, 80 | TokenEoi, 81 | TokenSemi, 82 | 83 | TokenIdentifier, 84 | }; 85 | 86 | #endif // _MEO_H_ 87 | -------------------------------------------------------------------------------- /inc/parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #ifndef _PARSE_H_ 7 | #define _PARSE_H_ 8 | 9 | #include 10 | #include "meo.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | int32_t ParseCreate(void); 17 | int32_t ParseDestroy(void); 18 | int32_t ParseOpen(void** prm, void* scan_prm, void* gen_prm, bool is_interpreter); 19 | int32_t ParseClose(void* prm); 20 | int32_t ParseProc(void* prm); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /inc/symtable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/08 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #ifndef _SYM_TABLE_H_ 7 | #define _SYM_TABLE_H_ 8 | 9 | #include 10 | #include 11 | #include "meo.h" 12 | #include "error_code.h" 13 | 14 | #define NSYMBOLS 1024 15 | 16 | typedef struct SymbolData { 17 | char name[MAX_IDENT_LEN]; 18 | int32_t type; 19 | int32_t pointer_level; 20 | int32_t level; 21 | int32_t id; 22 | char* label; 23 | union { 24 | int32_t int_value; 25 | float float_value; 26 | }; 27 | } SymbolData; 28 | 29 | enum SymbolType { 30 | SymbolInt, 31 | SymbolFloat 32 | }; 33 | 34 | typedef struct SymbolTable { 35 | SymbolData data[NSYMBOLS]; 36 | int32_t cur_pos; 37 | int32_t cur_id; 38 | } SymbolTable; 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | int32_t symtable_init(SymbolTable* st); 45 | int32_t symtable_add(SymbolTable* st, char* symbol, int level); 46 | int32_t symtable_remove(SymbolTable* st, char* symbol); 47 | int32_t symtable_find(SymbolTable* st, char* symbol, int level); 48 | int32_t symtable_find_valid(SymbolTable* st, char* symbol, int level); 49 | int32_t symtable_get_value(SymbolTable* st, char* symbol, int level); 50 | int32_t symtable_get_id(SymbolTable* st, char* symbol, int level); 51 | int32_t symtable_set_type(SymbolTable* st, char* symbol, int level, int32_t type); 52 | int32_t symtable_set_label(SymbolTable* st, char* symbol, int level, char* lable); 53 | char* symtable_get_label(SymbolTable* st, char* symbol, int level); 54 | int32_t symtable_set_value(SymbolTable* st, char* symbol, int level, int32_t value); 55 | int32_t symtable_clear_level(SymbolTable* st, int32_t level); 56 | int32_t symtable_set_pointer_level(SymbolTable* st, char* symbol, int level, int32_t pointer_level); 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /sample/clgt.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i; 4 | int j; 5 | int k; 6 | i = 1; 7 | j = 2; 8 | k = 3; 9 | k = i + j * k; 10 | int a; 11 | a = i > j; 12 | i = j == j; 13 | return i+k+j; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /sample/equal.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int a; 4 | int b; 5 | a = 1; 6 | b = 2; 7 | return (a == b) + (a != b); 8 | } 9 | -------------------------------------------------------------------------------- /sample/fibonacci.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int pre = 1; 4 | int cur = 1; 5 | int n = 15; 6 | 7 | for (int i = 2; i < n; i=i+1) { 8 | int t = cur; 9 | cur = cur + pre; 10 | pre = t; 11 | } 12 | 13 | printf("So fibonacci in order %d is : %d\n",n,cur); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /sample/for_stmt.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | for (int i = 0; i < 10; i=i+1) { 4 | printf("i = %d\n",i); 5 | } 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /sample/func.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int a = 3; 4 | int b = 2; 5 | if ( a > b) { 6 | return b; 7 | } else { 8 | return 10; 9 | } 10 | return a; 11 | } 12 | -------------------------------------------------------------------------------- /sample/if_stmt.c: -------------------------------------------------------------------------------- 1 | void main() 2 | { 3 | int a; 4 | int b; 5 | a = 1; 6 | b = 2; 7 | if (a >= b) 8 | { 9 | a = 3; 10 | } else { 11 | b = 4; 12 | } 13 | 14 | if (a <= b) 15 | a = 5; 16 | else 17 | b = 6; 18 | 19 | if (a > b) 20 | { 21 | a = 7; 22 | } else if (a == b) { 23 | a = 8; 24 | } else if (a <= b) { 25 | a = 9; 26 | } else { 27 | a = 10; 28 | } 29 | return a; 30 | } 31 | -------------------------------------------------------------------------------- /sample/local_variable.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int b; 4 | b = 1; 5 | { 6 | printf("b1 = %d\n",b); 7 | int b = 0; 8 | b = b+2; 9 | printf("b2 = %d\n",b); 10 | { 11 | b = b+2; 12 | printf("b3 = %d\n",b); 13 | int b = 10; 14 | printf("b4 = %d\n",b); 15 | } 16 | } 17 | printf("b5 = %d\n",b); 18 | } 19 | -------------------------------------------------------------------------------- /sample/pointer.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int *a; 4 | int b = 10; 5 | a = &b; 6 | b = 11; 7 | printf("value a pointer = %d\n",*a); 8 | return a; 9 | } 10 | -------------------------------------------------------------------------------- /sample/recursion.c: -------------------------------------------------------------------------------- 1 | int fibonacci(int n) 2 | { 3 | if (n < 2) return n; 4 | return fibonacci(n-1) + fibonacci(n-2); 5 | } 6 | 7 | int main() 8 | { 9 | int n = 15; 10 | int i = fibonacci(n); 11 | printf("fibonacci order %d = %d\n",n,i); 12 | return 1; 13 | } 14 | -------------------------------------------------------------------------------- /sample/relational.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int x = 0; 4 | x = x + (7 < 9); 5 | x = x + (7 <= 9); 6 | x = x + (7 >= 7); 7 | x = x + (7 <= 7); 8 | x = x + (9 > 7); 9 | x = x + (9 >= 7); 10 | return x; 11 | } 12 | -------------------------------------------------------------------------------- /sample/s1.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int a = 10; 4 | if (a > 10) { 5 | printf("case 1: %d\n",a); 6 | } else { 7 | if (a > 10) { 8 | printf("case 2: %d\n",a); 9 | } else { 10 | 11 | if (a > 10) { 12 | printf("case 3: %d\n",a); 13 | } else { 14 | if (a > 10) { 15 | printf("case 4: %d\n",a); 16 | } else { 17 | printf("case 5: %d\n",a); 18 | } 19 | } 20 | 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sample/s2.c: -------------------------------------------------------------------------------- 1 | int f(int a) 2 | { 3 | 4 | return a+1; 5 | } 6 | int main() 7 | { 8 | int a = f(1); 9 | int b = 2 + f(a+1); 10 | printf("f(1) %d\n",b); 11 | } 12 | -------------------------------------------------------------------------------- /sample/s3.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | return 6/2; 4 | } 5 | -------------------------------------------------------------------------------- /sample/s4.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | return (2+3)/2*(7-5)+9/3; 4 | } 5 | -------------------------------------------------------------------------------- /sample/variable.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int a; 4 | int b; 5 | a= 2; 6 | b= 8; 7 | int c; 8 | c = a+b-3; 9 | a=a+b*a-b; 10 | return a+b*a-b; 11 | } 12 | -------------------------------------------------------------------------------- /sample/while_stmt.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int a; 4 | int b; 5 | a = 1; 6 | b = 2; 7 | while (a < b) { 8 | a = a + b; 9 | } 10 | while (0) {} 11 | return a; 12 | } 13 | -------------------------------------------------------------------------------- /src/ast.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/08 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include "log.h" 8 | #include "ast.h" 9 | #include "lex.h" 10 | #include "gen.h" 11 | #include "parse_internal.h" 12 | 13 | static int32_t tok_2_ast(Token token); 14 | static void ast_tree_free(AstNode* node); 15 | static int32_t invert_ast(int32_t ast_type); 16 | static void* ast_compile_node( 17 | ParseParameter* parse_prm, 18 | AstNode* node, 19 | char* left, 20 | char* right); 21 | static void ast_map_set_label( 22 | ParseParameter* parse_prm, 23 | char* id_str, 24 | char* label); 25 | static char* ast_map_get_label( 26 | ParseParameter* parse_prm, 27 | char* id_str); 28 | static void ast_compile_pre_func( 29 | void* gen_prm, 30 | AstNode* node, 31 | const char* exit_label, 32 | int* local_var_size); 33 | static void* ast_compile_declare( 34 | ParseParameter* parse_prm, 35 | AstNode* node); 36 | 37 | int32_t tok_2_ast (Token token) 38 | { 39 | int32_t ast = -1; 40 | switch (token.tok) { 41 | case TokenPlus: 42 | ast = AstPlus; 43 | break; 44 | case TokenMinus: 45 | ast = AstMinus; 46 | break; 47 | case TokenMul: 48 | ast = AstMul; 49 | break; 50 | case TokenDiv: 51 | ast = AstDiv; 52 | break; 53 | case TokenLT: 54 | ast = AstLT; 55 | break; 56 | case TokenLE: 57 | ast = AstLE; 58 | break; 59 | case TokenGT: 60 | ast = AstGT; 61 | break; 62 | case TokenGE: 63 | ast = AstGE; 64 | break; 65 | case TokenEQ: 66 | ast = AstEQ; 67 | break; 68 | case TokenNE: 69 | ast = AstNE; 70 | break; 71 | case TokenOr: 72 | ast = AstOr; 73 | break; 74 | case TokenAnd: 75 | ast = AstAnd; 76 | break; 77 | case TokenBitOr: 78 | ast = AstBitOr; 79 | break; 80 | case TokenBitXor: 81 | ast = AstBitXor; 82 | break; 83 | case TokenBitAnd: 84 | ast = AstBitAnd; 85 | break; 86 | case TokenNumber: 87 | ast = AstNumber; 88 | break; 89 | case TokenIntType: 90 | ast = AstIntType; 91 | break; 92 | case TokenVoidType: 93 | ast = AstVoidType; 94 | break; 95 | case TokenString: 96 | ast = AstString; 97 | break; 98 | case TokenIdentifier: 99 | ast = AstIdentifier; 100 | break; 101 | case TokenAssign: 102 | ast = AstAssign; 103 | break; 104 | case TokenWhile: 105 | ast = AstWhile; 106 | break; 107 | case TokenReturn: 108 | ast = AstReturn; 109 | break; 110 | default: 111 | MLOG(CLGT,"Can not create AstNode with token: %s\n", tok2str(token.tok)); 112 | } 113 | 114 | return ast; 115 | } 116 | 117 | // NOT logic 118 | static int32_t invert_ast(int32_t ast_type) 119 | { 120 | switch (ast_type) { 121 | case AstLT: 122 | return AstGE; 123 | case AstLE: 124 | return AstGT; 125 | case AstGT: 126 | return AstLE; 127 | case AstGE: 128 | return AstLT; 129 | case AstEQ: 130 | return AstNE; 131 | case AstNE: 132 | return AstEQ; 133 | } 134 | MLOG(CLGT, "Invalid input ast type\n"); 135 | return -1; 136 | } 137 | 138 | AstNode* ast_create_link( 139 | AstNode* left, 140 | AstNode* right) 141 | { 142 | AstNode* node = (AstNode*) malloc(sizeof(AstNode)); 143 | memset(node, 0x00, sizeof(AstNode)); 144 | 145 | node->type = AstLink; 146 | node->left = left; 147 | node->right = right; 148 | return node; 149 | } 150 | 151 | AstNode* ast_create_ifnode( 152 | AstNode* left, 153 | AstNode* mid, 154 | AstNode* right) 155 | { 156 | AstNode* node = (AstNode*) malloc(sizeof(AstNode)); 157 | memset(node, 0x00, sizeof(AstNode)); 158 | 159 | node->type = AstIf; 160 | node->left = left; 161 | node->mid = mid; 162 | node->right = right; 163 | return node; 164 | } 165 | 166 | AstNode* ast_create_func( 167 | AstNode* left, 168 | AstNode* mid, 169 | AstNode* right) 170 | { 171 | AstNode* node = (AstNode*) malloc(sizeof(AstNode)); 172 | memset(node, 0x00, sizeof(AstNode)); 173 | 174 | node->type = AstFunc; 175 | node->left = left; 176 | node->mid = mid; 177 | node->right = right; 178 | return node; 179 | } 180 | 181 | AstNode* ast_create_arg_init( 182 | Token token, 183 | int arg_order) 184 | { 185 | AstNode* var = ast_create_leaf(token); 186 | var->type = AstLeftVar; 187 | 188 | AstNode* arg = (AstNode*) malloc(sizeof(AstNode)); 189 | memset(arg, 0x00, sizeof(AstNode)); 190 | arg->type = AstFuncArg; 191 | arg->arg_order = arg_order; 192 | arg->left = NULL; 193 | arg->right = NULL; 194 | 195 | AstNode* node = (AstNode*) malloc(sizeof(AstNode)); 196 | memset(node, 0x00, sizeof(AstNode)); 197 | node->type = AstAssign; 198 | node->left = var; 199 | node->right = arg; 200 | 201 | return node; 202 | } 203 | AstNode* ast_create_declare( 204 | AstNode* left, 205 | AstNode* right, 206 | int var_type) 207 | { 208 | AstNode* node = (AstNode*) malloc(sizeof(AstNode)); 209 | memset(node, 0x00, sizeof(AstNode)); 210 | 211 | node->type = AstDeclare; 212 | node->var_type = var_type; 213 | node->left = left; 214 | node->right = right; 215 | return node; 216 | } 217 | 218 | 219 | AstNode* ast_create_func_call(void) 220 | { 221 | AstNode* node = (AstNode*) malloc(sizeof(AstNode)); 222 | memset(node, 0x00, sizeof(AstNode)); 223 | node->type = AstFuncCall; 224 | node->left = NULL; 225 | node->right = NULL; 226 | return node; 227 | } 228 | 229 | AstNode* ast_create_arg_pass(AstNode* arg, int arg_order) 230 | { 231 | AstNode* node = (AstNode*) malloc(sizeof(AstNode)); 232 | memset(node, 0x00, sizeof(AstNode)); 233 | node->type = AstArgPass; 234 | node->arg_order = arg_order; 235 | node->left = arg; 236 | node->right = NULL; 237 | return node; 238 | 239 | } 240 | 241 | AstNode* ast_create_node( 242 | Token token, 243 | AstNode* left, 244 | AstNode* right) 245 | { 246 | AstNode* node = (AstNode*) malloc(sizeof(AstNode)); 247 | memset(node, 0x00, sizeof(AstNode)); 248 | 249 | int32_t ast_type = tok_2_ast(token); 250 | switch (ast_type) 251 | { 252 | case AstNumber: 253 | node->value = token.value; 254 | break; 255 | case AstLeftVar: 256 | case AstIdentifier: 257 | //TODO: dangerous code :-o 258 | memset(node->id_str, 0x00, strlen(node->id_str)); 259 | memcpy(node->id_str, token.id_str, strlen(token.id_str)); 260 | if (-1 != token.var_id) { 261 | sprintf(&(node->id_str[strlen(token.id_str)]),"%d",token.var_id); 262 | MLOG(TRACE, "var: %s \n",node->id_str); 263 | } 264 | break; 265 | case AstString: 266 | memcpy(node->str, token.str, strlen(token.str)); 267 | node->str[strlen(token.str)] = '\0'; 268 | break; 269 | default: 270 | MLOG(TRACE, "AstNode %d\n", ast_type); 271 | } 272 | 273 | node->type = ast_type; 274 | node->left = left; 275 | node->right = right; 276 | 277 | return node; 278 | } 279 | 280 | AstNode* ast_create_leaf(Token token) 281 | { 282 | return ast_create_node(token, NULL, NULL); 283 | } 284 | 285 | AstNode* ast_create_unary(Token token, AstNode* left) 286 | { 287 | return ast_create_node(token, left, NULL); 288 | } 289 | 290 | void* ast_compile_if(ParseParameter* parse_prm, AstNode* node) 291 | { 292 | void* gen_prm = parse_prm->gen_prm; 293 | char label_false[10]; 294 | char label_end[10]; 295 | memset(label_false, 0x00, sizeof(label_false)); 296 | memset(label_end, 0x00, sizeof(label_end)); 297 | 298 | sprintf(label_false,"L%d",GenGetLabel(gen_prm)); 299 | if (node->right) { 300 | sprintf(label_end,"L%d",GenGetLabel(gen_prm)); 301 | } 302 | 303 | // Generate condition IF 304 | void* cond_value = ast_compile(parse_prm, node->left); 305 | GenZeroJump(gen_prm, cond_value, label_false); 306 | 307 | // Generation TRUE statements 308 | ast_compile(parse_prm, node->mid); 309 | 310 | // Jump to end if having FALSE statements 311 | if (node->right) { 312 | GenJump(gen_prm, label_end); 313 | } 314 | 315 | GenLabel(gen_prm, label_false); 316 | if (node->right) { 317 | // Generation FALSE statements 318 | ast_compile(parse_prm, node->right); 319 | GenLabel(gen_prm, label_end); 320 | } 321 | return NULL; 322 | } 323 | 324 | void* ast_compile_while(ParseParameter* parse_prm, AstNode* node) 325 | { 326 | void* gen_prm = parse_prm->gen_prm; 327 | char label_start[10]; 328 | char label_end[10]; 329 | memset(label_start, 0x00, sizeof(label_start)); 330 | memset(label_end, 0x00, sizeof(label_end)); 331 | 332 | sprintf(label_start,"L%d",GenGetLabel(gen_prm)); 333 | sprintf(label_end,"L%d",GenGetLabel(gen_prm)); 334 | 335 | GenLabel(gen_prm, label_start); 336 | 337 | // Generate condition WHILE 338 | void* cond_value = ast_compile(parse_prm, node->left); 339 | GenZeroJump(gen_prm, cond_value, label_end); 340 | 341 | // Generation statements 342 | ast_compile(parse_prm, node->right); 343 | 344 | // Jump to start for continue loop 345 | GenJump(gen_prm, label_start); 346 | 347 | // End label 348 | GenLabel(gen_prm, label_end); 349 | 350 | return NULL; 351 | } 352 | 353 | void ast_compile_pre_func( 354 | void* gen_prm, 355 | AstNode* node, 356 | const char* exit_label, 357 | int* local_var_size) 358 | { 359 | if (NULL == node) { 360 | return; 361 | } 362 | 363 | if (AstString == node->type) { 364 | char label_str[10]; 365 | memset(label_str, 0x00, sizeof(label_str)); 366 | sprintf(label_str,".LS%d",GenGetLabel(gen_prm)); 367 | GenStrLabel(gen_prm, label_str, node->str); 368 | 369 | // change string -> label str 370 | memset(node->str, 0x00, sizeof(node->str)); 371 | sprintf(node->str,"$%s",label_str); 372 | } else if (AstReturn == node->type) { 373 | // setting exit label 374 | memset(node->exit_label, 0x00, sizeof(node->exit_label)); 375 | memcpy(node->exit_label, exit_label, strlen(exit_label)); 376 | } else if (AstDeclare == node->type) { 377 | if (AstIntType == node->left->type) { 378 | // TODO: using 4 size 379 | MLOG(TRACE, "var name: %s\n",node->right->id_str); 380 | *local_var_size += 8; 381 | } else { 382 | MLOG(CLGT, "Now, meo only support int type\n"); 383 | } 384 | } 385 | 386 | ast_compile_pre_func(gen_prm, node->left, exit_label, local_var_size); 387 | ast_compile_pre_func(gen_prm, node->mid, exit_label, local_var_size); 388 | ast_compile_pre_func(gen_prm, node->right, exit_label, local_var_size); 389 | } 390 | 391 | void* ast_compile_func(ParseParameter* parse_prm, AstNode* node) 392 | { 393 | void* gen_prm = parse_prm->gen_prm; 394 | char exit_label[10]; 395 | memset(exit_label, 0x00, sizeof(exit_label)); 396 | sprintf(exit_label,"L%d",GenGetLabel(gen_prm)); 397 | 398 | // gen string before 399 | int local_var_size = 0; 400 | ast_compile_pre_func(gen_prm, node, exit_label, &local_var_size); 401 | 402 | //TODO: stack size = alignment of 16? need investigate 403 | local_var_size = ((local_var_size+15)/16)*16; 404 | MLOG(TRACE, "local_var_size %d\n",local_var_size); 405 | 406 | // gen function lable 407 | GenFunc(gen_prm, node->left->id_str, local_var_size); 408 | 409 | // gen input argument 410 | ast_compile(parse_prm, node->mid); 411 | 412 | // gen body 413 | ast_compile(parse_prm, node->right); 414 | 415 | // gen function end 416 | GenFuncExit(gen_prm, exit_label, local_var_size); 417 | return NULL; 418 | } 419 | 420 | void* ast_compile_func_call(ParseParameter* parse_prm, AstNode* node) 421 | { 422 | //gen and pass input parameter. 423 | ast_compile(parse_prm, node->left); 424 | 425 | // call function 426 | return GenFuncCall(parse_prm->gen_prm, node->right->id_str); 427 | } 428 | 429 | char* gen_bin_op(void* gen_prm, char* left, char* right, int type) 430 | { 431 | switch (type) { 432 | case AstPlus: 433 | return GenPlus(gen_prm, left, right); 434 | case AstMinus: 435 | return GenMinus(gen_prm, left, right); 436 | case AstMul: 437 | return GenMul(gen_prm, left, right); 438 | case AstDiv: 439 | return GenDiv(gen_prm, left, right); 440 | case AstBitOr: 441 | return GenBitOr(gen_prm, left, right); 442 | case AstBitXor: 443 | return GenBitXor(gen_prm, left, right); 444 | case AstBitAnd: 445 | return GenBitAnd(gen_prm, left, right); 446 | default: 447 | MLOG(CLGT,"Invalid type binary operator\n"); 448 | return NULL; 449 | } 450 | } 451 | 452 | char* gen_logical_op(void* gen_prm, char* left, char* right, int type) 453 | { 454 | switch (type) { 455 | case AstOr: 456 | return GenOr(gen_prm, left, right); 457 | case AstAnd: 458 | return GenAnd(gen_prm, left, right); 459 | default: 460 | MLOG(CLGT,"Invalid type logical operator\n"); 461 | return NULL; 462 | } 463 | } 464 | 465 | char* gen_relational_op(void* gen_prm, char* left, char* right, int type) 466 | { 467 | switch (type) { 468 | case AstLT: 469 | return GenLT(gen_prm, left, right); 470 | case AstLE: 471 | return GenLE(gen_prm, left, right); 472 | case AstGT: 473 | return GenGT(gen_prm, left, right); 474 | case AstGE: 475 | return GenGE(gen_prm, left, right); 476 | case AstEQ: 477 | return GenEQ(gen_prm, left, right); 478 | case AstNE: 479 | return GenNE(gen_prm, left, right); 480 | default: 481 | MLOG(CLGT,"Invalid type relational operator\n"); 482 | return NULL; 483 | } 484 | } 485 | 486 | char* gen_relational_jump(void* gen_prm, char* left, char* right, char* label, int32_t type) 487 | { 488 | // invert type 489 | int32_t t = invert_ast(type); 490 | switch (t) { 491 | case AstLT: 492 | return GenLtJump(gen_prm, left, right, label); 493 | case AstLE: 494 | return GenLeJump(gen_prm, left, right, label); 495 | case AstGT: 496 | return GenGtJump(gen_prm, left, right, label); 497 | case AstGE: 498 | return GenGeJump(gen_prm, left, right, label); 499 | case AstEQ: 500 | return GenEqJump(gen_prm, left, right, label); 501 | case AstNE: 502 | return GenNeJump(gen_prm, left, right, label); 503 | default: 504 | MLOG(CLGT,"Invalid type relational operator jump\n"); 505 | return NULL; 506 | } 507 | } 508 | 509 | void* ast_compile(ParseParameter* parse_prm, AstNode* node) 510 | { 511 | if (NULL == node) { 512 | // do nothing 513 | MLOG(DEBUG,"NULL node \n"); 514 | return NULL; 515 | } 516 | 517 | switch (node->type) 518 | { 519 | case AstLink: 520 | { 521 | char* l = (char*)ast_compile(parse_prm, node->left); 522 | if (NULL != l) { 523 | MLOG(TRACE, "l = %s\n",l); 524 | GenFree(parse_prm->gen_prm, l); 525 | } 526 | char* r = ast_compile(parse_prm, node->right); 527 | if (NULL != r) { 528 | MLOG(TRACE, "r = %s\n",r); 529 | GenFree(parse_prm->gen_prm, r); 530 | } 531 | return NULL; 532 | } 533 | case AstIf: 534 | return ast_compile_if(parse_prm, node); 535 | case AstWhile: 536 | return ast_compile_while(parse_prm, node); 537 | case AstFunc: 538 | return ast_compile_func(parse_prm, node); 539 | case AstFuncCall: 540 | return ast_compile_func_call(parse_prm, node); 541 | case AstDeclare: 542 | return ast_compile_declare(parse_prm, node); 543 | } 544 | 545 | char *left = NULL, *right = NULL; 546 | if (NULL != node->left) { 547 | left = (char*)ast_compile(parse_prm, node->left); 548 | } 549 | if (NULL != node->right) { 550 | right = (char*)ast_compile(parse_prm, node->right); 551 | } 552 | 553 | return ast_compile_node(parse_prm, node, left, right); 554 | } 555 | 556 | void* ast_compile_declare(ParseParameter* parse_prm, AstNode* node) 557 | { 558 | if (NULL == node || NULL == node->left || NULL == node->right) { 559 | MLOG(CLGT, "Declare tree is not correct\n"); 560 | exit(1); 561 | } 562 | 563 | void* gen_prm = parse_prm->gen_prm; 564 | 565 | // left -> type 566 | // right -> variable name 567 | AstNode* var = node->right; 568 | 569 | char* label = NULL; 570 | if (AstVarGlobal == node->var_type) { 571 | label = GenGlobalVar(gen_prm, var->id_str); 572 | } else if (AstVarLocal == node->var_type) { 573 | //todo: base on variable type (node->left) to decide size 574 | label = GenLocalVar(gen_prm, var->id_str, 8); 575 | } else { 576 | MLOG(CLGT,"Unknow variable type %d\n",node->left->var_type); 577 | } 578 | 579 | /* TODO: Consider how to support variable of each scope can be same name. */ 580 | /* I considered use node->var_level, that is passed from parse processing, but it need more consider. */ 581 | /* At the moment, meo only supports variable name distint */ 582 | // mapping ID -> label 583 | ast_map_set_label(parse_prm, var->id_str, label); 584 | return label; 585 | } 586 | 587 | void* ast_compile_node(ParseParameter* parse_prm, AstNode* node, char* left, char* right) 588 | { 589 | void* gen_prm = parse_prm->gen_prm; 590 | switch (node->type) { 591 | case AstNumber: 592 | return GenLoad(gen_prm,node->value); 593 | case AstIntType: 594 | return node; 595 | case AstLeftVar: 596 | return ast_map_get_label(parse_prm, node->id_str); 597 | case AstIdentifier: 598 | { 599 | char* id_label = ast_map_get_label(parse_prm, node->id_str); 600 | return GenLoadVar(gen_prm, id_label); 601 | } 602 | case AstReturn: 603 | return GenReturn(gen_prm, left, node->exit_label); 604 | case AstFuncArg: 605 | return GenFuncArg(gen_prm, node->arg_order); 606 | case AstArgPass: 607 | return GenArg(parse_prm->gen_prm, left, node->arg_order); 608 | case AstAssign: 609 | return GenStore(gen_prm, left, right); 610 | case AstPlus: 611 | case AstMinus: 612 | case AstMul: 613 | case AstDiv: 614 | case AstBitOr: 615 | case AstBitXor: 616 | case AstBitAnd: 617 | return gen_bin_op(gen_prm, left, right, node->type); 618 | case AstOr: 619 | case AstAnd: 620 | return gen_logical_op(gen_prm, left, right, node->type); 621 | case AstLT: 622 | case AstLE: 623 | case AstGT: 624 | case AstGE: 625 | case AstEQ: 626 | case AstNE: 627 | return gen_relational_op(gen_prm, left, right, node->type); 628 | case AstString: 629 | return node->str; 630 | default: 631 | MLOG(CLGT,"Not yet to support ast type %d\n",node->type); 632 | } 633 | return NULL; 634 | } 635 | 636 | void ast_gen(ParseParameter* parse_prm, AstNode* node) 637 | { 638 | if (parse_prm->is_interpret) { 639 | // todo: 640 | // ast_interpret(parse_prm, node); 641 | } else { 642 | char* r = ast_compile(parse_prm, node); 643 | if (NULL != r) { 644 | MLOG(TRACE, "final reg = %s",r); 645 | GenFree(parse_prm->gen_prm, r); 646 | } 647 | ast_tree_free(node); 648 | } 649 | } 650 | 651 | void ast_tree_free(AstNode* node) 652 | { 653 | if (NULL == node) { 654 | return; 655 | } 656 | ast_tree_free(node->left); 657 | ast_tree_free(node->mid); 658 | ast_tree_free(node->right); 659 | free(node); 660 | } 661 | 662 | void ast_map_init(ParseParameter* parse_prm) 663 | { 664 | parse_prm->var_map_pos = 0; 665 | memset(parse_prm->var_map, 0x00, sizeof(parse_prm->var_map)); 666 | } 667 | 668 | void ast_map_set_label(ParseParameter* parse_prm, char* id_str,char* label) 669 | { 670 | int pos = parse_prm->var_map_pos; 671 | if (pos >= MAX_IDENT_CNT) { 672 | MLOG(CLGT, "Too many variable \n"); 673 | exit(1); 674 | } 675 | 676 | memcpy(parse_prm->var_map[pos].id, id_str, strlen(id_str)); 677 | parse_prm->var_map[pos].label = label; 678 | parse_prm->var_map_pos++; 679 | } 680 | 681 | char* ast_map_get_label(ParseParameter* parse_prm, char* id_str) 682 | { 683 | for (int i = 0; i < parse_prm->var_map_pos; i++) { 684 | if (strlen(parse_prm->var_map[i].id) == strlen(id_str) && 685 | !strncmp(parse_prm->var_map[i].id, id_str, strlen(id_str))) { 686 | return parse_prm->var_map[i].label; 687 | } 688 | } 689 | return NULL; 690 | } 691 | -------------------------------------------------------------------------------- /src/ast.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/08 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | #include 6 | #include 7 | #include "meo.h" 8 | #include "parse_internal.h" 9 | 10 | #ifndef _AST_H_ 11 | #define _AST_H_ 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | typedef struct AstNode { 18 | int32_t type; 19 | union { 20 | int32_t value; 21 | char id_str[MAX_IDENT_LEN]; 22 | char str[MAX_STR_LEN]; 23 | char exit_label[MAX_LABEL_LEN]; 24 | }; 25 | int32_t var_type; 26 | 27 | int32_t var_level; // use to manage local var in scope 28 | int32_t arg_order; // use to handle function argument. 29 | 30 | // if statement: if (left) {mid} else {right}; 31 | // function: left -> function name, mid -> argument, right -> function body 32 | struct AstNode* left; 33 | struct AstNode* mid; 34 | struct AstNode* right; 35 | } AstNode; 36 | 37 | enum AstVarType{ 38 | AstVarGlobal, 39 | AstVarLocal 40 | }; 41 | 42 | enum AstType { 43 | AstPlus, 44 | AstMinus, 45 | AstMul, 46 | AstDiv, 47 | 48 | AstLT, 49 | AstLE, 50 | AstGT, 51 | AstGE, 52 | AstEQ, 53 | AstNE, 54 | 55 | AstDeclare, 56 | AstNumber, 57 | AstIntType, 58 | AstVoidType, 59 | AstString, 60 | AstIdentifier, 61 | 62 | AstLeftVar, 63 | AstRightVar, 64 | AstAssign, 65 | 66 | AstBitAnd, 67 | AstBitOr, 68 | AstBitXor, 69 | AstAnd, 70 | AstOr, 71 | 72 | AstIf, 73 | AstWhile, 74 | AstFunc, 75 | AstFuncArg, 76 | 77 | AstFuncCall, 78 | AstArgPass, 79 | AstReturn, 80 | // Link statements 81 | AstLink 82 | }; 83 | 84 | AstNode* ast_create_node(Token token, AstNode* left, AstNode* right); 85 | AstNode* ast_create_leaf(Token token); 86 | AstNode* ast_create_unary(Token token, AstNode* left); 87 | AstNode* ast_create_link(AstNode* left, AstNode* right); 88 | AstNode* ast_create_ifnode(AstNode* left, AstNode* mid, AstNode* right); 89 | AstNode* ast_create_func(AstNode* left, AstNode* mid, AstNode* right); 90 | AstNode* ast_create_arg_init(Token token, int arg_order); 91 | AstNode* ast_create_leaf(Token token); 92 | AstNode* ast_create_func_call(void); 93 | AstNode* ast_create_arg_pass(AstNode* arg, int arg_order); 94 | 95 | AstNode* ast_create_declare(AstNode* left, AstNode* right, int var_type); 96 | AstNode* ast_interpret(ParseParameter* parse_prm, AstNode* node); 97 | void* ast_compile(ParseParameter* parse_prm, AstNode* node); 98 | void ast_gen(ParseParameter* parse_prm, AstNode* node); 99 | 100 | void ast_map_init(ParseParameter* parse_prm); 101 | 102 | #ifdef __cplusplus 103 | } 104 | #endif 105 | 106 | #endif /* _AST_H_ */ 107 | -------------------------------------------------------------------------------- /src/gen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "gen.h" 11 | #include "meo.h" 12 | #include "error_code.h" 13 | #include "log.h" 14 | #include "gen_internal.h" 15 | 16 | typedef struct GenParameter{ 17 | bool avail; 18 | FILE* out_asm_file; 19 | GenFuncTable func; 20 | int32_t label_id; 21 | } GenParameter; 22 | 23 | #define MAX_GEN_RSC 10 24 | GenParameter g_gen_prm[MAX_GEN_RSC]; 25 | 26 | int32_t GenCreate(void) 27 | { 28 | for (int i = 0; i < MAX_GEN_RSC; i++) { 29 | g_gen_prm[i].avail = true; 30 | } 31 | return Success; 32 | } 33 | 34 | int32_t GenDestroy(void) 35 | { 36 | for (int i = 0; i < MAX_GEN_RSC; i++) { 37 | g_gen_prm[i].avail = true; 38 | } 39 | return Success; 40 | } 41 | 42 | int32_t GenOpen(void** gen_prm, int32_t arch, char* out_file_name) 43 | { 44 | if (NULL != *gen_prm || NULL == out_file_name) { 45 | return InParameterInvalid; 46 | } 47 | int i = 0; 48 | for (i = 0; i < MAX_GEN_RSC; i++) { 49 | if (true == g_gen_prm[i].avail) { 50 | g_gen_prm[i].avail = false; 51 | break; 52 | } 53 | } 54 | if (MAX_GEN_RSC == i) { 55 | return GenLimitResource; 56 | } 57 | 58 | memset(&(g_gen_prm[i]), 0x00, sizeof(g_gen_prm[i])); 59 | g_gen_prm[i].out_asm_file = fopen(out_file_name, "w"); 60 | g_gen_prm[i].label_id = 0; 61 | if (NULL == g_gen_prm[i].out_asm_file) { 62 | return OpenFileError; 63 | } 64 | switch (arch) { 65 | case GenX86_64: 66 | GenLoadX86_64(&(g_gen_prm[i].func)); 67 | break; 68 | default: 69 | printf("Unsupported\n"); 70 | } 71 | *gen_prm = &g_gen_prm[i]; 72 | return Success; 73 | } 74 | 75 | int32_t GenClose(void* gen_prm) 76 | { 77 | if (NULL == gen_prm) { 78 | return InParameterInvalid; 79 | } 80 | 81 | GenParameter* l_gen_prm = (GenParameter*)gen_prm; 82 | fclose(l_gen_prm->out_asm_file); 83 | 84 | return Success; 85 | } 86 | 87 | int32_t GenGetLabel(void* gen_prm) 88 | { 89 | GenParameter* prm = (GenParameter*)gen_prm; 90 | if (prm->label_id == INT_MAX) { 91 | MLOG(CLGT,"Too much label \n"); 92 | exit(1); 93 | } 94 | return prm->label_id++; 95 | } 96 | 97 | char* GenLoad(void* gen_prm, int32_t value) 98 | { 99 | GenParameter* prm = (GenParameter*)gen_prm; 100 | return prm->func.f_load(value, prm->out_asm_file); 101 | } 102 | 103 | char* GenFree(void* gen_prm, char* r) 104 | { 105 | GenParameter* prm = (GenParameter*)gen_prm; 106 | return prm->func.f_free(r, prm->out_asm_file); 107 | } 108 | 109 | char* GenPlus(void* gen_prm, char* r1, char* r2) 110 | { 111 | GenParameter* prm = (GenParameter*)gen_prm; 112 | return prm->func.f_add(r1, r2, prm->out_asm_file); 113 | } 114 | 115 | char* GenMinus(void* gen_prm, char* r1, char* r2) 116 | { 117 | GenParameter* prm = (GenParameter*)gen_prm; 118 | return prm->func.f_sub(r1, r2, prm->out_asm_file); 119 | } 120 | 121 | char* GenMul(void* gen_prm, char* r1, char* r2) 122 | { 123 | GenParameter* prm = (GenParameter*)gen_prm; 124 | return prm->func.f_mul(r1, r2, prm->out_asm_file); 125 | } 126 | 127 | char* GenDiv(void* gen_prm, char* r1, char* r2) 128 | { 129 | GenParameter* prm = (GenParameter*)gen_prm; 130 | return prm->func.f_div(r1, r2, prm->out_asm_file); 131 | } 132 | 133 | char* GenLT(void* gen_prm, char* r1, char* r2) 134 | { 135 | GenParameter* prm = (GenParameter*)gen_prm; 136 | return prm->func.f_lt(r1, r2, prm->out_asm_file); 137 | } 138 | 139 | char* GenLE(void* gen_prm, char* r1, char* r2) 140 | { 141 | GenParameter* prm = (GenParameter*)gen_prm; 142 | return prm->func.f_le(r1, r2, prm->out_asm_file); 143 | } 144 | 145 | char* GenGT(void* gen_prm, char* r1, char* r2) 146 | { 147 | GenParameter* prm = (GenParameter*)gen_prm; 148 | return prm->func.f_gt(r1, r2, prm->out_asm_file); 149 | } 150 | 151 | char* GenGE(void* gen_prm, char* r1, char* r2) 152 | { 153 | GenParameter* prm = (GenParameter*)gen_prm; 154 | return prm->func.f_ge(r1, r2, prm->out_asm_file); 155 | } 156 | 157 | char* GenEQ(void* gen_prm, char* r1, char* r2) 158 | { 159 | GenParameter* prm = (GenParameter*)gen_prm; 160 | return prm->func.f_eq(r1, r2, prm->out_asm_file); 161 | } 162 | 163 | char* GenNE(void* gen_prm, char* r1, char* r2) 164 | { 165 | GenParameter* prm = (GenParameter*)gen_prm; 166 | return prm->func.f_ne(r1, r2, prm->out_asm_file); 167 | } 168 | 169 | char* GenOr(void* gen_prm, char* r1, char* r2) 170 | { 171 | GenParameter* prm = (GenParameter*)gen_prm; 172 | return prm->func.f_or(r1, r2, prm->out_asm_file); 173 | } 174 | 175 | char* GenAnd(void* gen_prm, char* r1, char* r2) 176 | { 177 | GenParameter* prm = (GenParameter*)gen_prm; 178 | return prm->func.f_and(r1, r2, prm->out_asm_file); 179 | } 180 | 181 | char* GenBitOr(void* gen_prm, char* r1, char* r2) 182 | { 183 | GenParameter* prm = (GenParameter*)gen_prm; 184 | return prm->func.f_b_or(r1, r2, prm->out_asm_file); 185 | } 186 | 187 | char* GenBitXor(void* gen_prm, char* r1, char* r2) 188 | { 189 | GenParameter* prm = (GenParameter*)gen_prm; 190 | return prm->func.f_b_xor(r1, r2, prm->out_asm_file); 191 | } 192 | 193 | char* GenBitAnd(void* gen_prm, char* r1, char* r2) 194 | { 195 | GenParameter* prm = (GenParameter*)gen_prm; 196 | return prm->func.f_b_and(r1, r2, prm->out_asm_file); 197 | } 198 | 199 | char* GenLtJump(void* gen_prm, char* r1, char* r2, char* label) 200 | { 201 | GenParameter* prm = (GenParameter*)gen_prm; 202 | return prm->func.f_lt_j(r1, r2, label, prm->out_asm_file); 203 | } 204 | 205 | char* GenLeJump(void* gen_prm, char* r1, char* r2, char* label) 206 | { 207 | GenParameter* prm = (GenParameter*)gen_prm; 208 | return prm->func.f_le_j(r1, r2, label, prm->out_asm_file); 209 | } 210 | 211 | char* GenGtJump(void* gen_prm, char* r1, char* r2, char* label) 212 | { 213 | GenParameter* prm = (GenParameter*)gen_prm; 214 | return prm->func.f_gt_j(r1, r2, label, prm->out_asm_file); 215 | } 216 | 217 | char* GenGeJump(void* gen_prm, char* r1, char* r2, char* label) 218 | { 219 | GenParameter* prm = (GenParameter*)gen_prm; 220 | return prm->func.f_ge_j(r1, r2, label, prm->out_asm_file); 221 | } 222 | 223 | char* GenEqJump(void* gen_prm, char* r1, char* r2, char* label) 224 | { 225 | GenParameter* prm = (GenParameter*)gen_prm; 226 | return prm->func.f_eq_j(r1, r2, label, prm->out_asm_file); 227 | } 228 | 229 | char* GenNeJump(void* gen_prm, char* r1, char* r2, char* label) 230 | { 231 | GenParameter* prm = (GenParameter*)gen_prm; 232 | return prm->func.f_ne_j(r1, r2, label, prm->out_asm_file); 233 | } 234 | 235 | char* GenJump(void* gen_prm, char* label) 236 | { 237 | GenParameter* prm = (GenParameter*)gen_prm; 238 | return prm->func.f_jump(label, prm->out_asm_file); 239 | } 240 | 241 | char* GenZeroJump(void* gen_prm, char* r, char* label) 242 | { 243 | GenParameter* prm = (GenParameter*)gen_prm; 244 | return prm->func.f_zero_j(r, label, prm->out_asm_file); 245 | } 246 | 247 | char* GenLabel(void* gen_prm, char* label) 248 | { 249 | GenParameter* prm = (GenParameter*)gen_prm; 250 | return prm->func.f_label(label, prm->out_asm_file); 251 | } 252 | 253 | char* GenStrLabel(void* gen_prm, char* label, char* str) 254 | { 255 | GenParameter* prm = (GenParameter*)gen_prm; 256 | return prm->func.f_str_label(label, str, prm->out_asm_file); 257 | } 258 | 259 | char* GenFunc(void* gen_prm, char* name, int stack_size) 260 | { 261 | GenParameter* prm = (GenParameter*)gen_prm; 262 | return prm->func.f_func(name, stack_size, prm->out_asm_file); 263 | } 264 | 265 | char* GenFuncArg(void* gen_prm, int arg_order) 266 | { 267 | GenParameter* prm = (GenParameter*)gen_prm; 268 | return prm->func.f_func_arg(arg_order, prm->out_asm_file); 269 | } 270 | 271 | char* GenFuncExit(void* gen_prm, char* exit_label, int stack_size) 272 | { 273 | GenParameter* prm = (GenParameter*)gen_prm; 274 | return prm->func.f_func_exit(exit_label, stack_size, prm->out_asm_file); 275 | } 276 | 277 | char* GenFuncCall(void* gen_prm, char* name) 278 | { 279 | GenParameter* prm = (GenParameter*)gen_prm; 280 | return prm->func.f_func_call(name, prm->out_asm_file); 281 | } 282 | 283 | char* GenRegBackup(void* gen_prm) 284 | { 285 | GenParameter* prm = (GenParameter*)gen_prm; 286 | return prm->func.f_reg_backup(prm->out_asm_file); 287 | } 288 | 289 | char* GenRegRestore(void* gen_prm) 290 | { 291 | GenParameter* prm = (GenParameter*)gen_prm; 292 | return prm->func.f_reg_restore(prm->out_asm_file); 293 | } 294 | 295 | char* GenArg(void* gen_prm, char* arg, int idx) 296 | { 297 | GenParameter* prm = (GenParameter*)gen_prm; 298 | return prm->func.f_arg(arg, idx, prm->out_asm_file); 299 | } 300 | 301 | void GenOut(void* gen_prm, char* r) 302 | { 303 | GenParameter* prm = (GenParameter*)gen_prm; 304 | prm->func.f_out(r, prm->out_asm_file); 305 | } 306 | 307 | char* GenGlobalVar(void* gen_prm, char* var) 308 | { 309 | GenParameter* prm = (GenParameter*)gen_prm; 310 | return prm->func.f_var(var, prm->out_asm_file); 311 | } 312 | 313 | char* GenLocalVar(void* gen_prm, char* var, int size) 314 | { 315 | GenParameter* prm = (GenParameter*)gen_prm; 316 | return prm->func.f_l_var(var, size, prm->out_asm_file); 317 | } 318 | 319 | char* GenStore(void* gen_prm, char* var, char* r) 320 | { 321 | GenParameter* prm = (GenParameter*)gen_prm; 322 | return prm->func.f_store(var, r, prm->out_asm_file); 323 | } 324 | 325 | char* GenLoadVar(void* gen_prm, char* var) 326 | { 327 | GenParameter* prm = (GenParameter*)gen_prm; 328 | return prm->func.f_load_var(var, prm->out_asm_file); 329 | } 330 | 331 | char* GenReturn(void* gen_prm, char* r, char* exit_label) 332 | { 333 | GenParameter* prm = (GenParameter*)gen_prm; 334 | return prm->func.f_return(r, exit_label, prm->out_asm_file); 335 | } 336 | -------------------------------------------------------------------------------- /src/gen_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | #include 6 | #include 7 | 8 | #ifndef _GEN_ASM_INTERNAL_H_ 9 | #define _GEN_ASM_INTERNAL_H_ 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | typedef struct GenFuncTable { 16 | char* (*f_load)(int32_t value, FILE*); 17 | char* (*f_free)(char* r, FILE*); 18 | char* (*f_out)(char* r, FILE*); 19 | char* (*f_var)(char* var, FILE*); 20 | char* (*f_l_var)(char* var, int size, FILE*); 21 | 22 | char* (*f_add)(char* r1, char* r2, FILE*); 23 | char* (*f_sub)(char* r1, char* r2, FILE*); 24 | char* (*f_mul)(char* r1, char* r2, FILE*); 25 | char* (*f_div)(char* r1, char* r2, FILE*); 26 | char* (*f_lt)(char* r1, char* r2, FILE*); 27 | char* (*f_le)(char* r1, char* r2, FILE*); 28 | char* (*f_gt)(char* r1, char* r2, FILE*); 29 | char* (*f_ge)(char* r1, char* r2, FILE*); 30 | char* (*f_eq)(char* r1, char* r2, FILE*); 31 | char* (*f_ne)(char* r1, char* r2, FILE*); 32 | 33 | char* (*f_or)(char* r1, char* r2, FILE*); 34 | char* (*f_and)(char* r1, char* r2, FILE*); 35 | char* (*f_b_or)(char* r1, char* r2, FILE*); 36 | char* (*f_b_xor)(char* r1, char* r2, FILE*); 37 | char* (*f_b_and)(char* r1, char* r2, FILE*); 38 | 39 | char* (*f_lt_j)(char* r1, char* r2, char* label, FILE*); 40 | char* (*f_le_j)(char* r1, char* r2, char* label, FILE*); 41 | char* (*f_gt_j)(char* r1, char* r2, char* label, FILE*); 42 | char* (*f_ge_j)(char* r1, char* r2, char* label, FILE*); 43 | char* (*f_eq_j)(char* r1, char* r2, char* label, FILE*); 44 | char* (*f_ne_j)(char* r1, char* r2, char* label, FILE*); 45 | char* (*f_zero_j)(char* r, char* label, FILE*); 46 | char* (*f_jump)(char* label, FILE*); 47 | char* (*f_label)(char* label, FILE*); 48 | char* (*f_str_label)(char* label, char* str, FILE*); 49 | 50 | char* (*f_func)(char* name, int stack_size, FILE*); 51 | char* (*f_func_arg)(int arg_order, FILE*); 52 | char* (*f_func_exit)(char* exit_label, int stack_size, FILE*); 53 | char* (*f_func_call)(char* name, FILE*); 54 | char* (*f_arg)(char* arg, int idx, FILE*); 55 | char* (*f_reg_backup)(FILE*); 56 | char* (*f_reg_restore)(FILE*); 57 | 58 | char* (*f_store)(char* var, char* r, FILE*); 59 | char* (*f_load_var)(char* var, FILE*); 60 | char* (*f_return)(char* r, char* exit_label, FILE*); 61 | } GenFuncTable; 62 | 63 | int32_t GenLoadX86_64(GenFuncTable *func); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/lex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "log.h" 13 | #include "lex.h" 14 | #include "error_code.h" 15 | 16 | typedef struct LexParameter{ 17 | bool avail; 18 | int32_t line; 19 | char push_back; 20 | FILE *in_file; 21 | } LexParameter; 22 | 23 | #define MAX_LEX_RSC 10 24 | LexParameter g_lex_prm[MAX_LEX_RSC]; 25 | 26 | static char get_char(LexParameter *prm); 27 | static char get_next(LexParameter *prm); 28 | static void push_back(LexParameter *prm, char c); 29 | static void read_number(LexParameter* lex_prm, char c, Token* t); 30 | static void read_identifier(LexParameter* lex_prm, char c, Token* t); 31 | static void read_string(LexParameter* lex_prm, char c, Token* t); 32 | 33 | int32_t LexCreate(void) 34 | { 35 | for (int i = 0; i < MAX_LEX_RSC; i++) { 36 | g_lex_prm[i].avail = true; 37 | } 38 | return Success; 39 | } 40 | 41 | int32_t LexDestroy(void) 42 | { 43 | for (int i = 0; i < MAX_LEX_RSC; i++) { 44 | g_lex_prm[i].avail = true; 45 | } 46 | return Success; 47 | } 48 | 49 | int32_t LexOpen(void** lex_prm, const char* file_name) 50 | { 51 | if (NULL != *lex_prm || NULL == file_name) { 52 | return InParameterInvalid; 53 | } 54 | 55 | int i = 0; 56 | for (i = 0; i < MAX_LEX_RSC; i++) { 57 | if (true == g_lex_prm[i].avail) { 58 | g_lex_prm[i].avail = false; 59 | break; 60 | } 61 | } 62 | if (MAX_LEX_RSC == i) { 63 | return LexLimitResource; 64 | } 65 | 66 | memset(&(g_lex_prm[i]), 0x00, sizeof(g_lex_prm[i])); 67 | g_lex_prm[i].in_file = fopen(file_name, "r"); 68 | g_lex_prm[i].push_back = -1; // -1 is OK? LOL 69 | g_lex_prm[i].line = 1; 70 | *lex_prm = &g_lex_prm[i]; 71 | return Success; 72 | } 73 | 74 | int32_t LexClose(void* prm) 75 | { 76 | if (NULL == prm) { 77 | return InParameterInvalid; 78 | } 79 | LexParameter* lex_prm = (LexParameter*)prm; 80 | 81 | if (NULL == lex_prm->in_file) return -1; 82 | 83 | fclose(lex_prm->in_file); 84 | lex_prm->avail = true; 85 | 86 | return Success; 87 | } 88 | 89 | int32_t LexProc(void* prm, Token *t) 90 | { 91 | if (NULL == prm || NULL == t) { 92 | return InParameterInvalid; 93 | } 94 | 95 | t->var_id = -1; 96 | LexParameter* lex_prm = (LexParameter*)prm; 97 | char c = get_next(lex_prm); 98 | switch (c) { 99 | case EOF: 100 | t->tok = TokenEoi; 101 | break; 102 | case '+': 103 | t->tok = TokenPlus; 104 | break; 105 | case '-': 106 | t->tok = TokenMinus; 107 | break; 108 | case '*': 109 | t->tok = TokenMul; 110 | break; 111 | case '/': 112 | t->tok = TokenDiv; 113 | break; 114 | case '(': 115 | t->tok = TokenLP; 116 | break; 117 | case ')': 118 | t->tok = TokenRP; 119 | break; 120 | case '{': 121 | t->tok = TokenLBracket; 122 | break; 123 | case '}': 124 | t->tok = TokenRBracket; 125 | break; 126 | case ';': 127 | t->tok = TokenSemi; 128 | break; 129 | case '=': 130 | c = get_char(lex_prm); 131 | if (c == '=') { 132 | t->tok = TokenEQ; 133 | } else { 134 | t->tok = TokenAssign; 135 | push_back(lex_prm, c); 136 | } 137 | break; 138 | case '!': 139 | c = get_char(lex_prm); 140 | if (c == '=') { 141 | t->tok = TokenNE; 142 | } else { 143 | mlog(ERROR,"Not yet support the lexeme\n"); 144 | // push_back(lex_prm, c); 145 | } 146 | break; 147 | case '>': 148 | c = get_char(lex_prm); 149 | if (c == '=') { 150 | t->tok = TokenGE; 151 | } else { 152 | t->tok = TokenGT; 153 | push_back(lex_prm, c); 154 | } 155 | break; 156 | case '<': 157 | c = get_char(lex_prm); 158 | if (c == '=') { 159 | t->tok = TokenLE; 160 | } else { 161 | t->tok = TokenLT; 162 | push_back(lex_prm, c); 163 | } 164 | break; 165 | case '&': 166 | c = get_char(lex_prm); 167 | if (c == '&') { 168 | t->tok = TokenAnd; 169 | } else { 170 | t->tok = TokenBitAnd; 171 | push_back(lex_prm, c); 172 | } 173 | break; 174 | case '|': 175 | c = get_char(lex_prm); 176 | if (c == '|') { 177 | t->tok = TokenOr; 178 | } else { 179 | t->tok = TokenBitOr; 180 | push_back(lex_prm, c); 181 | } 182 | break; 183 | case '^': 184 | t->tok = TokenBitXor; 185 | break; 186 | case '"': 187 | read_string(lex_prm, c, t); 188 | break; 189 | case ',': 190 | t->tok = TokenComma; 191 | break; 192 | case '0' ... '9': 193 | read_number(lex_prm, c, t); 194 | break; 195 | case 'a' ... 'z': 196 | case 'A' ... 'Z': 197 | read_identifier(lex_prm, c, t); 198 | break; 199 | default: 200 | mlog(CLGT, "Syntax Error\n"); 201 | return SyntaxError; 202 | } 203 | return Success; 204 | } 205 | 206 | int32_t LexGetLine(void* prm) 207 | { 208 | if (NULL == prm) { 209 | return -1; 210 | } 211 | LexParameter* lex_prm = (LexParameter*)prm; 212 | return lex_prm->line; 213 | } 214 | 215 | static void read_identifier(LexParameter* lex_prm, char c, Token* t) 216 | { 217 | char id[100] = ""; 218 | int i = 0; 219 | id[i++] = c; 220 | 221 | c = get_char(lex_prm); 222 | while (('a' <= c && c <= 'z') || 223 | ('A' <= c && c <= 'Z') || 224 | ('0' <= c && c <= '9')) { 225 | if (i >= 100) { 226 | mlog(CLGT, "wft identifier too long\n"); 227 | exit(1); 228 | } 229 | id[i++] = c; 230 | c = get_char(lex_prm); 231 | } 232 | 233 | if (!strncmp(id, "int", sizeof("int"))) { 234 | t->tok = TokenIntType; 235 | } else if (!strncmp(id, "void", sizeof("void"))) { 236 | t->tok = TokenVoidType; 237 | } else if (!strncmp(id, "return", sizeof("return"))) { 238 | t->tok = TokenReturn; 239 | } else if (!strncmp(id, "if", sizeof("if"))) { 240 | t->tok = TokenIf; 241 | } else if (!strncmp(id, "else", sizeof("else"))) { 242 | t->tok = TokenElse; 243 | } else if (!strncmp(id, "while", sizeof("while"))) { 244 | t->tok = TokenWhile; 245 | } else if (!strncmp(id, "do", sizeof("do"))) { 246 | t->tok = TokenDo; 247 | } else if (!strncmp(id, "for", sizeof("for"))) { 248 | t->tok = TokenFor; 249 | } else { 250 | t->tok = TokenIdentifier; 251 | memcpy(t->id_str, id, i); 252 | t->id_str[i] = '\0'; 253 | } 254 | push_back(lex_prm, c); 255 | } 256 | 257 | static void read_string(LexParameter* lex_prm, char c, Token* t) 258 | { 259 | char id[100] = ""; 260 | int i = 0; 261 | c = get_char(lex_prm); 262 | while (c != '"') { 263 | if (i >= 100) { 264 | mlog(CLGT, "wft string too long\n"); 265 | exit(1); 266 | } 267 | id[i++] = c; 268 | c = get_char(lex_prm); 269 | } 270 | t->tok = TokenString; 271 | memcpy(t->str, id, i); 272 | t->id_str[i] = '\0'; 273 | } 274 | 275 | 276 | void read_number(LexParameter* lex_prm, char c, Token* t) 277 | { 278 | if ('0' <= c && c <= '9') { 279 | t->value = c - '0'; 280 | t->tok = TokenNumber; 281 | c = get_char(lex_prm); 282 | while ('0' <= c && c <= '9') { 283 | t->value = t->value*10 + c-'0'; 284 | c = get_char(lex_prm); 285 | } 286 | push_back(lex_prm, c); 287 | } 288 | } 289 | 290 | static void push_back(LexParameter *prm, char c) 291 | { 292 | prm->push_back = c; 293 | } 294 | 295 | static char get_next(LexParameter *prm) 296 | { 297 | char c = get_char(prm); 298 | while (c == ' ' || 299 | c == '\t' || 300 | c == '\n' || 301 | c == '\v') { 302 | c = get_char(prm); 303 | } 304 | 305 | return c; 306 | } 307 | 308 | static char get_char(LexParameter *prm) 309 | { 310 | char c; 311 | if (-1 != prm->push_back) { 312 | c = prm->push_back; 313 | prm->push_back = -1; 314 | return c; 315 | } 316 | c = fgetc(prm->in_file); 317 | if ('\n' == c) { 318 | prm->line++; 319 | } 320 | return c; 321 | } 322 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/08 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include "log.h" 7 | 8 | #define RESET "\033[0m" 9 | #define BLACK "\033[30m" /* Black */ 10 | #define RED "\033[31m" /* Red */ 11 | #define GREEN "\033[32m" /* Green */ 12 | #define YELLOW "\033[33m" /* Yellow */ 13 | #define BLUE "\033[34m" /* Blue */ 14 | #define MAGENTA "\033[35m" /* Magenta */ 15 | #define CYAN "\033[36m" /* Cyan */ 16 | #define WHITE "\033[37m" /* White */ 17 | #define BOLDBLACK "\033[1m\033[30m" /* Bold Black */ 18 | #define BOLDRED "\033[1m\033[31m" /* Bold Red */ 19 | #define BOLDGREEN "\033[1m\033[32m" /* Bold Green */ 20 | #define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */ 21 | #define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */ 22 | #define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */ 23 | #define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */ 24 | #define BOLDWHITE "\033[1m\033[37m" /* Bold White */ 25 | 26 | #define LOG_OFF 0xFFFF 27 | static int g_log_level = 2; 28 | 29 | static char* g_log_level_msg[] = { 30 | "TRACE", 31 | "DEBUG", 32 | "INFO", 33 | "WARN", 34 | "ERROR", 35 | "CLGT" // fata error 36 | }; 37 | 38 | static char* g_token_str[] = { 39 | "TokenEof", 40 | "TokenPlus", 41 | "TokenMinus", 42 | "TokenMul", 43 | "TokenDiv", 44 | "TokenEqual", 45 | "TokenNE", 46 | "TokenLT", 47 | "TokenLE", 48 | "TokenGT", 49 | "TokenGE", 50 | "TokenBitAnd", 51 | "TokenBitOr", 52 | "TokenBitXor", 53 | "TokenAnd", 54 | "TokenOr", 55 | "TokenIf", 56 | "TokenElse", 57 | "TokenWhile", 58 | "TokenDo", 59 | "TokenFor", 60 | "TokenIntType", 61 | "TokenVoidType", 62 | "TokenLongType", 63 | "TokenString", 64 | "TokenNumber", 65 | "TokenLP", 66 | "TokenRP", 67 | "TokenLBracket", 68 | "TokenRBracket", 69 | "TokenComma", 70 | "TokenAssign", 71 | "TokenReturn", 72 | "TokenEoi", 73 | "TokenSemi", 74 | "TokenIdentifier" 75 | }; 76 | 77 | void set_mlog_level(int level) 78 | { 79 | g_log_level = level; 80 | } 81 | 82 | char* tok2str(int tok) 83 | { 84 | if (tok >= sizeof(g_token_str)/sizeof(g_token_str[0])) { 85 | return "NULL"; 86 | } 87 | return g_token_str[tok]; 88 | } 89 | 90 | void mlog(int level, char* format, ...) 91 | { 92 | va_list varg; 93 | char buf[4096]; 94 | if (level >= g_log_level || CLGT == level) { 95 | va_start(varg, format); 96 | vsnprintf(buf, sizeof(buf), format, varg); 97 | va_end(varg); 98 | 99 | fprintf(stdout,BOLDRED"[%s] "RESET,g_log_level_msg[level]); 100 | fprintf(stdout, "%s", buf); 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/08 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | #include 6 | #include 7 | 8 | #ifndef _LOG_H_ 9 | #define _LOG_H_ 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #define MLOG(...) do { mlog(__VA_ARGS__);} while(0) 16 | 17 | enum LogLevel { 18 | TRACE, 19 | DEBUG, 20 | INFO, 21 | WARN, 22 | ERROR, 23 | CLGT 24 | }; 25 | 26 | void set_log_level(int level); 27 | void mlog(int level, char* format, ...); 28 | char* tok2str(int tok); 29 | 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/meo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "lex.h" 10 | #include "parse.h" 11 | #include "gen.h" 12 | #include "meo.h" 13 | #include "log.h" 14 | 15 | typedef struct MeoHandle { 16 | void* lex_prm; 17 | void* gen_prm; 18 | void* parse_prm; 19 | } MeoHandle; 20 | 21 | int main(int argc, char*argv[]) 22 | { 23 | if (argc < 2) { 24 | mlog(CLGT,"input parameter error\n"); 25 | return -1; 26 | } 27 | 28 | char* in_file = NULL; 29 | bool is_interpreter = false; 30 | if (!strncmp(argv[1], "-i", sizeof("-i"))) { 31 | is_interpreter = true; 32 | in_file = argv[2]; 33 | } else { 34 | is_interpreter = false; 35 | in_file = argv[1]; 36 | } 37 | 38 | char* out_file = "out.s"; 39 | MeoHandle meo_handle = {NULL, NULL}; 40 | 41 | LexCreate(); 42 | LexOpen(&(meo_handle.lex_prm), in_file); 43 | 44 | GenCreate(); 45 | GenOpen(&(meo_handle.gen_prm), GenX86_64, out_file); 46 | 47 | ParseCreate(); 48 | ParseOpen(&(meo_handle.parse_prm), meo_handle.lex_prm, meo_handle.gen_prm, is_interpreter); 49 | 50 | ParseProc(meo_handle.parse_prm); 51 | 52 | ParseClose(meo_handle.parse_prm); 53 | LexClose(meo_handle.lex_prm); 54 | GenClose(meo_handle.gen_prm); 55 | 56 | LexDestroy(); 57 | GenDestroy(); 58 | ParseDestroy(); 59 | 60 | // using backend of gcc 61 | system("cc -o a.out out.s"); 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/parse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "log.h" 10 | #include "parse.h" 11 | #include "lex.h" 12 | #include "ast.h" 13 | #include "gen.h" 14 | #include "symtable.h" 15 | #include "error_code.h" 16 | 17 | #include "parse_internal.h" 18 | 19 | #define MAX_PARSE_RSC 10 20 | 21 | ParseParameter g_parse_prm[MAX_PARSE_RSC]; 22 | 23 | static AstNode* function_call(ParseParameter* parse_prm, Token tok); 24 | static AstNode* factor(ParseParameter* parse_prm); 25 | static AstNode* mul(ParseParameter* parse_prm); 26 | static AstNode* add(ParseParameter* parse_prm); 27 | static AstNode* relational(ParseParameter* parse_prm); 28 | static AstNode* logic_or(ParseParameter* parse_prm); 29 | static AstNode* logic_and(ParseParameter* parse_prm); 30 | static AstNode* bit_or(ParseParameter* parse_prm); 31 | static AstNode* bit_xor(ParseParameter* parse_prm); 32 | static AstNode* bit_and(ParseParameter* parse_prm); 33 | static AstNode* equal(ParseParameter* parse_prm); 34 | static AstNode* assign(ParseParameter* parse_prm); 35 | static AstNode* expression(ParseParameter* parse_prm); 36 | 37 | static AstNode* syntax_parse(ParseParameter* parse_prm); 38 | static AstNode* statements(ParseParameter* parse_prm, AstNode* root); 39 | static AstNode* stmt_decl(ParseParameter* parse_prm); 40 | static AstNode* stmt_expr(ParseParameter* parse_prm); 41 | static AstNode* stmt_if(ParseParameter* parse_prm); 42 | static AstNode* stmt_while(ParseParameter* parse_prm); 43 | static AstNode* stmt_return(ParseParameter* parse_prm); 44 | static AstNode* stmt_scope(ParseParameter* parse_prm); 45 | static bool match(ParseParameter* parse_prm, int32_t tok_type); 46 | 47 | int32_t ParseCreate(void) 48 | { 49 | for (int i = 0; i < MAX_PARSE_RSC; i++) { 50 | g_parse_prm[i].avail = true; 51 | } 52 | return Success; 53 | } 54 | 55 | int32_t ParseDestroy(void) 56 | { 57 | for (int i = 0; i < MAX_PARSE_RSC; i++) { 58 | g_parse_prm[i].avail = true; 59 | } 60 | return Success; 61 | } 62 | 63 | int32_t ParseOpen(void** parse_prm, void* lex_prm, void* gen_prm, bool is_interpret) 64 | { 65 | if (NULL != *parse_prm || 66 | NULL == lex_prm || 67 | NULL == gen_prm) { 68 | return InParameterInvalid; 69 | } 70 | int i = 0; 71 | for (i = 0; i < MAX_PARSE_RSC; i++) { 72 | if (true == g_parse_prm[i].avail) { 73 | g_parse_prm[i].avail = false; 74 | break; 75 | } 76 | } 77 | if (MAX_PARSE_RSC == i) { 78 | return ParseLimitResource; 79 | } 80 | 81 | memset(&(g_parse_prm[i]), 0x00, sizeof(g_parse_prm[i])); 82 | g_parse_prm[i].lex_prm = lex_prm; 83 | g_parse_prm[i].gen_prm = gen_prm; 84 | g_parse_prm[i].is_interpret = is_interpret; 85 | g_parse_prm[i].cur_token.tok = -1; 86 | g_parse_prm[i].var_level = 0; 87 | g_parse_prm[i].var_map_pos = 0; 88 | 89 | ast_map_init(&(g_parse_prm[i])); 90 | symtable_init(&(g_parse_prm[i].symbol_table)); 91 | 92 | *parse_prm = &g_parse_prm[i]; 93 | 94 | return Success; 95 | } 96 | 97 | int32_t ParseClose(void* prm) 98 | { 99 | if (NULL == prm) { 100 | return InParameterInvalid; 101 | } 102 | 103 | ((ParseParameter*)prm)->avail = true; 104 | 105 | return Success; 106 | } 107 | 108 | int32_t ParseProc(void* prm) 109 | { 110 | if (NULL == prm) { 111 | return InParameterInvalid; 112 | } 113 | 114 | ParseParameter* parse_prm = (ParseParameter*)prm; 115 | 116 | while (!match(parse_prm, TokenEoi)) { 117 | AstNode* node = syntax_parse(parse_prm); 118 | // gen code 119 | ast_gen(parse_prm, node); 120 | } 121 | 122 | return Success; 123 | } 124 | 125 | AstNode* stmt_decl(ParseParameter* parse_prm) 126 | { 127 | // stmt int 128 | AstNode* type = ast_create_leaf(parse_prm->cur_token); 129 | 130 | int pointer_level = 0; 131 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 132 | while (match (parse_prm, TokenStar)) { 133 | // TODO(pointer): Need process specific for pointer 134 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 135 | pointer_level++; 136 | MLOG(TRACE,"Set pointer level %d\n",pointer_level); 137 | } 138 | 139 | if (!match (parse_prm, TokenIdentifier)) { 140 | MLOG(CLGT,"Expect Identifier but token: %s at line: %d\n",tok2str(parse_prm->cur_token.tok), LexGetLine(parse_prm->lex_prm)); 141 | } 142 | 143 | // add the identifier to symbol table 144 | if (Success != symtable_add(&(parse_prm->symbol_table), parse_prm->cur_token.id_str, parse_prm->var_level)) { 145 | MLOG(CLGT, "Duplicated declare variable: %s\n",parse_prm->cur_token.id_str); 146 | exit(1); 147 | } 148 | symtable_set_type(&(parse_prm->symbol_table), parse_prm->cur_token.id_str, parse_prm->var_level, SymbolInt); 149 | symtable_set_pointer_level(&(parse_prm->symbol_table), parse_prm->cur_token.id_str, parse_prm->var_level, pointer_level); 150 | 151 | parse_prm->cur_token.var_id = symtable_get_id(&(parse_prm->symbol_table), parse_prm->cur_token.id_str, parse_prm->var_level); 152 | AstNode* var_name = ast_create_leaf(parse_prm->cur_token); 153 | AstNode* decl = ast_create_declare(type, var_name, AstVarLocal); 154 | 155 | Token var_tok = parse_prm->cur_token; 156 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 157 | 158 | if (match (parse_prm, TokenAssign)) { 159 | // initialize value at declare timming 160 | AstNode* left = ast_create_leaf(var_tok); 161 | left->type = AstLeftVar; 162 | 163 | Token op_tok = parse_prm->cur_token; 164 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 165 | 166 | AstNode* init = expression(parse_prm); 167 | init = ast_create_node(op_tok, left, init); 168 | decl = ast_create_link(decl, init); 169 | } 170 | 171 | if (match (parse_prm, TokenSemi)) { 172 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 173 | } else { 174 | MLOG(CLGT,"Missing semicolon at line: %d\n",LexGetLine(parse_prm->lex_prm)); 175 | } 176 | 177 | return decl; 178 | } 179 | 180 | AstNode* stmt_if(ParseParameter* parse_prm) 181 | { 182 | /* if_statement: if_head 183 | * | if_head 'else' compound_statement 184 | * ; 185 | */ 186 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 187 | if (!match(parse_prm, TokenLP)){ 188 | MLOG(CLGT,"Missing open parentheses ( at line: %d\n",LexGetLine(parse_prm->lex_prm)); 189 | exit(1); 190 | } 191 | 192 | AstNode* cond = expression(parse_prm); 193 | if (NULL == cond) { 194 | MLOG(CLGT,"Error of IF condition at line: %d\n",LexGetLine(parse_prm->lex_prm)); 195 | exit(1); 196 | } 197 | AstNode* true_stmt = NULL; 198 | true_stmt = statements(parse_prm, true_stmt); 199 | 200 | // else 201 | AstNode* false_stmt = NULL; 202 | if (match(parse_prm, TokenElse)){ 203 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 204 | false_stmt = statements(parse_prm, false_stmt); 205 | } 206 | 207 | // create If node 208 | return ast_create_ifnode(cond, true_stmt, false_stmt); 209 | } 210 | 211 | AstNode* stmt_while(ParseParameter* parse_prm) 212 | { 213 | Token tok = parse_prm->cur_token; 214 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 215 | if (!match(parse_prm, TokenLP)){ 216 | MLOG(CLGT,"Missing open parentheses ( at line: %d\n",LexGetLine(parse_prm->lex_prm)); 217 | exit(1); 218 | } 219 | 220 | AstNode* cond = expression(parse_prm); 221 | if (NULL == cond) { 222 | MLOG(CLGT,"Error of WHILE condition at line: %d\n",LexGetLine(parse_prm->lex_prm)); 223 | exit(1); 224 | } 225 | AstNode* stmt = NULL; 226 | stmt = statements(parse_prm, stmt); 227 | 228 | return ast_create_node(tok, cond, stmt); 229 | } 230 | 231 | AstNode* stmt_for(ParseParameter* parse_prm) 232 | { 233 | // handle FOR as scope to manage declare variable at pre condition. 234 | parse_prm->var_level++; 235 | 236 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 237 | if (!match(parse_prm, TokenLP)){ 238 | MLOG(CLGT,"Missing open parentheses ( at line: %d\n",LexGetLine(parse_prm->lex_prm)); 239 | exit(1); 240 | } 241 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 242 | 243 | AstNode* pre_exp = NULL; 244 | pre_exp = statements(parse_prm, pre_exp); 245 | 246 | AstNode* cond_exp = stmt_expr(parse_prm); 247 | if (NULL == cond_exp) { 248 | MLOG(CLGT,"Not support without condition: %d\n",LexGetLine(parse_prm->lex_prm)); 249 | exit(1); 250 | } 251 | 252 | AstNode* post_exp = expression(parse_prm); 253 | 254 | if (!match(parse_prm, TokenRP)){ 255 | MLOG(CLGT,"Missing close parentheses ) at line: %d\n",LexGetLine(parse_prm->lex_prm)); 256 | exit(1); 257 | } 258 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 259 | 260 | AstNode* stmt = NULL; 261 | stmt = statements(parse_prm, stmt); 262 | 263 | stmt = ast_create_link(stmt, post_exp); 264 | 265 | Token w_token; 266 | w_token.tok = TokenWhile; // handle For as While 267 | AstNode* w_stmt = ast_create_node(w_token, cond_exp, stmt); 268 | 269 | // clear all local variable at pre condition 270 | symtable_clear_level(&(parse_prm->symbol_table), parse_prm->var_level); 271 | // decrease variable level at exit FOR 272 | parse_prm->var_level--; 273 | 274 | return ast_create_link(pre_exp, w_stmt); 275 | } 276 | 277 | AstNode* stmt_return(ParseParameter* parse_prm) 278 | { 279 | Token op_tok = parse_prm->cur_token; 280 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 281 | AstNode* node = stmt_expr(parse_prm); 282 | return ast_create_unary(op_tok, node); 283 | } 284 | 285 | AstNode* stmt_scope(ParseParameter* parse_prm) 286 | { 287 | // increase variable level at scope in 288 | parse_prm->var_level++; 289 | 290 | if(!match(parse_prm, TokenLBracket)) { 291 | MLOG(CLGT,"Missing open braces { at line: %d\n",LexGetLine(parse_prm->lex_prm)); 292 | exit(1); 293 | } 294 | 295 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 296 | AstNode* node = NULL; 297 | while (!match(parse_prm, TokenRBracket) && !match(parse_prm, TokenEoi)) { 298 | node = statements(parse_prm, node); 299 | } 300 | 301 | if (match(parse_prm, TokenEoi)) { 302 | MLOG(CLGT,"Missing close braces } at line: %d\n",LexGetLine(parse_prm->lex_prm)); 303 | exit(1); 304 | } 305 | 306 | // clear all local variable at scope 307 | symtable_clear_level(&(parse_prm->symbol_table), parse_prm->var_level); 308 | // decrease variable level at scope out 309 | parse_prm->var_level--; 310 | 311 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 312 | return node; 313 | } 314 | 315 | 316 | AstNode* stmt_expr(ParseParameter* parse_prm) 317 | { 318 | AstNode* node = expression(parse_prm); 319 | if (match(parse_prm, TokenSemi)) { 320 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 321 | } else { 322 | MLOG(CLGT,"Missing semicolon at line: %d\n",LexGetLine(parse_prm->lex_prm)); 323 | } 324 | 325 | return node; 326 | } 327 | 328 | AstNode* func_arg_parse(ParseParameter* parse_prm, int arg_order) 329 | { 330 | // stmt int 331 | AstNode* type = ast_create_leaf(parse_prm->cur_token); 332 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 333 | if (!match (parse_prm, TokenIdentifier)) { 334 | MLOG(CLGT,"Expect Identifier but token: %s at line: %d\n",tok2str(parse_prm->cur_token.tok), LexGetLine(parse_prm->lex_prm)); 335 | } 336 | 337 | // add the identifier to symbol table 338 | if (Success != symtable_add(&(parse_prm->symbol_table), parse_prm->cur_token.id_str, parse_prm->var_level)) { 339 | MLOG(CLGT, "Duplicated declare variable: %s\n",parse_prm->cur_token.id_str); 340 | exit(1); 341 | } 342 | symtable_set_type(&(parse_prm->symbol_table), parse_prm->cur_token.id_str, parse_prm->var_level, SymbolInt); 343 | 344 | parse_prm->cur_token.var_id = symtable_get_id(&(parse_prm->symbol_table), parse_prm->cur_token.id_str, parse_prm->var_level); 345 | AstNode* var_name = ast_create_leaf(parse_prm->cur_token); 346 | AstNode* decl = ast_create_declare(type, var_name, AstVarLocal); 347 | 348 | AstNode* init = ast_create_arg_init(parse_prm->cur_token, arg_order); 349 | decl = ast_create_link(decl, init); 350 | 351 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 352 | return decl; 353 | } 354 | 355 | AstNode* syntax_parse(ParseParameter* parse_prm) 356 | { 357 | // At first data type 358 | if (!match(parse_prm, TokenVoidType) && !match(parse_prm, TokenIntType)) { 359 | MLOG(ERROR, "The version only support void main function : %s\n",parse_prm->cur_token.id_str); 360 | exit(1); 361 | } 362 | AstNode* type = ast_create_leaf(parse_prm->cur_token); 363 | 364 | // Identifier -> function name. 365 | // Identifier -> global variable. 366 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 367 | Token ident_tok = parse_prm->cur_token; 368 | 369 | // open parenthesis 370 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 371 | if (match(parse_prm, TokenLP)) { 372 | // parse as function 373 | parse_prm->var_level++; 374 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 375 | // parse input parameter 376 | AstNode* arg = NULL; 377 | int arg_order = 0; 378 | while (!match(parse_prm, TokenRP)) { 379 | arg = ast_create_link(arg, func_arg_parse(parse_prm, arg_order++)); 380 | if (match(parse_prm, TokenComma)) { 381 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 382 | } else if (match(parse_prm, TokenRP)) { 383 | break; 384 | } else { 385 | MLOG(CLGT,"Missing ) or , at line: %d\n",LexGetLine(parse_prm->lex_prm)); 386 | } 387 | } 388 | 389 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 390 | if (!match(parse_prm, TokenLBracket)) { 391 | MLOG(ERROR, "Expect { at line: %d but token %s\n",LexGetLine(parse_prm->lex_prm), tok2str(parse_prm->cur_token.tok)); 392 | } 393 | 394 | AstNode* ident = ast_create_leaf(ident_tok); 395 | AstNode* body = stmt_scope(parse_prm); 396 | 397 | // clear all local variable in function 398 | symtable_clear_level(&(parse_prm->symbol_table), parse_prm->var_level); 399 | parse_prm->var_level--; 400 | // create function tree. 401 | return ast_create_func(ident, arg, body); 402 | } else { 403 | // add the global variable to symbol table 404 | if (Success != symtable_add(&(parse_prm->symbol_table), ident_tok.id_str, parse_prm->var_level)) { 405 | MLOG(CLGT,"Duplicated declare variable : %s\n",ident_tok.id_str); 406 | exit(1); 407 | } 408 | 409 | symtable_set_type(&(parse_prm->symbol_table), ident_tok.id_str, parse_prm->var_level, SymbolInt); 410 | 411 | // create global variable tree with type 412 | ident_tok.var_id = symtable_get_id(&(parse_prm->symbol_table), ident_tok.id_str, parse_prm->var_level); 413 | AstNode* var_name = ast_create_leaf(ident_tok); 414 | AstNode* global_var = ast_create_declare(type, var_name, AstVarGlobal); 415 | 416 | if (match (parse_prm, TokenSemi)) { 417 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 418 | } else { 419 | MLOG(CLGT,"Missing semicolon at line: %d\n",LexGetLine(parse_prm->lex_prm)); 420 | } 421 | return global_var; 422 | } 423 | } 424 | 425 | AstNode* statements(ParseParameter* parse_prm, AstNode* root) 426 | { 427 | /* statements -> expression SEMI 428 | * -> expression SEMI statements 429 | * -> 'int' identifier SEMI statements 430 | * -> identifier '=' expression SEMI statements 431 | * -> if_statement 432 | */ 433 | AstNode* node = NULL; 434 | switch(parse_prm->cur_token.tok) 435 | { 436 | case TokenIntType: 437 | node = stmt_decl(parse_prm); 438 | break; 439 | case TokenIf: 440 | node = stmt_if(parse_prm); 441 | break; 442 | case TokenWhile: 443 | node = stmt_while(parse_prm); 444 | break; 445 | case TokenFor: 446 | node = stmt_for(parse_prm); 447 | break; 448 | case TokenLBracket: 449 | node = stmt_scope(parse_prm); 450 | break; 451 | case TokenRBracket: 452 | MLOG(CLGT,"Redundancy open braces { at line: %d\n",LexGetLine(parse_prm->lex_prm)); 453 | // Ignore to next 454 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 455 | break; 456 | case TokenReturn: 457 | node = stmt_return(parse_prm); 458 | break; 459 | case TokenSemi: 460 | MLOG(TRACE,"Just ; -> nothing to do :-) \n"); 461 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 462 | break; 463 | default: 464 | node = stmt_expr(parse_prm); 465 | } 466 | 467 | if (NULL == root) { 468 | return ast_create_link(node, NULL); 469 | } else { 470 | return ast_create_link(root, node); 471 | } 472 | } 473 | 474 | AstNode* expression(ParseParameter* parse_prm) 475 | { 476 | return assign(parse_prm); 477 | } 478 | 479 | AstNode* assign(ParseParameter* parse_prm) { 480 | AstNode* node = logic_or(parse_prm); 481 | while (match(parse_prm, TokenAssign)) { 482 | Token op_tok = parse_prm->cur_token; 483 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 484 | AstNode* node1 = logic_or(parse_prm); 485 | 486 | if (AstIdentifier == node->type) { 487 | node->type = AstLeftVar; // todo: consider better design for Lval & Rval 488 | } else { 489 | MLOG(CLGT,"left operand is not Lvalue at line %d\n", LexGetLine(parse_prm->lex_prm)); 490 | exit(1); 491 | } 492 | node = ast_create_node(op_tok, node, node1); 493 | } 494 | return node; 495 | } 496 | 497 | AstNode* logic_or(ParseParameter* parse_prm) { 498 | AstNode* node = logic_and(parse_prm); 499 | while (match(parse_prm, TokenOr)) { 500 | Token op_tok = parse_prm->cur_token; 501 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 502 | AstNode* node1 = logic_and(parse_prm); 503 | node = ast_create_node(op_tok, node, node1); 504 | } 505 | return node; 506 | } 507 | 508 | AstNode* logic_and(ParseParameter* parse_prm) { 509 | AstNode* node = bit_or(parse_prm); 510 | while (match(parse_prm, TokenAnd)) { 511 | Token op_tok = parse_prm->cur_token; 512 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 513 | AstNode* node1 = bit_or(parse_prm); 514 | node = ast_create_node(op_tok, node, node1); 515 | } 516 | return node; 517 | } 518 | 519 | AstNode* bit_or(ParseParameter* parse_prm) { 520 | AstNode* node = bit_xor(parse_prm); 521 | while (match(parse_prm, TokenBitOr)) { 522 | Token op_tok = parse_prm->cur_token; 523 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 524 | AstNode* node1 = bit_xor(parse_prm); 525 | node = ast_create_node(op_tok, node, node1); 526 | } 527 | return node; 528 | } 529 | 530 | AstNode* bit_xor(ParseParameter* parse_prm) { 531 | AstNode* node = bit_and(parse_prm); 532 | while (match(parse_prm, TokenBitXor)) { 533 | Token op_tok = parse_prm->cur_token; 534 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 535 | AstNode* node1 = bit_and(parse_prm); 536 | node = ast_create_node(op_tok, node, node1); 537 | } 538 | return node; 539 | } 540 | 541 | AstNode* bit_and(ParseParameter* parse_prm) { 542 | AstNode* node = equal(parse_prm); 543 | while (match(parse_prm, TokenBitAnd)) { 544 | Token op_tok = parse_prm->cur_token; 545 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 546 | AstNode* node1 = equal(parse_prm); 547 | node = ast_create_node(op_tok, node, node1); 548 | } 549 | return node; 550 | } 551 | 552 | AstNode* equal(ParseParameter* parse_prm) { 553 | AstNode* node = relational(parse_prm); 554 | while (match(parse_prm, TokenEQ) || 555 | match(parse_prm, TokenNE)) { 556 | Token op_tok = parse_prm->cur_token; 557 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 558 | AstNode* node1 = relational(parse_prm); 559 | node = ast_create_node(op_tok, node, node1); 560 | } 561 | return node; 562 | } 563 | 564 | AstNode* relational(ParseParameter* parse_prm) { 565 | AstNode* node = add(parse_prm); 566 | while (match(parse_prm, TokenLT) || 567 | match(parse_prm, TokenLE) || 568 | match(parse_prm, TokenGT) || 569 | match(parse_prm, TokenGE)) { 570 | Token op_tok = parse_prm->cur_token; 571 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 572 | AstNode* node1 = add(parse_prm); 573 | node = ast_create_node(op_tok, node, node1); 574 | } 575 | return node; 576 | } 577 | 578 | AstNode* add(ParseParameter* parse_prm) 579 | { 580 | AstNode* node = mul(parse_prm); 581 | while (match(parse_prm, TokenPlus) || match(parse_prm, TokenMinus)) { 582 | Token op_tok = parse_prm->cur_token; 583 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 584 | AstNode* node1 = mul(parse_prm); 585 | node = ast_create_node(op_tok, node, node1); 586 | } 587 | return node; 588 | } 589 | 590 | AstNode* mul(ParseParameter* parse_prm) 591 | { 592 | AstNode *node, *node1; 593 | node = factor(parse_prm); 594 | while (match(parse_prm, TokenMul) || match(parse_prm, TokenDiv)) { 595 | Token op_tok = parse_prm->cur_token; 596 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 597 | node1 = factor(parse_prm); 598 | node = ast_create_node(op_tok, node, node1); 599 | } 600 | return node; 601 | } 602 | 603 | AstNode* factor(ParseParameter* parse_prm) 604 | { 605 | AstNode* node = NULL; 606 | if (match(parse_prm, TokenNumber)) { 607 | node = ast_create_leaf(parse_prm->cur_token); 608 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 609 | } else if (match(parse_prm, TokenDereference) || match(parse_prm, TokenStar)) { 610 | // TODO(pointer): Need consider how to manage address variable 611 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 612 | while (match(parse_prm, TokenDereference)) { 613 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 614 | } 615 | // TODO(pointer): Need consider how to manage dereference pointer 616 | while (match(parse_prm, TokenStar)) { 617 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 618 | } 619 | 620 | if (!match(parse_prm, TokenIdentifier)) { 621 | MLOG(ERROR, "Number or identifier expected but token: %s at line %d\n", tok2str(parse_prm->cur_token.tok), LexGetLine(parse_prm->lex_prm)); 622 | } 623 | Token op_tok = parse_prm->cur_token; 624 | if (-1 == symtable_find_valid(&(parse_prm->symbol_table), op_tok.id_str, parse_prm->var_level)) { 625 | MLOG(CLGT, "Can not find symbol %s at line: %d\n",op_tok.id_str, LexGetLine(parse_prm->lex_prm)); 626 | exit(1); 627 | } 628 | op_tok.var_id = symtable_get_id(&(parse_prm->symbol_table), op_tok.id_str, parse_prm->var_level); 629 | node = ast_create_leaf(op_tok); 630 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 631 | } else if (match(parse_prm, TokenIdentifier)) { 632 | Token op_tok = parse_prm->cur_token; 633 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 634 | if (match(parse_prm, TokenLP)) { 635 | // todo: need check the function is declared or not. 636 | node = function_call(parse_prm, op_tok); 637 | } else { 638 | if (-1 == symtable_find_valid(&(parse_prm->symbol_table), op_tok.id_str, parse_prm->var_level)) { 639 | MLOG(CLGT, "Can not find symbol %s at line: %d\n",op_tok.id_str, LexGetLine(parse_prm->lex_prm)); 640 | exit(1); 641 | } 642 | op_tok.var_id = symtable_get_id(&(parse_prm->symbol_table), op_tok.id_str, parse_prm->var_level); 643 | node = ast_create_leaf(op_tok); 644 | } 645 | 646 | } else if (match(parse_prm, TokenLP)) { 647 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 648 | node = expression(parse_prm); 649 | if (match(parse_prm, TokenRP)) { 650 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 651 | } else { 652 | MLOG(CLGT,"Missing ( at line: %d\n",LexGetLine(parse_prm->lex_prm)); 653 | exit(1); 654 | } 655 | } else { 656 | MLOG(CLGT, "Number or identifier expected but token: %s at line %d\n", tok2str(parse_prm->cur_token.tok), LexGetLine(parse_prm->lex_prm)); 657 | exit(1); 658 | } 659 | 660 | return node; 661 | } 662 | 663 | AstNode* function_call(ParseParameter* parse_prm, Token tok) 664 | { 665 | // create function call node. 666 | AstNode* node = ast_create_func_call(); 667 | node->right = ast_create_leaf(tok); // function name 668 | 669 | AstNode *arg = NULL, *arg_seq = NULL; 670 | int arg_order = 0; 671 | 672 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 673 | while (!match(parse_prm, TokenRP)) { 674 | if (match (parse_prm, TokenString)) { 675 | arg = ast_create_leaf(parse_prm->cur_token); 676 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 677 | } else { 678 | arg = expression(parse_prm); 679 | } 680 | 681 | arg_seq = ast_create_link(arg_seq, ast_create_arg_pass(arg, arg_order++)); 682 | 683 | if (match(parse_prm, TokenComma)) { 684 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 685 | } else if (match(parse_prm, TokenRP)) { 686 | break; 687 | } else { 688 | MLOG(CLGT,"Missing ( or , at line: %d\n",LexGetLine(parse_prm->lex_prm)); 689 | exit(1); 690 | } 691 | } 692 | node->left = arg_seq; 693 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 694 | return node; 695 | } 696 | 697 | bool match(ParseParameter* parse_prm, int32_t tok_type) 698 | { 699 | if (-1 == parse_prm->cur_token.tok) { 700 | LexProc(parse_prm->lex_prm, &(parse_prm->cur_token)); 701 | } 702 | return (parse_prm->cur_token.tok == tok_type); 703 | } 704 | -------------------------------------------------------------------------------- /src/parse_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include "symtable.h" 9 | 10 | #ifndef _PARSE_INTERNAL_H_ 11 | #define _PARSE_INTERNAL_H_ 12 | 13 | typedef struct StringMap { 14 | char id[MAX_IDENT_LEN]; 15 | char* label; 16 | } StringMap; 17 | 18 | typedef struct ParseParameter{ 19 | bool avail; 20 | bool is_interpret; 21 | void *lex_prm; 22 | void *gen_prm; 23 | SymbolTable symbol_table; 24 | Token cur_token; 25 | int var_level; 26 | 27 | StringMap var_map[MAX_IDENT_CNT]; 28 | int var_map_pos; 29 | } ParseParameter; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/symtable.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/08 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | /* 7 | * Symtable for quick simple version. poor performance. 8 | * It will be replace by hashtable version later. 9 | */ 10 | #include "log.h" 11 | #include "symtable.h" 12 | #include 13 | #include 14 | 15 | int32_t symtable_init(SymbolTable* st) 16 | { 17 | memset((void*)st, 0x00, sizeof(SymbolTable)); 18 | st->cur_pos = -1; 19 | st->cur_id = 0; 20 | return Success; 21 | } 22 | 23 | int32_t symtable_add(SymbolTable* st, char* symbol, int level) 24 | { 25 | if (st->cur_pos >= NSYMBOLS-1) { 26 | return SymbolTableOver; 27 | } 28 | 29 | if (-1 != symtable_find(st, symbol, level)) { 30 | return VariableDeclared; 31 | } 32 | 33 | MLOG(TRACE,"Add to symbol table %s level %d\n", symbol, level); 34 | st->cur_pos++; 35 | int size_sym = strlen(symbol); 36 | memcpy(st->data[st->cur_pos].name , symbol, size_sym); 37 | st->data[st->cur_pos].level = level; 38 | st->data[st->cur_pos].name[size_sym] = '\0'; 39 | st->data[st->cur_pos].id = st->cur_id++; 40 | return Success; 41 | } 42 | 43 | int32_t symtable_remove(SymbolTable* st, char* symbol) 44 | { 45 | // todo 46 | return Success; 47 | } 48 | 49 | int32_t symtable_find(SymbolTable* st, char* symbol, int level) 50 | { 51 | if (NULL == symbol) { 52 | return -1; 53 | } 54 | 55 | for (int i = 0; i <= st->cur_pos; i++) { 56 | if (*(st->data[i].name) == *symbol && 57 | strlen(st->data[i].name) == strlen(symbol) && 58 | !strncmp(st->data[i].name, symbol, strlen(symbol)) && 59 | st->data[i].level == level) { 60 | return i; 61 | } 62 | } 63 | 64 | return -1; 65 | } 66 | 67 | int32_t symtable_find_valid(SymbolTable* st, char* symbol, int level) 68 | { 69 | for (int i = level; i >= 0; i--) { 70 | if (-1 != symtable_find(st, symbol, i)) { 71 | return i; 72 | } 73 | } 74 | return -1; 75 | } 76 | 77 | int32_t symtable_get_value(SymbolTable* st, char* symbol, int level) 78 | { 79 | int32_t idx = symtable_find(st, symbol, level); 80 | if (-1 == idx) { 81 | MLOG(CLGT,"Not found the symbol %s\n", symbol); 82 | return -1; 83 | } 84 | 85 | if (SymbolInt == st->data[idx].type) { 86 | return st->data[idx].int_value; 87 | } else { 88 | MLOG(CLGT,"Currently, only support Int type\n"); 89 | } 90 | return -1; 91 | } 92 | 93 | int32_t symtable_get_id(SymbolTable* st, char* symbol, int level) 94 | { 95 | 96 | int idx = -1; 97 | for (int i = level; i >= 0; i--) { 98 | idx = symtable_find(st, symbol, i); 99 | if (-1 != idx) { 100 | break; 101 | } 102 | } 103 | if (-1 == idx) { 104 | MLOG(CLGT,"Not found the symbol %s\n", symbol); 105 | return -1; 106 | } 107 | 108 | return st->data[idx].id; 109 | } 110 | 111 | int32_t symtable_set_type(SymbolTable* st, char* symbol, int level, int32_t type) 112 | { 113 | int32_t idx = symtable_find(st, symbol, level); 114 | if (-1 == idx) { 115 | MLOG(CLGT,"Not found the symbol %s\n", symbol); 116 | return -1; 117 | } 118 | st->data[idx].type = type; 119 | return 0; 120 | } 121 | 122 | int32_t symtable_clear_level(SymbolTable* st, int32_t level) 123 | { 124 | int cnt = 0; 125 | for (int i = 0; i <= st->cur_pos; i++) { 126 | if (st->data[i].level == level) { 127 | cnt++; 128 | st->data[i].level = -1; 129 | memset(st->data[i].name, 0x00, sizeof(st->data[i].name)); 130 | } 131 | } 132 | 133 | if (0 == cnt) { 134 | MLOG(TRACE,"Not found any variable level %d to clear\n", level); 135 | } 136 | 137 | return cnt; 138 | } 139 | 140 | int32_t symtable_set_label(SymbolTable* st, char* symbol, int level, char* label) 141 | { 142 | 143 | int32_t idx = symtable_find_valid(st, symbol, level); 144 | if (-1 == idx) { 145 | MLOG(CLGT,"Not found the symbol %s\n", symbol); 146 | return -1; 147 | } 148 | st->data[idx].label = label; 149 | return 0; 150 | } 151 | 152 | char* symtable_get_label(SymbolTable* st, char* symbol, int level) 153 | { 154 | int32_t idx = symtable_find_valid(st, symbol, level); 155 | if (-1 == idx) { 156 | MLOG(CLGT,"Not found the symbol %s\n", symbol); 157 | return NULL; 158 | } 159 | return st->data[idx].label; 160 | } 161 | 162 | int32_t symtable_set_value(SymbolTable* st, char* symbol, int level, int32_t value) 163 | { 164 | int32_t idx = symtable_find(st, symbol, level); 165 | if (-1 == idx) { 166 | MLOG(CLGT,"Not found the symbol %s\n", symbol); 167 | return -1; 168 | } 169 | 170 | if (SymbolInt == st->data[idx].type) { 171 | st->data[idx].int_value = value; 172 | } else { 173 | MLOG(CLGT,"Currently, only support Int type\n"); 174 | } 175 | return 0; 176 | } 177 | 178 | int32_t symtable_set_pointer_level(SymbolTable* st, char* symbol, int level, int32_t pointer_level) 179 | { 180 | int32_t idx = symtable_find(st, symbol, level); 181 | if (-1 == idx) { 182 | MLOG(CLGT,"Not found the symbol %s\n", symbol); 183 | return -1; 184 | } 185 | st->data[idx].pointer_level = pointer_level; 186 | return 0; 187 | } 188 | -------------------------------------------------------------------------------- /src/x86_64_asm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | /* 7 | * The document should be read 8 | * - https://aaronbloomfield.github.io/pdr/book/x86-64bit-ccc-chapter.pdf 9 | */ 10 | 11 | #include 12 | #include "log.h" 13 | #include "gen.h" 14 | #include "gen_internal.h" 15 | #include "error_code.h" 16 | 17 | static bool is_op_reg(char* arg); 18 | static char* x86_64_load(int32_t value, FILE* out_file); 19 | static char* x86_64_free(char* r, FILE* out_file); 20 | static char* x86_64_out(char* value, FILE* out_file); 21 | static char* x86_64_var(char* var, FILE* out_file); 22 | static char* x86_64_local_var(char* var, int size, FILE* out_file); 23 | static char* x86_64_add(char* r1, char* r2, FILE* out_file); 24 | static char* x86_64_sub(char* r1, char* r2, FILE* out_file); 25 | static char* x86_64_mul(char* r1, char* r2, FILE* out_file); 26 | static char* x86_64_div(char* r1, char* r2, FILE* out_file); 27 | static char* x86_64_lt(char* r1, char* r2, FILE* out_file); 28 | static char* x86_64_le(char* r1, char* r2, FILE* out_file); 29 | static char* x86_64_gt(char* r1, char* r2, FILE* out_file); 30 | static char* x86_64_ge(char* r1, char* r2, FILE* out_file); 31 | static char* x86_64_eq(char* r1, char* r2, FILE* out_file); 32 | static char* x86_64_ne(char* r1, char* r2, FILE* out_file); 33 | 34 | static char* x86_64_or(char* r1, char* r2, FILE* out_file); 35 | static char* x86_64_and(char* r1, char* r2, FILE* out_file); 36 | static char* x86_64_b_or(char* r1, char* r2, FILE* out_file); 37 | static char* x86_64_b_xor(char* r1, char* r2, FILE* out_file); 38 | static char* x86_64_b_and(char* r1, char* r2, FILE* out_file); 39 | 40 | static char* x86_64_lt_j(char* r1, char* r2, char* label, FILE* out_file); 41 | static char* x86_64_le_j(char* r1, char* r2, char* label, FILE* out_file); 42 | static char* x86_64_gt_j(char* r1, char* r2, char* label, FILE* out_file); 43 | static char* x86_64_ge_j(char* r1, char* r2, char* label, FILE* out_file); 44 | static char* x86_64_eq_j(char* r1, char* r2, char* label, FILE* out_file); 45 | static char* x86_64_ne_j(char* r1, char* r2, char* label, FILE* out_file); 46 | static char* x86_64_jump(char* label, FILE* out_file); 47 | static char* x86_64_zero_j(char* r, char* label, FILE* out_file); 48 | static char* x86_64_label(char* label, FILE* out_file); 49 | static char* x86_64_str_label(char* label, char* str, FILE* out_file); 50 | static char* x86_64_func(char* name, int stack_size, FILE* out_file); 51 | static char* x86_64_func_arg(int arg_order, FILE* out_file); 52 | static char* x86_64_func_exit(char* exit_label, int stack_size, FILE* out_file); 53 | 54 | static char* x86_64_func_call(char* name, FILE* out_file); 55 | static char* x86_64_arg(char* arg, int idx, FILE* out_file); 56 | 57 | static char* x86_64_store(char* r, char* var, FILE* out_file); 58 | static char* x86_64_load_var(char* var, FILE* out_file); 59 | static char* x86_64_return(char* r, char* exit_label, FILE* out_file); 60 | static char* x86_64_reg_backup(FILE* out_file); 61 | static char* x86_64_reg_restore(FILE* out_file); 62 | 63 | typedef struct RegMap { 64 | char* reg64; 65 | char* reg8; 66 | } RegMap; 67 | 68 | //TODO: move all global to gen structure. 69 | static char* const op_reg[] = { 70 | "%r10", 71 | "%r11", 72 | "%r12", 73 | "%r13", 74 | "%r14", 75 | "%r15"}; 76 | 77 | static char* reg[] = { 78 | "%r10", 79 | "%r11", 80 | "%r12", 81 | "%r13", 82 | "%r14", 83 | "%r15"}; 84 | 85 | static RegMap reg_map[] = { 86 | {"%r10", "%r10b"}, 87 | {"%r11", "%r11b"}, 88 | {"%r12", "%r12b"}, 89 | {"%r13", "%r13b"}, 90 | {"%r14", "%r14b"}, 91 | {"%r15", "%r15b"} 92 | }; 93 | 94 | static char* arg_reg[] = { 95 | "%rdi", 96 | "%rsi", 97 | "%rdx", 98 | "%rcx", 99 | "%r8", 100 | "%r9"}; 101 | 102 | 103 | static int cur_reg = 0; 104 | static int var_on_stack = 0; 105 | static int allocated_stack = 0; 106 | 107 | int32_t GenLoadX86_64(GenFuncTable *func) 108 | { 109 | func->f_load = &x86_64_load; 110 | func->f_free = &x86_64_free; 111 | func->f_out = &x86_64_out; 112 | func->f_var = &x86_64_var; 113 | func->f_l_var = &x86_64_local_var; 114 | func->f_add = &x86_64_add; 115 | func->f_sub = &x86_64_sub; 116 | func->f_mul = &x86_64_mul; 117 | func->f_div = &x86_64_div; 118 | func->f_lt = &x86_64_lt; 119 | func->f_le = &x86_64_le; 120 | func->f_gt = &x86_64_gt; 121 | func->f_ge = &x86_64_ge; 122 | func->f_eq = &x86_64_eq; 123 | func->f_ne = &x86_64_ne; 124 | 125 | func->f_or = &x86_64_or; 126 | func->f_and = &x86_64_and; 127 | func->f_b_or = &x86_64_b_or; 128 | func->f_b_xor = &x86_64_b_xor; 129 | func->f_b_and = &x86_64_b_and; 130 | 131 | func->f_lt_j = &x86_64_lt_j; 132 | func->f_le_j = &x86_64_le_j; 133 | func->f_gt_j = &x86_64_gt_j; 134 | func->f_ge_j = &x86_64_ge_j; 135 | func->f_eq_j = &x86_64_eq_j; 136 | func->f_ne_j = &x86_64_ne_j; 137 | func->f_jump = &x86_64_jump; 138 | func->f_zero_j = &x86_64_zero_j; 139 | 140 | func->f_label = &x86_64_label; 141 | func->f_str_label = &x86_64_str_label; 142 | func->f_func = &x86_64_func; 143 | func->f_func_arg = &x86_64_func_arg; 144 | func->f_func_exit = &x86_64_func_exit; 145 | func->f_func_call = &x86_64_func_call; 146 | func->f_arg = &x86_64_arg; 147 | func->f_store = &x86_64_store; 148 | func->f_load_var = &x86_64_load_var; 149 | func->f_return = &x86_64_return; 150 | func->f_reg_backup = &x86_64_reg_backup; 151 | func->f_reg_restore= &x86_64_reg_restore; 152 | 153 | cur_reg = 0; 154 | var_on_stack = 0; 155 | 156 | return Success; 157 | } 158 | 159 | static bool is_op_reg(char* arg) 160 | { 161 | for (int i = 0; i < sizeof(op_reg)/sizeof(*op_reg); i++) { 162 | if (!strncmp(arg, op_reg[i], sizeof(*op_reg))) { 163 | return true; 164 | } 165 | } 166 | return false; 167 | } 168 | 169 | char* reg_alloc() 170 | { 171 | if (cur_reg >= sizeof(reg)/sizeof(*reg)) { 172 | MLOG(CLGT,"Not availabel register\n"); 173 | return NULL; 174 | } 175 | 176 | MLOG(TRACE,"Alloc ============================\n"); 177 | for (int i = 0; i < sizeof(reg)/sizeof(*reg); i++) { 178 | MLOG(TRACE,"Alloc: %d = %s\n",i,reg[i]); 179 | } 180 | MLOG(TRACE,"Alloc ============================\n"); 181 | return reg[cur_reg++]; 182 | } 183 | 184 | void reg_free(char* r) 185 | { 186 | if (!is_op_reg(r)) { 187 | MLOG(TRACE,"Oops the register is not op register: %s\n",r); 188 | return; 189 | } 190 | 191 | if (0 == cur_reg) { 192 | MLOG(CLGT,"Free register invalid: r = %s\n",r); 193 | return; 194 | } 195 | 196 | for (int i = cur_reg; i < sizeof(reg)/sizeof(*reg); i++) { 197 | if (!strncmp(r, reg[i], sizeof(*reg))) { 198 | MLOG(CLGT,"Oops the register is freed\n"); 199 | return; 200 | } 201 | } 202 | 203 | reg[--cur_reg] = r; 204 | MLOG(TRACE,"Free ============================\n"); 205 | for (int i = 0; i < sizeof(reg)/sizeof(*reg); i++) { 206 | MLOG(TRACE,"Free: %d = %s\n",i,reg[i]); 207 | } 208 | MLOG(TRACE,"Free ============================\n"); 209 | } 210 | 211 | char* reg64_to_8(char* r) 212 | { 213 | for (int i = 0; i < sizeof(reg_map)/sizeof(reg_map[0]); i++) { 214 | if (!strncmp(reg_map[i].reg64 , r, strlen(r))) { 215 | return reg_map[i].reg8; 216 | } 217 | } 218 | return NULL; 219 | } 220 | 221 | char* x86_64_load(int32_t value, FILE* out_file) 222 | { 223 | char* r = reg_alloc(); 224 | fprintf(out_file,"\tmovq\t $%d, %s\n",value,r); 225 | return r; 226 | } 227 | 228 | char* x86_64_free(char* r, FILE* out_file) 229 | { 230 | reg_free(r); 231 | return NULL; 232 | } 233 | 234 | char* x86_64_out(char* r, FILE* out_file) 235 | { 236 | fprintf(out_file,"\tmovq\t %s, %s\n",r,"%rax"); 237 | fprintf(out_file,"\tret\n"); 238 | reg_free(r); 239 | return NULL; 240 | } 241 | 242 | char* x86_64_var(char* var, FILE* out_file) 243 | { 244 | fprintf(out_file,"\t.comm\t %s,8,8\n",var); 245 | 246 | int s = sizeof(var) + sizeof("(%rip)"); 247 | char* label = malloc(s*sizeof(char)+1); 248 | sprintf(label,"%s(%%rip)",var); 249 | 250 | return label; 251 | } 252 | 253 | char* x86_64_local_var(char* var, int size, FILE* out_file) 254 | { 255 | (void) out_file; 256 | (void) var; 257 | var_on_stack = var_on_stack - size; 258 | if (allocated_stack < -var_on_stack) { 259 | MLOG(CLGT,"Stack is not enought\n"); 260 | exit(1); 261 | } 262 | int s = sizeof("-1000") + sizeof("(%rbp)"); 263 | char* label = malloc(s*sizeof(char)+1); 264 | sprintf(label,"%d(%%rbp)",var_on_stack); 265 | 266 | return label; 267 | } 268 | 269 | char* x86_64_add(char* r1, char* r2, FILE* out_file) 270 | { 271 | fprintf(out_file,"\taddq\t %s, %s\n",r1,r2); 272 | reg_free(r1); 273 | return r2; 274 | } 275 | 276 | char* x86_64_sub(char* r1, char* r2, FILE* out_file) 277 | { 278 | fprintf(out_file,"\tsubq\t %s, %s\n",r2,r1); 279 | reg_free(r2); 280 | return r1; 281 | } 282 | 283 | char* x86_64_mul(char* r1, char* r2, FILE* out_file) 284 | { 285 | fprintf(out_file,"\timulq\t %s, %s\n",r1,r2); 286 | reg_free(r1); 287 | return r2; 288 | } 289 | 290 | char* x86_64_div(char* r1, char* r2, FILE* out_file) 291 | { 292 | fprintf(out_file,"\tmovq\t %s, %s\n",r1,"%rax"); 293 | fprintf(out_file, "\tcqo\n"); 294 | fprintf(out_file,"\tidivq\t %s\n",r2); 295 | fprintf(out_file,"\tmovq\t %s, %s\n","%rax",r2); 296 | reg_free(r1); 297 | return r2; 298 | } 299 | 300 | char* x86_64_lt(char* r1, char* r2, FILE* out_file) 301 | { 302 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 303 | fprintf(out_file, "\tsetl\t %s\n", reg64_to_8(r2)); 304 | fprintf(out_file, "\tandq\t $255,%s\n", r2); 305 | reg_free(r1); 306 | return r2; 307 | } 308 | 309 | char* x86_64_le(char* r1, char* r2, FILE* out_file) 310 | { 311 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 312 | fprintf(out_file, "\tsetle\t %s\n", reg64_to_8(r2)); 313 | fprintf(out_file, "\tandq\t $255,%s\n", r2); 314 | reg_free(r1); 315 | return r2; 316 | } 317 | 318 | char* x86_64_gt(char* r1, char* r2, FILE* out_file) 319 | { 320 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 321 | fprintf(out_file, "\tsetg\t %s\n", reg64_to_8(r2)); 322 | fprintf(out_file, "\tandq\t $255,%s\n", r2); 323 | reg_free(r1); 324 | return r2; 325 | } 326 | 327 | char* x86_64_ge(char* r1, char* r2, FILE* out_file) 328 | { 329 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 330 | fprintf(out_file, "\tsetge\t %s\n", reg64_to_8(r2)); 331 | fprintf(out_file, "\tandq\t $255,%s\n", r2); 332 | reg_free(r1); 333 | return r2; 334 | } 335 | 336 | char* x86_64_eq(char* r1, char* r2, FILE* out_file) 337 | { 338 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 339 | fprintf(out_file, "\tsete\t %s\n", reg64_to_8(r2)); 340 | fprintf(out_file, "\tandq\t $255,%s\n", r2); 341 | reg_free(r1); 342 | return r2; 343 | } 344 | 345 | char* x86_64_ne(char* r1, char* r2, FILE* out_file) 346 | { 347 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 348 | fprintf(out_file, "\tsetne\t %s\n", reg64_to_8(r2)); 349 | fprintf(out_file, "\tandq\t $255,%s\n", r2); 350 | reg_free(r1); 351 | return r2; 352 | } 353 | 354 | static char* x86_64_or(char* r1, char* r2, FILE* out_file) 355 | { 356 | // todo: how to execute? need investigate 357 | // tentative workarround throuth bitwise op 358 | char* r = reg_alloc(); 359 | fprintf(out_file,"\tmovq\t $0, %s\n",r); 360 | 361 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r); 362 | fprintf(out_file, "\tsetne\t %s\n", reg64_to_8(r2)); 363 | fprintf(out_file, "\tandq\t $255,%s\n", r2); 364 | 365 | fprintf(out_file, "\tcmpq\t %s, %s\n", r1, r); 366 | fprintf(out_file, "\tsetne\t %s\n", reg64_to_8(r1)); 367 | fprintf(out_file, "\tandq\t $255,%s\n", r1); 368 | 369 | fprintf(out_file,"\tor\t %s, %s\n",r1,r2); 370 | reg_free(r1); 371 | reg_free(r); 372 | return r2; 373 | } 374 | 375 | static char* x86_64_and(char* r1, char* r2, FILE* out_file) 376 | { 377 | // todo: how to execute? need investigate 378 | // tentative workarround throuth bitwise op 379 | 380 | char* r = reg_alloc(); 381 | fprintf(out_file,"\tmovq\t $0, %s\n",r); 382 | 383 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r); 384 | fprintf(out_file, "\tsetne\t %s\n", reg64_to_8(r2)); 385 | fprintf(out_file, "\tandq\t $255,%s\n", r2); 386 | 387 | fprintf(out_file, "\tcmpq\t %s, %s\n", r1, r); 388 | fprintf(out_file, "\tsetne\t %s\n", reg64_to_8(r1)); 389 | fprintf(out_file, "\tandq\t $255,%s\n", r1); 390 | 391 | fprintf(out_file,"\tand\t %s, %s\n",r1,r2); 392 | reg_free(r1); 393 | return r2; 394 | } 395 | 396 | static char* x86_64_b_or(char* r1, char* r2, FILE* out_file) 397 | { 398 | fprintf(out_file,"\tor\t %s, %s\n",r1,r2); 399 | reg_free(r1); 400 | return r2; 401 | } 402 | 403 | static char* x86_64_b_xor(char* r1, char* r2, FILE* out_file) 404 | { 405 | fprintf(out_file,"\txor\t %s, %s\n",r1,r2); 406 | reg_free(r1); 407 | return r2; 408 | } 409 | 410 | static char* x86_64_b_and(char* r1, char* r2, FILE* out_file) 411 | { 412 | fprintf(out_file,"\tand\t %s, %s\n",r1,r2); 413 | reg_free(r1); 414 | return r2; 415 | } 416 | 417 | char* x86_64_lt_j(char* r1, char* r2, char* label, FILE* out_file) 418 | { 419 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 420 | fprintf(out_file, "\tjl\t %s\n", label); 421 | reg_free(r1); 422 | reg_free(r2); 423 | return label; 424 | } 425 | 426 | char* x86_64_le_j(char* r1, char* r2, char* label, FILE* out_file) 427 | { 428 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 429 | fprintf(out_file, "\tjle\t %s\n", label); 430 | reg_free(r1); 431 | reg_free(r2); 432 | return label; 433 | } 434 | 435 | char* x86_64_gt_j(char* r1, char* r2, char* label, FILE* out_file) 436 | { 437 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 438 | fprintf(out_file, "\tjg\t %s\n", label); 439 | reg_free(r1); 440 | reg_free(r2); 441 | return label; 442 | } 443 | 444 | char* x86_64_ge_j(char* r1, char* r2, char* label, FILE* out_file) 445 | { 446 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 447 | fprintf(out_file, "\tjge\t %s\n", label); 448 | reg_free(r1); 449 | reg_free(r2); 450 | return label; 451 | } 452 | 453 | char* x86_64_eq_j(char* r1, char* r2, char* label, FILE* out_file) 454 | { 455 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 456 | fprintf(out_file, "\tje\t %s\n", label); 457 | reg_free(r1); 458 | reg_free(r2); 459 | return label; 460 | } 461 | 462 | char* x86_64_ne_j(char* r1, char* r2, char* label, FILE* out_file) 463 | { 464 | fprintf(out_file, "\tcmpq\t %s, %s\n", r2, r1); 465 | fprintf(out_file, "\tjne\t %s\n", label); 466 | reg_free(r1); 467 | reg_free(r2); 468 | return label; 469 | } 470 | 471 | char* x86_64_jump(char* label, FILE* out_file) 472 | { 473 | fprintf(out_file, "\tjmp\t %s\n", label); 474 | return label; 475 | } 476 | 477 | char* x86_64_zero_j(char* r, char* label, FILE* out_file) 478 | { 479 | fprintf(out_file, "\tcmpq\t $0, %s\n", r); 480 | fprintf(out_file, "\tje\t %s\n", label); 481 | reg_free(r); 482 | return label; 483 | } 484 | 485 | char* x86_64_label(char* label, FILE* out_file) 486 | { 487 | fprintf(out_file, "%s:\n", label); 488 | return label; 489 | } 490 | 491 | char* x86_64_str_label(char* label, char* str, FILE* out_file) 492 | { 493 | fprintf(out_file, "%s:\n", label); 494 | fprintf(out_file, "\t.string \"%s\"\n", str); 495 | return label; 496 | } 497 | 498 | char* x86_64_func(char* name, int stack_size, FILE* out_file) 499 | { 500 | fprintf(out_file, "\t.text\n"); 501 | fprintf(out_file, "\t.globl\t %s\n", name); 502 | fprintf(out_file, "\t.type\t %s, @function\n", name); 503 | fprintf(out_file, "%s:\n", name); 504 | // backup register 505 | x86_64_reg_backup(out_file); 506 | fprintf(out_file, "\tpushq\t %%rbp\n"); 507 | fprintf(out_file, "\tmovq\t %%rsp, %%rbp\n"); 508 | fprintf(out_file, "\tsubq\t $%d, %%rsp\n",stack_size); 509 | var_on_stack = 0; 510 | allocated_stack = stack_size; 511 | return name; 512 | } 513 | 514 | char* x86_64_func_arg(int arg_order, FILE* out_file) 515 | { 516 | if (arg_order > 5) { 517 | MLOG(ERROR, "Now, only support until 6 input parameter\n"); 518 | return NULL; 519 | } 520 | return arg_reg[arg_order]; 521 | } 522 | 523 | char* x86_64_func_exit(char* exit_label, int stack_size, FILE* out_file) 524 | { 525 | fprintf(out_file, "\t%s:\n", exit_label); 526 | fprintf(out_file, "\taddq\t $%d, %%rsp\n",stack_size); 527 | fprintf(out_file, "\tpopq\t %%rbp\n"); 528 | // restore register 529 | x86_64_reg_restore(out_file); 530 | fprintf(out_file, "\tret\n"); 531 | return NULL; 532 | } 533 | 534 | char* x86_64_func_call(char* name, FILE* out_file) 535 | { 536 | fprintf(out_file, "\tcall\t %s\n", name); 537 | // return stored result register 538 | char* r = reg_alloc(); 539 | fprintf(out_file, "\tmovq\t %%rax, %s\n", r); 540 | return r; 541 | } 542 | 543 | char* x86_64_arg(char* arg, int idx, FILE* out_file) 544 | { 545 | if (idx > 5) { 546 | MLOG(ERROR, "Now, only support until 6 input parameter\n"); 547 | return NULL; 548 | } 549 | 550 | // release if register 551 | if (is_op_reg(arg)) { 552 | reg_free(arg); 553 | } 554 | 555 | fprintf(out_file, "\tmovq\t %s, %s\n", arg, arg_reg[idx]); 556 | return NULL; 557 | } 558 | 559 | 560 | char* x86_64_store(char* var, char* r, FILE* out_file) 561 | { 562 | fprintf(out_file, "\tmovq\t %s, %s\n", r, var); 563 | 564 | // todo: in func return, r can be %rax register. 565 | // need consider better solution 566 | if (is_op_reg(r)) { 567 | reg_free(r); 568 | } 569 | return var; 570 | } 571 | 572 | char* x86_64_load_var(char* var, FILE* out_file) 573 | { 574 | char* r = reg_alloc(); 575 | fprintf(out_file, "\tmovq\t %s, %s\n", var, r); 576 | return r; 577 | } 578 | 579 | static char* x86_64_return(char* r, char* exit_label, FILE* out_file) 580 | { 581 | fprintf(out_file, "\tmovq\t %s, %%rax\n", r); 582 | fprintf(out_file, "\tjmp\t %s\n", exit_label); 583 | 584 | if (is_op_reg(r)) { 585 | reg_free(r); 586 | } 587 | return NULL; 588 | } 589 | 590 | static char* x86_64_reg_backup(FILE* out_file) 591 | { 592 | // TODO: just tentatve backup all parameter 593 | for (int i = 0; i < sizeof(op_reg)/sizeof(*op_reg); i++) { 594 | fprintf(out_file, "\tpushq\t %s\n", op_reg[i]); 595 | } 596 | 597 | return NULL; 598 | } 599 | 600 | static char* x86_64_reg_restore(FILE* out_file) 601 | { 602 | for (int i = sizeof(op_reg)/sizeof(*op_reg) - 1; i >= 0; i--) { 603 | fprintf(out_file, "\tpopq\t %s\n", op_reg[i]); 604 | } 605 | return NULL; 606 | } 607 | -------------------------------------------------------------------------------- /system_struct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truongpt/meo/55738a68f139749ce7f895a815cfdcd593e04efc/system_struct.png -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | TOPTARGETS := all clean 2 | 3 | SUBDIRS := lex parse gen ast intergration 4 | 5 | $(TOPTARGETS): $(SUBDIRS) 6 | $(SUBDIRS): 7 | $(MAKE) -C $@ $(MAKECMDGOALS) 8 | 9 | .PHONY: $(TOPTARGETS) $(SUBDIRS) 10 | 11 | .PHONY: run 12 | run: 13 | ./lex/lex_test 14 | ./parse/parse_test 15 | ./gen/gen_test 16 | ./ast/ast_test 17 | ./intergration/intergration_test 18 | mem_test: 19 | valgrind ./lex/lex_test 20 | valgrind ./parse/parse_test 21 | valgrind ./gen/gen_test 22 | valgrind ./ast/ast_test 23 | valgrind ./intergration/intergration_test 24 | -------------------------------------------------------------------------------- /test/ast/Makefile: -------------------------------------------------------------------------------- 1 | CPP = g++ -std=c++11 2 | CC = gcc 3 | LD = g++ -std=c++11 4 | LDFLAGS += 5 | CPPFLAGS := -g -O0 -fpermissive -Wnarrowing 6 | 7 | #-fpermissive -Wnarrowing 8 | 9 | TARGET = ast_test 10 | TOP_SRC = ../../ 11 | TOP_TEST = ../../test 12 | 13 | 14 | INC := -I$(TOP_SRC)/inc 15 | INC += -I$(TOP_TEST)/inc 16 | INC += -I$(TOP_SRC)/src 17 | 18 | SRC_CPP := ast_test.cpp 19 | SRC_CPP += main.cpp 20 | SRC_CPP += mock_lex.cpp 21 | SRC := $(TOP_SRC)/src/ast.c 22 | SRC += $(TOP_SRC)/src/symtable.c 23 | SRC += $(TOP_SRC)/src/gen.c 24 | SRC += $(TOP_SRC)/src/parse.c 25 | SRC += $(TOP_SRC)/src/x86_64_asm.c 26 | SRC += $(TOP_SRC)/src/log.c 27 | 28 | CFLAGS += $(INC) 29 | 30 | # generate dependence file 31 | OBJDIR = . 32 | OBJ += $(SRC:%.c=$(OBJDIR)/%.o) 33 | OBJ_CPP += $(SRC_CPP:%.cpp=$(OBJDIR)/%.o) 34 | 35 | # Add target to build library 36 | all:TARGET 37 | 38 | TARGET:$(TARGET) 39 | 40 | $(TARGET):$(OBJ) $(OBJ_CPP) 41 | $(LD) $(LDFLAGS) -o $@ $(OBJ) $(OBJ_CPP) $(LIBS) 42 | 43 | $(OBJDIR)/%.o : %.c 44 | $(CC) $(CFLAGS) -c $< -o $@ 45 | 46 | $(OBJDIR)/%.o : %.cpp 47 | $(CPP) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 48 | 49 | clean: 50 | -rm $(OBJ) $(OBJ_CPP) 51 | -rm $(TARGET) 52 | 53 | .PHONY:clean all TARGET 54 | 55 | -include $(shell mkdir $(OBJDIR) 2>/dev/null) $(wildcard $(OBJDIR)/*.d) 56 | -------------------------------------------------------------------------------- /test/ast/ast_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018/12 truong 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "ast.h" 11 | #include "gen.h" 12 | #include "parse.h" 13 | #include "error_code.h" 14 | 15 | #include "common.h" 16 | #include "catch.hh" 17 | 18 | using namespace std; 19 | 20 | TEST_CASE("ast test") 21 | { 22 | create_folder("data"); 23 | Token T = {TokenNumber, 10}; 24 | AstNode* node = ast_create_leaf(T); 25 | REQUIRE(NULL != node); 26 | REQUIRE(10 == node->value); 27 | } 28 | 29 | TEST_CASE("ast test operator +") 30 | { 31 | 32 | Token T = {TokenNumber, 10}; 33 | AstNode* node = ast_create_leaf(T); 34 | REQUIRE(NULL != node); 35 | REQUIRE(10 == node->value); 36 | REQUIRE(AstNumber == node->type); 37 | 38 | Token T1 = {TokenNumber, 5}; 39 | AstNode* node1 = ast_create_leaf(T1); 40 | REQUIRE(NULL != node1); 41 | REQUIRE(5 == node1->value); 42 | REQUIRE(AstNumber == node1->type); 43 | 44 | Token T2 = {TokenPlus, -1}; 45 | AstNode* node2 = ast_create_node(T2, node, node1); 46 | REQUIRE(NULL != node2); 47 | REQUIRE(AstPlus == node2->type); 48 | // todo 49 | // REQUIRE(15 == ast_interpret(NULL, node2)); 50 | } 51 | 52 | TEST_CASE("ast test operator -") 53 | { 54 | void* gen_prm = NULL; 55 | REQUIRE(Success == GenCreate()); 56 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out1")); 57 | 58 | int32_t mock_lex_prm; 59 | void* parse_prm = NULL; 60 | REQUIRE(Success == ParseCreate()); 61 | REQUIRE(Success == ParseOpen(&parse_prm, (void*)&mock_lex_prm, gen_prm, false)); 62 | 63 | Token T = {TokenNumber, 10}; 64 | AstNode* node = ast_create_leaf(T); 65 | REQUIRE(NULL != node); 66 | REQUIRE(10 == node->value); 67 | REQUIRE(AstNumber == node->type); 68 | 69 | Token T1 = {TokenNumber, 5}; 70 | AstNode* node1 = ast_create_leaf(T1); 71 | REQUIRE(NULL != node1); 72 | REQUIRE(5 == node1->value); 73 | REQUIRE(AstNumber == node1->type); 74 | 75 | Token T2 = {TokenMinus, -1}; 76 | AstNode* node2 = ast_create_node(T2, node, node1); 77 | REQUIRE(NULL != node2); 78 | REQUIRE(AstMinus == node2->type); 79 | ast_gen((ParseParameter*)parse_prm, node2); 80 | 81 | ParseClose(parse_prm); 82 | ParseDestroy(); 83 | } 84 | 85 | -------------------------------------------------------------------------------- /test/ast/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define CATCH_CONFIG_MAIN 3 | 4 | #include "catch.hh" 5 | -------------------------------------------------------------------------------- /test/ast/mock_lex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include "lex.h" 7 | #include "error_code.h" 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | vector g_tok_array; 13 | int32_t tok_idx = 0; 14 | 15 | int32_t MockLexCreate(vector tok_array) 16 | { 17 | g_tok_array = tok_array; 18 | //g_tok_array(tok_array.begin(), tok_array.end()); 19 | tok_idx = 0; 20 | return Success; 21 | } 22 | 23 | int32_t MockLexDestroy() 24 | { 25 | g_tok_array.clear(); 26 | tok_idx = 0; 27 | return Success; 28 | } 29 | 30 | int32_t LexCreate(void) 31 | { 32 | return Success; 33 | } 34 | int32_t LexDestroy(void) 35 | { 36 | return Success; 37 | 38 | } 39 | 40 | int32_t LexOpen(void** prm, const char* file) 41 | { 42 | *prm = malloc(1); 43 | return Success; 44 | } 45 | int32_t LexClose(void* prm) 46 | { 47 | free(prm); 48 | return Success; 49 | } 50 | 51 | int32_t LexProc(void* prm, Token *t) 52 | { 53 | if (tok_idx >= g_tok_array.size()) { 54 | return -1; 55 | } 56 | *t = g_tok_array[tok_idx++]; 57 | return Success; 58 | } 59 | 60 | int32_t LexGetLine(void* prm) 61 | { 62 | return Success; 63 | } 64 | -------------------------------------------------------------------------------- /test/gen/Makefile: -------------------------------------------------------------------------------- 1 | CPP = g++ -std=c++11 2 | CC = gcc 3 | LD = g++ -std=c++11 4 | LDFLAGS += 5 | CPPFLAGS := -g -O0 -fpermissive -Wnarrowing -Wno-write-strings 6 | 7 | #-fpermissive -Wnarrowing 8 | 9 | TARGET = gen_test 10 | TOP_SRC = ../../ 11 | TOP_TEST = ../../test 12 | 13 | 14 | INC := -I$(TOP_SRC)/inc 15 | INC += -I$(TOP_TEST)/inc 16 | INC += -I$(TOP_SRC)/src 17 | 18 | SRC_CPP := gen_test.cpp 19 | SRC_CPP += mock_arch.cpp 20 | SRC_CPP += main.cpp 21 | SRC := $(TOP_SRC)/src/gen.c 22 | SRC += $(TOP_SRC)/src/log.c 23 | 24 | CFLAGS += $(INC) 25 | 26 | # generate dependence file 27 | OBJDIR = . 28 | OBJ += $(SRC:%.c=$(OBJDIR)/%.o) 29 | OBJ_CPP += $(SRC_CPP:%.cpp=$(OBJDIR)/%.o) 30 | 31 | # Add target to build library 32 | all:TARGET 33 | 34 | TARGET:$(TARGET) 35 | 36 | $(TARGET):$(OBJ) $(OBJ_CPP) 37 | $(LD) $(LDFLAGS) -o $@ $(OBJ) $(OBJ_CPP) $(LIBS) 38 | 39 | $(OBJDIR)/%.o : %.c 40 | $(CC) $(CFLAGS) -c $< -o $@ 41 | 42 | $(OBJDIR)/%.o : %.cpp 43 | $(CPP) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 44 | 45 | clean: 46 | -rm $(OBJ) $(OBJ_CPP) 47 | -rm $(TARGET) 48 | 49 | .PHONY:clean all TARGET 50 | 51 | -include $(shell mkdir $(OBJDIR) 2>/dev/null) $(wildcard $(OBJDIR)/*.d) 52 | -------------------------------------------------------------------------------- /test/gen/gen_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "gen.h" 11 | #include "error_code.h" 12 | 13 | #include "common.h" 14 | #include "catch.hh" 15 | 16 | using namespace std; 17 | int32_t MockGetValue(char* r); 18 | 19 | TEST_CASE("gen test get single resource") 20 | { 21 | create_folder("data"); 22 | void* prm = NULL; 23 | REQUIRE(Success == GenCreate()); 24 | REQUIRE(Success == GenOpen(&prm, GenX86_64, (char*)"data/test1")); 25 | 26 | REQUIRE(Success == GenClose(prm)); 27 | REQUIRE(Success == GenDestroy()); 28 | } 29 | 30 | TEST_CASE("gen test get multi resource") 31 | { 32 | int max_rsc = 10; 33 | vector prm = vector(10,NULL); 34 | REQUIRE(Success == GenCreate()); 35 | for (auto& p : prm) { 36 | REQUIRE(Success == GenOpen(&p, GenX86_64, (char*)"data/test2")); 37 | REQUIRE(NULL != p); 38 | } 39 | 40 | REQUIRE(InParameterInvalid == GenOpen(&prm[0], GenX86_64, (char*)"data/test21")); 41 | 42 | void* a_prm = NULL; 43 | REQUIRE(GenLimitResource == GenOpen(&a_prm, GenX86_64, (char*)"data/test22")); 44 | REQUIRE(NULL == a_prm); 45 | 46 | for (auto& p : prm) { 47 | REQUIRE(Success == GenClose(p)); 48 | } 49 | 50 | REQUIRE(Success == GenDestroy()); 51 | } 52 | 53 | TEST_CASE("gen test basic parttern + ") 54 | { 55 | void* prm = NULL; 56 | REQUIRE(Success == GenCreate()); 57 | REQUIRE(Success == GenOpen(&prm, GenX86_64, (char*)"data/test3")); 58 | 59 | char* r1 = GenLoad(prm, 1); 60 | REQUIRE(NULL != r1); 61 | 62 | char* r2 = GenLoad(prm, 2); 63 | REQUIRE(NULL != r2); 64 | 65 | char* r3 = GenPlus(prm, r1,r2); 66 | int32_t total = MockGetValue(r3); 67 | REQUIRE(total == (1+2)); 68 | REQUIRE(Success == GenClose(prm)); 69 | REQUIRE(Success == GenDestroy()); 70 | } 71 | 72 | 73 | TEST_CASE("gen test basic parttern -") 74 | { 75 | void* prm = NULL; 76 | REQUIRE(Success == GenCreate()); 77 | REQUIRE(Success == GenOpen(&prm, GenX86_64, (char*)"data/test3")); 78 | 79 | char* r1 = GenLoad(prm, 1); 80 | REQUIRE(NULL != r1); 81 | 82 | char* r2 = GenLoad(prm, 2); 83 | REQUIRE(NULL != r2); 84 | 85 | char* r3 = GenMinus(prm, r1,r2); 86 | 87 | int32_t total = MockGetValue(r3); 88 | REQUIRE(total == (1-2)); 89 | REQUIRE(Success == GenClose(prm)); 90 | REQUIRE(Success == GenDestroy()); 91 | } 92 | 93 | 94 | TEST_CASE("gen test basic parttern * ") 95 | { 96 | void* prm = NULL; 97 | REQUIRE(Success == GenCreate()); 98 | REQUIRE(Success == GenOpen(&prm, GenX86_64, (char*)"data/test3")); 99 | 100 | char* r1 = GenLoad(prm, 3); 101 | REQUIRE(NULL != r1); 102 | 103 | char* r2 = GenLoad(prm, 2); 104 | REQUIRE(NULL != r2); 105 | 106 | char* r3 = GenMul(prm, r1,r2); 107 | 108 | int32_t total = MockGetValue(r3); 109 | REQUIRE(total == (3*2)); 110 | REQUIRE(Success == GenClose(prm)); 111 | REQUIRE(Success == GenDestroy()); 112 | } 113 | 114 | 115 | TEST_CASE("gen test basic parttern / ") 116 | { 117 | void* prm = NULL; 118 | REQUIRE(Success == GenCreate()); 119 | REQUIRE(Success == GenOpen(&prm, GenX86_64, (char*)"data/test3")); 120 | 121 | char* r1 = GenLoad(prm, 10); 122 | REQUIRE(NULL != r1); 123 | 124 | char* r2 = GenLoad(prm, 2); 125 | REQUIRE(NULL != r2); 126 | 127 | char* r3 = GenDiv(prm, r1,r2); 128 | 129 | int32_t total = MockGetValue(r3); 130 | REQUIRE(total == (10/2)); 131 | REQUIRE(Success == GenClose(prm)); 132 | REQUIRE(Success == GenDestroy()); 133 | } 134 | 135 | TEST_CASE("gen test basic parttern combine arithmetic 10*2+4/2-5") 136 | { 137 | void* prm = NULL; 138 | REQUIRE(Success == GenCreate()); 139 | REQUIRE(Success == GenOpen(&prm, GenX86_64, (char*)"data/test3")); 140 | 141 | 142 | Token t1 = {TokenNumber, 10}; 143 | Token t2 = {TokenNumber, 2}; 144 | Token t3 = {TokenNumber, 4}; 145 | Token t4 = {TokenNumber, 2}; 146 | Token t5 = {TokenNumber, 5}; 147 | 148 | char* r1 = GenLoad(prm, 10); 149 | REQUIRE(NULL != r1); 150 | char* r2 = GenLoad(prm, 2); 151 | REQUIRE(NULL != r2); 152 | 153 | char* r3 = GenMul(prm, r1,r2); 154 | REQUIRE(NULL != r3); 155 | 156 | char* r4 = GenLoad(prm, 4); 157 | REQUIRE(NULL != r4); 158 | 159 | char* r5 = GenLoad(prm, 2); 160 | REQUIRE(NULL != r5); 161 | 162 | char* r6 = GenDiv(prm, r4, r5); 163 | 164 | char* r7 = GenPlus(prm, r3, r6); // 10*2+4/2 165 | 166 | char* r8 = GenLoad(prm, 5); 167 | REQUIRE(NULL != r8); 168 | 169 | char* r9 = GenMinus(prm, r7, r8); // 10*2+4/2-5 170 | 171 | int32_t total = MockGetValue(r9); 172 | REQUIRE(total == (10*2+4/2-5)); 173 | REQUIRE(Success == GenClose(prm)); 174 | REQUIRE(Success == GenDestroy()); 175 | } 176 | -------------------------------------------------------------------------------- /test/gen/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #define CATCH_CONFIG_MAIN 7 | #include "catch.hh" 8 | -------------------------------------------------------------------------------- /test/gen/mock_arch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "error_code.h" 7 | #include "gen_internal.h" 8 | 9 | using namespace std; 10 | static char* mock_load(int32_t value, FILE* out_file); 11 | static char* mock_add(char* r1, char* r2, FILE* out_file); 12 | static char* mock_sub(char* r1, char* r2, FILE* out_file); 13 | static char* mock_mul(char* r1, char* r2, FILE* out_file); 14 | static char* mock_div(char* r1, char* r2, FILE* out_file); 15 | 16 | // register 17 | vector reg = {"r0","r1","r2","r3","r4"}; 18 | 19 | int cur = 0; 20 | unordered_map mem; 21 | 22 | int32_t GenLoadX86_64(GenFuncTable *func) 23 | { 24 | func->f_load = &mock_load; 25 | func->f_add = &mock_add; 26 | func->f_sub = &mock_sub; 27 | func->f_mul = &mock_mul; 28 | func->f_div = &mock_div; 29 | for (auto r : reg) { 30 | mem[r] = 0; 31 | } 32 | cur = 0; 33 | return Success; 34 | } 35 | 36 | int32_t MockGetValue(char* r) 37 | { 38 | return mem[r]; 39 | } 40 | 41 | char* reg_alloc() { 42 | if (cur >= reg.size()) { 43 | cout << "Not have available register" << endl; 44 | return NULL; 45 | } 46 | return reg[cur++]; 47 | } 48 | 49 | void reg_free(char* r) { 50 | if (mem.find(r) == mem.end()) { 51 | cout << "Free reg is not correct" << endl; 52 | exit(1); 53 | } 54 | reg[--cur] = r; 55 | } 56 | 57 | static char* mock_load(int32_t value, FILE* out_file) 58 | { 59 | char* r = reg_alloc(); 60 | if (NULL == r) { 61 | return NULL; 62 | } 63 | mem[r] = value; 64 | return r; 65 | } 66 | 67 | static char* mock_add(char* r1, char* r2, FILE* out_file) 68 | { 69 | mem[r1] += mem[r2]; 70 | mem[r2] = 0; 71 | reg_free(r2); 72 | return r1; 73 | } 74 | 75 | static char* mock_sub(char* r1, char* r2, FILE* out_file) 76 | { 77 | mem[r1] -= mem[r2]; 78 | mem[r2] = 0; 79 | reg_free(r2); 80 | return r1; 81 | } 82 | 83 | static char* mock_mul(char* r1, char* r2, FILE* out_file) 84 | { 85 | mem[r1] *= mem[r2]; 86 | mem[r2] = 0; 87 | reg_free(r2); 88 | return r1; 89 | } 90 | 91 | static char* mock_div(char* r1, char* r2, FILE* out_file) 92 | { 93 | mem[r1] /= mem[r2]; 94 | mem[r2] = 0; 95 | reg_free(r2); 96 | return r1; 97 | } 98 | -------------------------------------------------------------------------------- /test/inc/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef _COMMON_TEST_H_ 10 | #define _COMMON_TEST_H_ 11 | 12 | void create_folder(std::string folder) 13 | { 14 | struct stat sb; 15 | if (!(stat(folder.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode))) { 16 | system(("mkdir " + folder).c_str()); 17 | } 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /test/intergration/Makefile: -------------------------------------------------------------------------------- 1 | CPP = g++ -std=c++11 2 | CC = gcc 3 | LD = g++ -std=c++11 4 | LDFLAGS += 5 | CPPFLAGS := -g -O0 -fpermissive -Wnarrowing -Wno-write-strings 6 | 7 | #-fpermissive -Wnarrowing 8 | 9 | TARGET = intergration_test 10 | TOP_SRC = ../.. 11 | TOP_TEST = ../../test 12 | 13 | 14 | INC := -I$(TOP_SRC)/inc 15 | INC += -I$(TOP_SRC)/src 16 | INC += -I$(TOP_TEST)/inc 17 | 18 | SRC_CPP := parse_lex_test.cpp 19 | SRC_CPP += mock_arch.cpp 20 | SRC_CPP += main.cpp 21 | SRC := $(TOP_SRC)/src/parse.c 22 | SRC += $(TOP_SRC)/src/gen.c 23 | SRC += $(TOP_SRC)/src/ast.c 24 | SRC += $(TOP_SRC)/src/symtable.c 25 | SRC += $(TOP_SRC)/src/log.c 26 | SRC += $(TOP_SRC)/src/lex.c 27 | 28 | CFLAGS += $(INC) 29 | 30 | # generate dependence file 31 | OBJDIR = . 32 | OBJ += $(SRC:%.c=$(OBJDIR)/%.o) 33 | OBJ_CPP += $(SRC_CPP:%.cpp=$(OBJDIR)/%.o) 34 | 35 | # Add target to build library 36 | all:TARGET 37 | 38 | TARGET:$(TARGET) 39 | 40 | $(TARGET):$(OBJ) $(OBJ_CPP) 41 | $(LD) $(LDFLAGS) -o $@ $(OBJ) $(OBJ_CPP) $(LIBS) 42 | 43 | $(OBJDIR)/%.o : %.c 44 | $(CC) $(CFLAGS) -c $< -o $@ 45 | 46 | $(OBJDIR)/%.o : %.cpp 47 | $(CPP) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 48 | 49 | clean: 50 | -rm $(OBJ) $(OBJ_CPP) 51 | -rm $(TARGET) 52 | 53 | .PHONY:clean all TARGET 54 | 55 | -include $(shell mkdir $(OBJDIR) 2>/dev/null) $(wildcard $(OBJDIR)/*.d) 56 | -------------------------------------------------------------------------------- /test/intergration/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #define CATCH_CONFIG_MAIN 7 | #include "catch.hh" 8 | -------------------------------------------------------------------------------- /test/intergration/mock_arch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "error_code.h" 7 | #include "gen_internal.h" 8 | 9 | using namespace std; 10 | static char* mock_load(int32_t value, FILE* out_file); 11 | static char* mock_out(char* r, FILE* out_file); 12 | static char* mock_free(char* r, FILE* out_file); 13 | 14 | static char* mock_add(char* r1, char* r2, FILE* out_file); 15 | static char* mock_sub(char* r1, char* r2, FILE* out_file); 16 | static char* mock_mul(char* r1, char* r2, FILE* out_file); 17 | static char* mock_div(char* r1, char* r2, FILE* out_file); 18 | 19 | static char* mock_lt(char* r1, char* r2, FILE* out_file); 20 | static char* mock_le(char* r1, char* r2, FILE* out_file); 21 | static char* mock_gt(char* r1, char* r2, FILE* out_file); 22 | static char* mock_ge(char* r1, char* r2, FILE* out_file); 23 | static char* mock_eq(char* r1, char* r2, FILE* out_file); 24 | static char* mock_ne(char* r1, char* r2, FILE* out_file); 25 | 26 | static char* mock_or(char* r1, char* r2, FILE* out_file); 27 | static char* mock_and(char* r1, char* r2, FILE* out_file); 28 | static char* mock_b_or(char* r1, char* r2, FILE* out_file); 29 | static char* mock_b_xor(char* r1, char* r2, FILE* out_file); 30 | static char* mock_b_and(char* r1, char* r2, FILE* out_file); 31 | 32 | static char* mock_lt_j(char* r1, char* r2, char* l, FILE* out_file); 33 | static char* mock_le_j(char* r1, char* r2, char* l, FILE* out_file); 34 | static char* mock_gt_j(char* r1, char* r2, char* l, FILE* out_file); 35 | static char* mock_ge_j(char* r1, char* r2, char* l, FILE* out_file); 36 | static char* mock_eq_j(char* r1, char* r2, char* l, FILE* out_file); 37 | static char* mock_ne_j(char* r1, char* r2, char* l, FILE* out_file); 38 | static char* mock_jump(char* l, FILE* out_file); 39 | static char* mock_zero_j(char* r, char* l, FILE* out_file); 40 | static char* mock_label(char* l, FILE* out_file); 41 | static char* mock_func(char* name, int stack_size, FILE* out_file); 42 | static char* mock_func_exit(char* label, int stack_size, FILE* out_file); 43 | static char* mock_return(char* r, char* exit_label, FILE* out_file); 44 | 45 | static char* mock_var(char* var, FILE* out_file); 46 | static char* mock_local_var(char* var, int size, FILE* out_file); 47 | static char* mock_store(char* r, char* var, FILE* out_file); 48 | static char* mock_load_var(char* var, FILE* out_file); 49 | 50 | // register 51 | vector reg = {"r0","r1","r2","r3","r4"}; 52 | unordered_map g_variable; 53 | unordered_map mem; 54 | 55 | int cur = 0; 56 | vector return_value = {}; 57 | int p_index = 0; 58 | 59 | int32_t GenLoadX86_64(GenFuncTable *func) 60 | { 61 | func->f_load = &mock_load; 62 | func->f_out = &mock_out; 63 | func->f_free = &mock_free; 64 | func->f_var = &mock_var; 65 | func->f_l_var = &mock_local_var; 66 | func->f_add = &mock_add; 67 | func->f_sub = &mock_sub; 68 | func->f_mul = &mock_mul; 69 | func->f_div = &mock_div; 70 | func->f_lt = &mock_lt; 71 | func->f_le = &mock_le; 72 | func->f_gt = &mock_gt; 73 | func->f_ge = &mock_ge; 74 | func->f_eq = &mock_eq; 75 | func->f_ne = &mock_ne; 76 | 77 | func->f_or = &mock_or; 78 | func->f_and = &mock_and; 79 | func->f_b_or = &mock_b_or; 80 | func->f_b_xor = &mock_b_xor; 81 | func->f_b_and = &mock_b_and; 82 | 83 | func->f_lt_j = &mock_lt_j; 84 | func->f_le_j = &mock_le_j; 85 | func->f_gt_j = &mock_gt_j; 86 | func->f_ge_j = &mock_ge_j; 87 | func->f_eq_j = &mock_eq_j; 88 | func->f_ne_j = &mock_ne_j; 89 | func->f_jump = &mock_jump; 90 | func->f_zero_j = &mock_zero_j; 91 | func->f_label = &mock_label; 92 | func->f_func = &mock_func; 93 | func->f_func_exit = &mock_func_exit; 94 | func->f_return = &mock_return; 95 | 96 | func->f_store = &mock_store; 97 | func->f_load_var = &mock_load_var; 98 | 99 | for (auto r : reg) { 100 | mem[r] = 0; 101 | } 102 | cur = 0; 103 | p_index = 0; 104 | g_variable.clear(); 105 | return_value.clear(); 106 | 107 | return Success; 108 | } 109 | 110 | int32_t MockGetReturnValue() 111 | { 112 | if (p_index > return_value.size()) { 113 | cout << "Not having print out data" << endl; 114 | return -1; 115 | }; 116 | return return_value[p_index++]; 117 | } 118 | 119 | char* reg_alloc() { 120 | if (cur >= reg.size()) { 121 | cout << "Not have available register" << endl; 122 | return NULL; 123 | } 124 | return reg[cur++]; 125 | } 126 | 127 | void reg_free(char* r) { 128 | if (mem.find(r) == mem.end()) { 129 | // cout << "Free reg is not correct: " << r << endl; 130 | return; 131 | } 132 | reg[--cur] = r; 133 | } 134 | 135 | static char* mock_load(int32_t value, FILE* out_file) 136 | { 137 | char* r = reg_alloc(); 138 | if (NULL == r) { 139 | return NULL; 140 | } 141 | mem[r] = value; 142 | fprintf(out_file,"[LOAD]:\t %s = %d\n", r, value); 143 | return r; 144 | } 145 | 146 | static char* mock_out(char* r, FILE* out_file) 147 | { 148 | reg_free(r); 149 | return r; 150 | } 151 | 152 | static char* mock_free(char* r, FILE* out_file) 153 | { 154 | reg_free(r); 155 | return NULL; 156 | } 157 | 158 | static char* mock_add(char* r1, char* r2, FILE* out_file) 159 | { 160 | mem[r1] += mem[r2]; 161 | mem[r2] = 0; 162 | reg_free(r2); 163 | fprintf(out_file,"[ADD ]:\t %s = %s+%s\n",r1,r1,r2); 164 | return r1; 165 | } 166 | 167 | static char* mock_sub(char* r1, char* r2, FILE* out_file) 168 | { 169 | mem[r1] -= mem[r2]; 170 | mem[r2] = 0; 171 | reg_free(r2); 172 | fprintf(out_file,"[SUB ]:\t %s = %s-%s\n",r1,r1,r2); 173 | return r1; 174 | } 175 | 176 | static char* mock_mul(char* r1, char* r2, FILE* out_file) 177 | { 178 | mem[r1] *= mem[r2]; 179 | mem[r2] = 0; 180 | reg_free(r2); 181 | fprintf(out_file,"[MUL ]:\t %s = %s*%s\n",r1,r1,r2); 182 | return r1; 183 | } 184 | 185 | static char* mock_div(char* r1, char* r2, FILE* out_file) 186 | { 187 | mem[r1] /= mem[r2]; 188 | mem[r2] = 0; 189 | reg_free(r2); 190 | fprintf(out_file,"[DIV ]:\t %s = %s/%s\n",r1,r1,r2); 191 | return r1; 192 | } 193 | 194 | static char* mock_lt(char* r1, char* r2, FILE* out_file) 195 | { 196 | mem[r1] = (mem[r1] < mem[r2]); 197 | mem[r2] = 0; 198 | reg_free(r2); 199 | fprintf(out_file,"[LT ]:\t %s = %s < %s\n",r1,r1,r2); 200 | return r1; 201 | } 202 | 203 | static char* mock_le(char* r1, char* r2, FILE* out_file) 204 | { 205 | mem[r1] = (mem[r1] <= mem[r2]); 206 | mem[r2] = 0; 207 | reg_free(r2); 208 | fprintf(out_file,"[LE ]:\t %s = %s <= %s\n",r1,r1,r2); 209 | return r1; 210 | } 211 | 212 | static char* mock_gt(char* r1, char* r2, FILE* out_file) 213 | { 214 | mem[r1] = (mem[r1] > mem[r2]); 215 | mem[r2] = 0; 216 | reg_free(r2); 217 | fprintf(out_file,"[GT ]:\t %s = %s > %s\n",r1,r1,r2); 218 | return r1; 219 | } 220 | 221 | static char* mock_ge(char* r1, char* r2, FILE* out_file) 222 | { 223 | mem[r1] = (mem[r1] <= mem[r2]); 224 | mem[r2] = 0; 225 | reg_free(r2); 226 | fprintf(out_file,"[GE ]:\t %s = %s >= %s\n",r1,r1,r2); 227 | return r1; 228 | } 229 | 230 | static char* mock_eq(char* r1, char* r2, FILE* out_file) 231 | { 232 | mem[r1] = (mem[r1] == mem[r2]); 233 | mem[r2] = 0; 234 | reg_free(r2); 235 | fprintf(out_file,"[EQUA]:\t %s = %s == %s\n",r1,r1,r2); 236 | return r1; 237 | } 238 | 239 | static char* mock_ne(char* r1, char* r2, FILE* out_file) 240 | { 241 | mem[r1] = (mem[r1] != mem[r2]); 242 | mem[r2] = 0; 243 | reg_free(r2); 244 | fprintf(out_file,"[NE ]:\t %s = %s != %s\n",r1,r1,r2); 245 | return r1; 246 | } 247 | 248 | static char* mock_or(char* r1, char* r2, FILE* out_file) 249 | { 250 | mem[r1] = mem[r1] || mem[r2]; 251 | mem[r2] = 0; 252 | reg_free(r2); 253 | fprintf(out_file,"[OR ]:\t %s = %s || %s\n",r1,r1,r2); 254 | return r1; 255 | } 256 | 257 | static char* mock_and(char* r1, char* r2, FILE* out_file) 258 | { 259 | mem[r1] = mem[r1] && mem[r2]; 260 | mem[r2] = 0; 261 | reg_free(r2); 262 | fprintf(out_file,"[AND ]:\t %s = %s && %s\n",r1,r1,r2); 263 | return r1; 264 | } 265 | 266 | static char* mock_b_or(char* r1, char* r2, FILE* out_file) 267 | { 268 | mem[r1] = mem[r1] | mem[r2]; 269 | mem[r2] = 0; 270 | reg_free(r2); 271 | fprintf(out_file,"[BOR ]:\t %s = %s | %s\n",r1,r1,r2); 272 | return r1; 273 | } 274 | 275 | static char* mock_b_xor(char* r1, char* r2, FILE* out_file) 276 | { 277 | mem[r1] = mem[r1] ^ mem[r2]; 278 | mem[r2] = 0; 279 | reg_free(r2); 280 | fprintf(out_file,"[BXOR]:\t %s = %s ^ %s\n",r1,r1,r2); 281 | return r1; 282 | } 283 | 284 | static char* mock_b_and(char* r1, char* r2, FILE* out_file) 285 | { 286 | mem[r1] = mem[r1] & mem[r2]; 287 | mem[r2] = 0; 288 | reg_free(r2); 289 | fprintf(out_file,"[BAND]:\t %s = %s & %s\n",r1,r1,r2); 290 | return r1; 291 | } 292 | 293 | static char* mock_lt_j(char* r1, char* r2, char* l, FILE* out_file) 294 | { 295 | // TODO : add mock processing 296 | reg_free(r1); 297 | reg_free(r2); 298 | fprintf(out_file,"[JUMP]:\t %s if %s < %s\n",l,r1,r2); 299 | return l; 300 | } 301 | 302 | static char* mock_le_j(char* r1, char* r2, char* l, FILE* out_file) 303 | { 304 | // TODO : add mock processing 305 | reg_free(r1); 306 | reg_free(r2); 307 | fprintf(out_file,"[JUMP]:\t %s if %s <= %s\n",l,r1,r2); 308 | return l; 309 | } 310 | 311 | static char* mock_gt_j(char* r1, char* r2, char* l, FILE* out_file) 312 | { 313 | reg_free(r1); 314 | reg_free(r2); 315 | fprintf(out_file,"[JUMP]:\t %s if %s > %s\n",l,r1,r2); 316 | return l; 317 | } 318 | 319 | static char* mock_ge_j(char* r1, char* r2, char* l, FILE* out_file) 320 | { 321 | reg_free(r1); 322 | reg_free(r2); 323 | fprintf(out_file,"[JUMP]:\t %s if %s >= %s\n",l,r1,r2); 324 | return l; 325 | } 326 | 327 | static char* mock_eq_j(char* r1, char* r2, char* l, FILE* out_file) 328 | { 329 | reg_free(r1); 330 | reg_free(r2); 331 | fprintf(out_file,"[JUMP]:\t %s if %s == %s\n",l,r1,r2); 332 | return l; 333 | } 334 | 335 | static char* mock_ne_j(char* r1, char* r2, char* l, FILE* out_file) 336 | { 337 | reg_free(r1); 338 | reg_free(r2); 339 | fprintf(out_file,"[JUMP]:\t %s if %s != %s\n",l,r1,r2); 340 | return l; 341 | } 342 | 343 | static char* mock_jump(char* l, FILE* out_file) 344 | { 345 | fprintf(out_file,"[JUMP]:\t %s\n",l); 346 | return l; 347 | } 348 | 349 | static char* mock_zero_j(char* r, char* l, FILE* out_file) 350 | { 351 | fprintf(out_file,"[JPZR]:\t %s if %s == 0\n",l,r); 352 | } 353 | 354 | static char* mock_label(char* l, FILE* out_file) 355 | { 356 | fprintf(out_file,"[LBEL]:\t %s: <- label\n",l); 357 | return l; 358 | } 359 | 360 | static char* mock_func(char* name, int stack_size, FILE* out_file) 361 | { 362 | (void)stack_size; 363 | fprintf(out_file,"[FUNC]:\t %s:\n",name); 364 | return name; 365 | } 366 | 367 | static char* mock_func_exit(char* label, int stack_size, FILE* out_file) 368 | { 369 | (void)stack_size; 370 | fprintf(out_file,"[EXIT]:\t %s:\n",label); 371 | return label; 372 | } 373 | 374 | static char* mock_return(char* r, char* exit_label, FILE* out_file) 375 | { 376 | return_value.push_back(mem[r]); 377 | reg_free(r); 378 | fprintf(out_file,"[RET ]:\t %s\n",r); 379 | fprintf(out_file,"[GOTO]:\t %s\n",exit_label); 380 | return exit_label; 381 | } 382 | static char* mock_var(char* var, FILE* out_file) 383 | { 384 | // just allocate buffer for var 385 | string s_var(var); 386 | g_variable[s_var] = 0; 387 | 388 | fprintf(out_file,"[DECL]:\t %s\n",var); 389 | return var; 390 | } 391 | 392 | static char* mock_local_var(char* var, int size, FILE* out_file) 393 | { 394 | string s_var(var); 395 | g_variable[s_var] = 0; 396 | fprintf(out_file,"[DECL]:\t %s\n",var); 397 | return var; 398 | } 399 | 400 | static char* mock_store(char* var, char* r, FILE* out_file) 401 | { 402 | string s_var(var); 403 | if (g_variable.find(s_var) == g_variable.end()) { 404 | fprintf(out_file,"[FUCK]:\t %s not found\n",var); 405 | return NULL; 406 | } 407 | g_variable[s_var] = mem[r]; 408 | reg_free(r); 409 | 410 | fprintf(out_file,"[STOR]:\t %s = %s(%d)\n",var,r,mem[r]); 411 | return var; 412 | } 413 | 414 | static char* mock_load_var(char* var, FILE* out_file) 415 | { 416 | string s_var(var); 417 | char* r = reg_alloc(); 418 | mem[r] = g_variable[s_var]; 419 | fprintf(out_file,"[LOAD]:\t %s = %s(%d)\n",r,var,g_variable[s_var]); 420 | return r; 421 | } 422 | 423 | -------------------------------------------------------------------------------- /test/intergration/parse_lex_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "lex.h" 12 | #include "gen.h" 13 | #include "parse.h" 14 | #include "error_code.h" 15 | 16 | #include "common.h" 17 | #include "catch.hh" 18 | 19 | using namespace std; 20 | int32_t MockGetReturnValue(); 21 | 22 | TEST_CASE("basic arithmetic op parttern : return 1+2;") 23 | { 24 | create_folder("data"); 25 | std::ofstream outfile ("data/test1"); 26 | outfile << "int main() {" << std::endl; 27 | outfile << "return 1+2;" << std::endl; 28 | outfile << "}" << std::endl; 29 | outfile.close(); 30 | 31 | void* lex_prm = NULL; 32 | REQUIRE(Success == LexCreate()); 33 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test1")); 34 | 35 | void* gen_prm = NULL; 36 | REQUIRE(Success == GenCreate()); 37 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out1")); 38 | 39 | void* parse_prm = NULL; 40 | REQUIRE(Success == ParseCreate()); 41 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 42 | 43 | REQUIRE(Success == ParseProc(parse_prm)); 44 | REQUIRE(MockGetReturnValue() == (1+2)); 45 | 46 | ParseClose(parse_prm); 47 | ParseDestroy(); 48 | 49 | REQUIRE(Success == GenClose(gen_prm)); 50 | REQUIRE(Success == GenDestroy()); 51 | 52 | REQUIRE(Success == LexClose(lex_prm)); 53 | REQUIRE(Success == LexDestroy()); 54 | 55 | } 56 | 57 | TEST_CASE("basic variable parttern: int a; int b;") 58 | { 59 | std::ofstream outfile ("data/test2"); 60 | outfile << "int main() { " << std::endl; 61 | outfile << " int a; " << std::endl; 62 | outfile << " int b; " << std::endl; 63 | outfile << " a = 2; " << std::endl; 64 | outfile << " b = 5; " << std::endl; 65 | outfile << " a = a*b; " << std::endl; 66 | outfile << " return a*b;" << std::endl; 67 | outfile << "} " << std::endl; 68 | outfile.close(); 69 | 70 | void* lex_prm = NULL; 71 | REQUIRE(Success == LexCreate()); 72 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test2")); 73 | 74 | void* gen_prm = NULL; 75 | REQUIRE(Success == GenCreate()); 76 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out2")); 77 | 78 | void* parse_prm = NULL; 79 | REQUIRE(Success == ParseCreate()); 80 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 81 | 82 | REQUIRE(Success == ParseProc(parse_prm)); 83 | REQUIRE(MockGetReturnValue() == (2*5*5)); 84 | 85 | ParseClose(parse_prm); 86 | ParseDestroy(); 87 | 88 | REQUIRE(Success == GenClose(gen_prm)); 89 | REQUIRE(Success == GenDestroy()); 90 | 91 | REQUIRE(Success == LexClose(lex_prm)); 92 | REQUIRE(Success == LexDestroy()); 93 | 94 | } 95 | 96 | TEST_CASE("basic variable parttern: hw reg resource manager test") 97 | { 98 | std::ofstream outfile ("data/test3"); 99 | outfile << "int main() {" << std::endl; 100 | outfile << "int a1;" << std::endl; 101 | outfile << "int a2;" << std::endl; 102 | outfile << "int a3;" << std::endl; 103 | outfile << "int a4;" << std::endl; 104 | outfile << "int a5;" << std::endl; 105 | outfile << "int a6;" << std::endl; 106 | outfile << "int a7;" << std::endl; 107 | outfile << "a1 = 1;" << std::endl; 108 | outfile << "a2 = 2;" << std::endl; 109 | outfile << "a3 = 3;" << std::endl; 110 | outfile << "a4 = 4;" << std::endl; 111 | outfile << "a5 = 5;" << std::endl; 112 | outfile << "a6 = 6;" << std::endl; 113 | outfile << "return a1+a2+a3+a4+a5+a6;" << std::endl; 114 | outfile << "}" << std::endl; 115 | outfile.close(); 116 | 117 | void* lex_prm = NULL; 118 | REQUIRE(Success == LexCreate()); 119 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test3")); 120 | 121 | void* gen_prm = NULL; 122 | REQUIRE(Success == GenCreate()); 123 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out3")); 124 | 125 | void* parse_prm = NULL; 126 | REQUIRE(Success == ParseCreate()); 127 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 128 | 129 | REQUIRE(Success == ParseProc(parse_prm)); 130 | REQUIRE(MockGetReturnValue() == (1+2+3+4+5+6)); 131 | 132 | ParseClose(parse_prm); 133 | ParseDestroy(); 134 | 135 | REQUIRE(Success == GenClose(gen_prm)); 136 | REQUIRE(Success == GenDestroy()); 137 | 138 | REQUIRE(Success == LexClose(lex_prm)); 139 | REQUIRE(Success == LexDestroy()); 140 | 141 | } 142 | 143 | 144 | TEST_CASE("relational basic pattern") 145 | { 146 | std::ofstream outfile ("data/test4"); 147 | outfile << "int main() {" << std::endl; 148 | outfile << "return 1 < 2;" << std::endl; 149 | outfile << "}" << std::endl; 150 | outfile.close(); 151 | 152 | void* lex_prm = NULL; 153 | REQUIRE(Success == LexCreate()); 154 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test4")); 155 | 156 | void* gen_prm = NULL; 157 | REQUIRE(Success == GenCreate()); 158 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out4")); 159 | 160 | void* parse_prm = NULL; 161 | REQUIRE(Success == ParseCreate()); 162 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 163 | 164 | REQUIRE(Success == ParseProc(parse_prm)); 165 | REQUIRE(MockGetReturnValue() == 1); 166 | 167 | ParseClose(parse_prm); 168 | ParseDestroy(); 169 | 170 | REQUIRE(Success == GenClose(gen_prm)); 171 | REQUIRE(Success == GenDestroy()); 172 | 173 | REQUIRE(Success == LexClose(lex_prm)); 174 | REQUIRE(Success == LexDestroy()); 175 | } 176 | 177 | TEST_CASE("relational basic pattern with variable") 178 | { 179 | std::ofstream outfile ("data/test5"); 180 | outfile << "void main() {" << std::endl; 181 | outfile << "int a1;" << std::endl; 182 | outfile << "int a2;" << std::endl; 183 | outfile << "a1 = 1;" << std::endl; 184 | outfile << "a2 = 2;" << std::endl; 185 | outfile << "return a1 > a2;" << std::endl; 186 | outfile << "}" << std::endl; 187 | outfile.close(); 188 | 189 | void* lex_prm = NULL; 190 | REQUIRE(Success == LexCreate()); 191 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test5")); 192 | 193 | void* gen_prm = NULL; 194 | REQUIRE(Success == GenCreate()); 195 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out5")); 196 | 197 | void* parse_prm = NULL; 198 | REQUIRE(Success == ParseCreate()); 199 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 200 | 201 | REQUIRE(Success == ParseProc(parse_prm)); 202 | REQUIRE(MockGetReturnValue() == 0); 203 | 204 | ParseClose(parse_prm); 205 | ParseDestroy(); 206 | 207 | REQUIRE(Success == GenClose(gen_prm)); 208 | REQUIRE(Success == GenDestroy()); 209 | 210 | REQUIRE(Success == LexClose(lex_prm)); 211 | REQUIRE(Success == LexDestroy()); 212 | 213 | } 214 | 215 | TEST_CASE("equal basic pattern with variable") 216 | { 217 | std::ofstream outfile ("data/test6"); 218 | outfile << "int main() {" << std::endl; 219 | outfile << "int a1;" << std::endl; 220 | outfile << "int a2;" << std::endl; 221 | outfile << "a1 = 2;" << std::endl; 222 | outfile << "a2 = 2;" << std::endl; 223 | outfile << "return a1 == a2;" << std::endl; 224 | outfile << "}" << std::endl; 225 | outfile.close(); 226 | 227 | void* lex_prm = NULL; 228 | REQUIRE(Success == LexCreate()); 229 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test6")); 230 | 231 | void* gen_prm = NULL; 232 | REQUIRE(Success == GenCreate()); 233 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out6")); 234 | 235 | void* parse_prm = NULL; 236 | REQUIRE(Success == ParseCreate()); 237 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 238 | 239 | REQUIRE(Success == ParseProc(parse_prm)); 240 | REQUIRE(MockGetReturnValue() == 1); 241 | 242 | ParseClose(parse_prm); 243 | ParseDestroy(); 244 | 245 | REQUIRE(Success == GenClose(gen_prm)); 246 | REQUIRE(Success == GenDestroy()); 247 | 248 | REQUIRE(Success == LexClose(lex_prm)); 249 | REQUIRE(Success == LexDestroy()); 250 | 251 | } 252 | 253 | TEST_CASE("basic parttern with {}") 254 | { 255 | std::ofstream outfile ("data/test7"); 256 | outfile << "void main() {" << std::endl; 257 | outfile << "int a1;" << std::endl; 258 | outfile << "int a2;" << std::endl; 259 | outfile << "{a1 = 1;}" << std::endl; 260 | outfile << "a2 = 2;" << std::endl; 261 | outfile << "{{{{return a2;}}}}" << std::endl; 262 | outfile << "}" << std::endl; 263 | outfile.close(); 264 | 265 | void* lex_prm = NULL; 266 | REQUIRE(Success == LexCreate()); 267 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test7")); 268 | 269 | void* gen_prm = NULL; 270 | REQUIRE(Success == GenCreate()); 271 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out7")); 272 | 273 | void* parse_prm = NULL; 274 | REQUIRE(Success == ParseCreate()); 275 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 276 | 277 | REQUIRE(Success == ParseProc(parse_prm)); 278 | REQUIRE(MockGetReturnValue() == 2); 279 | 280 | ParseClose(parse_prm); 281 | ParseDestroy(); 282 | 283 | REQUIRE(Success == GenClose(gen_prm)); 284 | REQUIRE(Success == GenDestroy()); 285 | 286 | REQUIRE(Success == LexClose(lex_prm)); 287 | REQUIRE(Success == LexDestroy()); 288 | 289 | } 290 | 291 | TEST_CASE("basic if-else pattern") 292 | { 293 | std::ofstream outfile ("data/test8"); 294 | outfile << "int main() { " << std::endl; 295 | outfile << " int a1; " << std::endl; 296 | outfile << " int a2; " << std::endl; 297 | outfile << " a1 = 1; " << std::endl; 298 | outfile << " a2 = 2; " << std::endl; 299 | outfile << " if (a1 > a2) " << std::endl; 300 | outfile << " {return a1;} " << std::endl; 301 | outfile << " else " << std::endl; 302 | outfile << " {return a2;} " << std::endl; 303 | outfile << "} " << std::endl; 304 | outfile.close(); 305 | 306 | void* lex_prm = NULL; 307 | REQUIRE(Success == LexCreate()); 308 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test8")); 309 | 310 | void* gen_prm = NULL; 311 | REQUIRE(Success == GenCreate()); 312 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out8")); 313 | 314 | void* parse_prm = NULL; 315 | REQUIRE(Success == ParseCreate()); 316 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 317 | 318 | REQUIRE(Success == ParseProc(parse_prm)); 319 | // todo: consider how to verify result 320 | // REQUIRE(MockGetReturnValue() == 2); 321 | 322 | ParseClose(parse_prm); 323 | ParseDestroy(); 324 | 325 | REQUIRE(Success == GenClose(gen_prm)); 326 | REQUIRE(Success == GenDestroy()); 327 | 328 | REQUIRE(Success == LexClose(lex_prm)); 329 | REQUIRE(Success == LexDestroy()); 330 | 331 | } 332 | 333 | TEST_CASE("basic & && | || ^ pattern") 334 | { 335 | std::ofstream outfile ("data/test9"); 336 | outfile << "int main() { " << std::endl; 337 | outfile << " int a1; " << std::endl; 338 | outfile << " int a2; " << std::endl; 339 | outfile << " a1 = 1; " << std::endl; 340 | outfile << " a2 = 2; " << std::endl; 341 | outfile << " return (a1 && a2) + (a1 & a2) + (a1 || a2) + (a1 | a2) + (a1 ^ a2); " << std::endl; 342 | outfile << "} " << std::endl; 343 | outfile.close(); 344 | 345 | void* lex_prm = NULL; 346 | REQUIRE(Success == LexCreate()); 347 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test9")); 348 | 349 | void* gen_prm = NULL; 350 | REQUIRE(Success == GenCreate()); 351 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out9")); 352 | 353 | void* parse_prm = NULL; 354 | REQUIRE(Success == ParseCreate()); 355 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 356 | 357 | REQUIRE(Success == ParseProc(parse_prm)); 358 | 359 | int a1 = 1, a2 = 2; 360 | REQUIRE(MockGetReturnValue() == (a1 && a2) + (a1 & a2) + (a1 || a2) + (a1 | a2) + (a1 ^ a2)); 361 | 362 | ParseClose(parse_prm); 363 | ParseDestroy(); 364 | 365 | REQUIRE(Success == GenClose(gen_prm)); 366 | REQUIRE(Success == GenDestroy()); 367 | 368 | REQUIRE(Success == LexClose(lex_prm)); 369 | REQUIRE(Success == LexDestroy()); 370 | 371 | } 372 | 373 | TEST_CASE("simple test case to confirm bug?") 374 | { 375 | std::ofstream outfile ("data/test10"); 376 | outfile << "int main() { " << std::endl; 377 | outfile << " int a; " << std::endl; 378 | outfile << " a = 9; " << std::endl; 379 | outfile << " return a; " << std::endl; 380 | outfile << "} " << std::endl; 381 | outfile.close(); 382 | 383 | void* lex_prm = NULL; 384 | REQUIRE(Success == LexCreate()); 385 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/test10")); 386 | 387 | void* gen_prm = NULL; 388 | REQUIRE(Success == GenCreate()); 389 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out10")); 390 | 391 | void* parse_prm = NULL; 392 | REQUIRE(Success == ParseCreate()); 393 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 394 | 395 | REQUIRE(Success == ParseProc(parse_prm)); 396 | REQUIRE(MockGetReturnValue() == 9); 397 | 398 | ParseClose(parse_prm); 399 | ParseDestroy(); 400 | 401 | REQUIRE(Success == GenClose(gen_prm)); 402 | REQUIRE(Success == GenDestroy()); 403 | 404 | REQUIRE(Success == LexClose(lex_prm)); 405 | REQUIRE(Success == LexDestroy()); 406 | } 407 | 408 | TEST_CASE("pointer 1") 409 | { 410 | std::ofstream outfile ("data/point1"); 411 | outfile << "int main() { " << std::endl; 412 | outfile << " int *a; " << std::endl; 413 | outfile << " int b = 10; " << std::endl; 414 | outfile << " a = &b; " << std::endl; 415 | outfile << " int b = 11; " << std::endl; 416 | outfile << " return *a; " << std::endl; 417 | outfile << "} " << std::endl; 418 | outfile.close(); 419 | 420 | void* lex_prm = NULL; 421 | REQUIRE(Success == LexCreate()); 422 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/point1")); 423 | 424 | void* gen_prm = NULL; 425 | REQUIRE(Success == GenCreate()); 426 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/point1")); 427 | 428 | void* parse_prm = NULL; 429 | REQUIRE(Success == ParseCreate()); 430 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 431 | 432 | REQUIRE(Success == ParseProc(parse_prm)); 433 | REQUIRE(MockGetReturnValue() == 11); 434 | 435 | ParseClose(parse_prm); 436 | ParseDestroy(); 437 | 438 | REQUIRE(Success == GenClose(gen_prm)); 439 | REQUIRE(Success == GenDestroy()); 440 | 441 | REQUIRE(Success == LexClose(lex_prm)); 442 | REQUIRE(Success == LexDestroy()); 443 | } 444 | 445 | TEST_CASE("pointer 2") 446 | { 447 | std::ofstream outfile ("data/point2"); 448 | outfile << "int main() { " << std::endl; 449 | outfile << " int *a; " << std::endl; 450 | outfile << " int b = 10; " << std::endl; 451 | outfile << " a = &b; " << std::endl; 452 | outfile << " *a = 11; " << std::endl; 453 | outfile << " return b; " << std::endl; 454 | outfile << "} " << std::endl; 455 | outfile.close(); 456 | 457 | void* lex_prm = NULL; 458 | REQUIRE(Success == LexCreate()); 459 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/point2")); 460 | 461 | void* gen_prm = NULL; 462 | REQUIRE(Success == GenCreate()); 463 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/point2")); 464 | 465 | void* parse_prm = NULL; 466 | REQUIRE(Success == ParseCreate()); 467 | REQUIRE(Success == ParseOpen(&parse_prm, lex_prm, gen_prm, false)); 468 | 469 | REQUIRE(Success == ParseProc(parse_prm)); 470 | REQUIRE(MockGetReturnValue() == 11); 471 | 472 | ParseClose(parse_prm); 473 | ParseDestroy(); 474 | 475 | REQUIRE(Success == GenClose(gen_prm)); 476 | REQUIRE(Success == GenDestroy()); 477 | 478 | REQUIRE(Success == LexClose(lex_prm)); 479 | REQUIRE(Success == LexDestroy()); 480 | } 481 | -------------------------------------------------------------------------------- /test/lex/Makefile: -------------------------------------------------------------------------------- 1 | CPP = g++ -std=c++11 2 | CC = gcc 3 | LD = g++ -std=c++11 4 | LDFLAGS += 5 | CPPFLAGS := -g -O0 -fpermissive -Wnarrowing -Wno-write-strings 6 | 7 | TARGET = lex_test 8 | TOP_SRC = ../.. 9 | TOP_TEST = ../../test 10 | 11 | 12 | INC := -I$(TOP_SRC)/inc 13 | INC += -I$(TOP_SRC)/src 14 | INC += -I$(TOP_TEST)/inc 15 | 16 | SRC_CPP := lex_test.cpp 17 | SRC_CPP += main.cpp 18 | SRC := $(TOP_SRC)/src/lex.c 19 | SRC += $(TOP_SRC)/src/log.c 20 | 21 | CFLAGS += $(INC) 22 | 23 | # generate dependence file 24 | OBJDIR = . 25 | OBJ += $(SRC:%.c=$(OBJDIR)/%.o) 26 | OBJ_CPP += $(SRC_CPP:%.cpp=$(OBJDIR)/%.o) 27 | 28 | # Add target to build library 29 | all:TARGET 30 | 31 | TARGET:$(TARGET) 32 | 33 | $(TARGET):$(OBJ) $(OBJ_CPP) 34 | $(LD) $(LDFLAGS) -o $@ $(OBJ) $(OBJ_CPP) $(LIBS) 35 | 36 | $(OBJDIR)/%.o : %.c 37 | $(CC) $(CFLAGS) -c $< -o $@ 38 | 39 | $(OBJDIR)/%.o : %.cpp 40 | $(CPP) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 41 | 42 | clean: 43 | -rm $(OBJ) $(OBJ_CPP) 44 | -rm $(TARGET) 45 | 46 | .PHONY:clean all TARGET 47 | 48 | -include $(shell mkdir $(OBJDIR) 2>/dev/null) $(wildcard $(OBJDIR)/*.d) 49 | -------------------------------------------------------------------------------- /test/lex/lex_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018/12 truong 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include "lex.h" 14 | #include "log.h" 15 | #include "error_code.h" 16 | 17 | #include "common.h" 18 | #include "catch.hh" 19 | 20 | using namespace std; 21 | 22 | TEST_CASE("lex test get single resource") 23 | { 24 | create_folder("data"); 25 | std::ofstream outfile ("data/xyz"); 26 | outfile << "1" << std::endl; 27 | outfile.close(); 28 | 29 | void* prm = NULL; 30 | REQUIRE(Success == LexCreate()); 31 | 32 | REQUIRE(InParameterInvalid == LexOpen(&prm, NULL)); 33 | 34 | REQUIRE(Success == LexOpen(&prm, (char*)"data/xyz")); 35 | 36 | REQUIRE(InParameterInvalid == LexOpen(&prm, (char*)"data/xyz")); 37 | 38 | REQUIRE(Success == LexClose(prm)); 39 | REQUIRE(Success == LexDestroy()); 40 | } 41 | 42 | TEST_CASE("lex test get multi resource") 43 | { 44 | int max_rsc = 10; 45 | vector prm = vector(10,NULL); 46 | REQUIRE(Success == LexCreate()); 47 | for (int i = 0; i < max_rsc; i++) { 48 | std::ofstream outfile ("data/xyz"+ to_string(i)); 49 | outfile.close(); 50 | 51 | REQUIRE(Success == LexOpen(&prm[i], ("data/xyz"+ to_string(i)).c_str() )); 52 | REQUIRE(NULL != prm[i]); 53 | } 54 | 55 | { 56 | std::ofstream outfile ("data/xyzk"); 57 | outfile.close(); 58 | REQUIRE(InParameterInvalid == LexOpen(&prm[0], (char*)"data/xyzk")); 59 | } 60 | 61 | { 62 | void* a_prm = NULL; 63 | std::ofstream outfile ("data/xyzf"); 64 | outfile.close(); 65 | REQUIRE(LexLimitResource == LexOpen(&a_prm, (char*)"data/xyzf")); 66 | REQUIRE(NULL == a_prm); 67 | } 68 | 69 | for (auto& p : prm) { 70 | REQUIRE(Success == LexClose(p)); 71 | } 72 | 73 | REQUIRE(Success == LexDestroy()); 74 | } 75 | 76 | TEST_CASE("lex test operator token") 77 | { 78 | std::ofstream outfile ("data/test1"); 79 | outfile << "-+*/()" << std::endl; 80 | outfile.close(); 81 | vector expect = vector{ 82 | {TokenMinus ,-1}, 83 | {TokenPlus ,-1}, 84 | {TokenMul ,-1}, 85 | {TokenDiv ,-1}, 86 | {TokenLP ,-1}, 87 | {TokenRP ,-1}, 88 | {TokenEoi ,-1} 89 | }; 90 | 91 | void* prm = NULL; 92 | REQUIRE(Success == LexCreate()); 93 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test1")); 94 | 95 | Token T; 96 | int i = 0; 97 | while(Success == LexProc(prm, &T)) { 98 | Token t = expect[i]; 99 | REQUIRE(T.tok == t.tok); 100 | i++; 101 | if (TokenEoi == T.tok) { 102 | break; 103 | } 104 | } 105 | 106 | REQUIRE(i == expect.size()); 107 | REQUIRE(Success == LexClose(prm)); 108 | REQUIRE(Success == LexDestroy()); 109 | } 110 | 111 | TEST_CASE("lex test numeric token") 112 | { 113 | std::ofstream outfile ("data/test2"); 114 | outfile << "1 2 3 4" << std::endl; 115 | outfile.close(); 116 | vector expect = vector{ 117 | {TokenNumber ,1}, 118 | {TokenNumber ,2}, 119 | {TokenNumber ,3}, 120 | {TokenNumber ,4}, 121 | {TokenEoi ,-1} 122 | }; 123 | 124 | void* prm = NULL; 125 | REQUIRE(Success == LexCreate()); 126 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test2")); 127 | 128 | Token T; 129 | int i = 0; 130 | while(Success == LexProc(prm, &T)) { 131 | Token t = expect[i]; 132 | REQUIRE(T.tok == t.tok); 133 | if (TokenNumber == t.tok) { 134 | REQUIRE(T.value == t.value); 135 | } 136 | 137 | i++; 138 | if (TokenEoi == T.tok) { 139 | break; 140 | } 141 | } 142 | 143 | REQUIRE(i == expect.size()); 144 | REQUIRE(Success == LexClose(prm)); 145 | REQUIRE(Success == LexDestroy()); 146 | } 147 | 148 | TEST_CASE("lex test arithmetic expression") 149 | { 150 | std::ofstream outfile ("data/test4"); 151 | outfile << "1 + 2 * 3 * 4" << std::endl; 152 | outfile.close(); 153 | vector expect = vector{ 154 | {TokenNumber ,1}, 155 | {TokenPlus ,-1}, 156 | {TokenNumber ,2}, 157 | {TokenMul ,-1}, 158 | {TokenNumber ,3}, 159 | {TokenMul ,-1}, 160 | {TokenNumber ,4}, 161 | {TokenEoi ,-1} 162 | }; 163 | 164 | void* prm = NULL; 165 | REQUIRE(Success == LexCreate()); 166 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test4")); 167 | 168 | Token T; 169 | int i = 0; 170 | while(Success == LexProc(prm, &T)) { 171 | Token t = expect[i]; 172 | REQUIRE(T.tok == t.tok); 173 | if (TokenNumber == t.tok) { 174 | REQUIRE(T.value == t.value); 175 | } 176 | i++; 177 | if (TokenEoi == T.tok) { 178 | break; 179 | } 180 | } 181 | 182 | REQUIRE(i == expect.size()); 183 | REQUIRE(Success == LexClose(prm)); 184 | REQUIRE(Success == LexDestroy()); 185 | } 186 | 187 | TEST_CASE("lex test arithmetic expression with special character") 188 | { 189 | std::ofstream outfile ("data/test5"); 190 | outfile << "1 " << std::endl; 191 | outfile << " +" << std::endl; 192 | outfile << "2 " << std::endl; 193 | outfile << "* " << std::endl; 194 | outfile << "3 " << std::endl; 195 | outfile << " *" << std::endl; 196 | outfile << " 4" << std::endl; 197 | outfile << " /" << std::endl; 198 | outfile << " 5" << std::endl; 199 | outfile.close(); 200 | vector expect = vector{ 201 | {TokenNumber ,1}, 202 | {TokenPlus ,-1}, 203 | {TokenNumber ,2}, 204 | {TokenMul ,-1}, 205 | {TokenNumber ,3}, 206 | {TokenMul ,-1}, 207 | {TokenNumber ,4}, 208 | {TokenDiv ,-1}, 209 | {TokenNumber ,5}, 210 | {TokenEoi ,-1} 211 | }; 212 | 213 | void* prm = NULL; 214 | REQUIRE(Success == LexCreate()); 215 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test5")); 216 | 217 | Token T; 218 | int i = 0; 219 | while(Success == LexProc(prm, &T)) { 220 | Token t = expect[i]; 221 | REQUIRE(T.tok == t.tok); 222 | if (TokenNumber == t.tok) { 223 | REQUIRE(T.value == t.value); 224 | } 225 | i++; 226 | if (TokenEoi == T.tok) { 227 | break; 228 | } 229 | } 230 | 231 | REQUIRE(i == expect.size()); 232 | REQUIRE(Success == LexClose(prm)); 233 | REQUIRE(Success == LexDestroy()); 234 | } 235 | 236 | 237 | TEST_CASE("lex test token: int type, L&R bracket, return") 238 | { 239 | std::ofstream outfile ("data/test6"); 240 | outfile << "int" << std::endl; 241 | outfile << "void" << std::endl; 242 | outfile << "{}" << std::endl; 243 | outfile << "return" << std::endl; 244 | outfile.close(); 245 | vector expect = vector{ 246 | {TokenIntType ,-1}, 247 | {TokenVoidType ,-1}, 248 | {TokenLBracket ,-1}, 249 | {TokenRBracket ,-1}, 250 | {TokenReturn ,-1}, 251 | {TokenEoi ,-1} 252 | }; 253 | 254 | void* prm = NULL; 255 | REQUIRE(Success == LexCreate()); 256 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test6")); 257 | 258 | Token T; 259 | int i = 0; 260 | while(Success == LexProc(prm, &T)) { 261 | Token t = expect[i]; 262 | REQUIRE(T.tok == t.tok); 263 | i++; 264 | if (TokenEoi == T.tok) { 265 | break; 266 | } 267 | } 268 | 269 | REQUIRE(i == expect.size()); 270 | REQUIRE(Success == LexClose(prm)); 271 | REQUIRE(Success == LexDestroy()); 272 | } 273 | 274 | TEST_CASE("lex test token: int type, assign, identifier") 275 | { 276 | std::ofstream outfile ("data/test7"); 277 | outfile << "int cnt1234 = 10;" << std::endl; 278 | 279 | outfile.close(); 280 | vector expect = vector{ 281 | {TokenIntType ,-1}, 282 | {TokenIdentifier ,-1}, 283 | {TokenAssign ,-1}, 284 | {TokenNumber ,10}, 285 | {TokenSemi ,-1}, 286 | {TokenEoi ,-1} 287 | }; 288 | 289 | memcpy(expect[1].id_str,"cnt1234", strlen("cnt1234")); 290 | 291 | void* prm = NULL; 292 | REQUIRE(Success == LexCreate()); 293 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test7")); 294 | 295 | Token T; 296 | int i = 0; 297 | while(Success == LexProc(prm, &T)) { 298 | Token t = expect[i]; 299 | REQUIRE(T.tok == t.tok); 300 | i++; 301 | if (TokenNumber == T.tok) { 302 | REQUIRE(T.value == t.value); 303 | } else if (TokenIdentifier == T.tok) { 304 | REQUIRE(0 == strncmp(T.id_str, t.id_str, strlen(t.id_str))); 305 | } else if (TokenEoi == T.tok) { 306 | break; 307 | } 308 | } 309 | 310 | REQUIRE(i == expect.size()); 311 | REQUIRE(Success == LexClose(prm)); 312 | REQUIRE(Success == LexDestroy()); 313 | } 314 | 315 | 316 | TEST_CASE("lex test bool operator: == <= >= !=") 317 | { 318 | std::ofstream outfile ("data/test8"); 319 | outfile << "1 == 2;" << std::endl; 320 | outfile << "1 >= 2;" << std::endl; 321 | outfile << "1 <= 2;" << std::endl; 322 | outfile << "1 != 2;" << std::endl; 323 | outfile << "1 > 2;" << std::endl; 324 | outfile << "1 < 2;" << std::endl; 325 | outfile.close(); 326 | vector expect = vector{ 327 | {TokenNumber ,1}, 328 | {TokenEQ , -1}, 329 | {TokenNumber ,2}, 330 | {TokenSemi , -1}, 331 | {TokenNumber ,1}, 332 | {TokenGE ,-1}, 333 | {TokenNumber ,2}, 334 | {TokenSemi , -1}, 335 | {TokenNumber ,1}, 336 | {TokenLE ,-1}, 337 | {TokenNumber ,2}, 338 | {TokenSemi , -1}, 339 | {TokenNumber ,1}, 340 | {TokenNE ,-1}, 341 | {TokenNumber ,2}, 342 | {TokenSemi , -1}, 343 | {TokenNumber ,1}, 344 | {TokenGT ,-1}, 345 | {TokenNumber ,2}, 346 | {TokenSemi , -1}, 347 | {TokenNumber ,1}, 348 | {TokenLT ,-1}, 349 | {TokenNumber ,2}, 350 | {TokenSemi ,-1}, 351 | {TokenEoi ,-1} 352 | }; 353 | 354 | void* prm = NULL; 355 | REQUIRE(Success == LexCreate()); 356 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test8")); 357 | 358 | Token T; 359 | int i = 0; 360 | while(Success == LexProc(prm, &T)) { 361 | Token t = expect[i]; 362 | if (T.tok != t.tok) { 363 | mlog(ERROR,"%s == %s\n",tok2str(T.tok), tok2str(t.tok)); 364 | mlog(ERROR, "error index %d\n",i); 365 | REQUIRE(T.tok == t.tok); 366 | } 367 | if (TokenNumber == t.tok) { 368 | REQUIRE(T.value == t.value); 369 | } 370 | i++; 371 | if (TokenEoi == T.tok) { 372 | break; 373 | } 374 | } 375 | 376 | REQUIRE(i == expect.size()); 377 | REQUIRE(Success == LexClose(prm)); 378 | REQUIRE(Success == LexDestroy()); 379 | } 380 | 381 | TEST_CASE("lex test if-then- operator: == <= >= !=") 382 | { 383 | std::ofstream outfile ("data/test9"); 384 | outfile << "if (1 == 2)"<< std::endl; 385 | outfile << "{1; }"<< std::endl; 386 | outfile << "else "<< std::endl; 387 | outfile << "{2; }" << std::endl; 388 | outfile.close(); 389 | vector expect = vector{ 390 | {TokenIf, -1}, 391 | {TokenLP, -1}, 392 | {TokenNumber, 1}, 393 | {TokenEQ, -1}, 394 | {TokenNumber, 2}, 395 | {TokenRP, -1}, 396 | {TokenLBracket,-1}, 397 | {TokenNumber, 1}, 398 | {TokenSemi, -1}, 399 | {TokenRBracket,-1}, 400 | {TokenElse, -1}, 401 | {TokenLBracket,-1}, 402 | {TokenNumber, 2}, 403 | {TokenSemi, -1}, 404 | {TokenRBracket,-1}, 405 | {TokenEoi ,-1} 406 | }; 407 | 408 | void* prm = NULL; 409 | REQUIRE(Success == LexCreate()); 410 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test9")); 411 | 412 | Token T; 413 | int i = 0; 414 | while(Success == LexProc(prm, &T)) { 415 | Token t = expect[i]; 416 | if (T.tok != t.tok) { 417 | mlog(ERROR,"%s == %s\n",tok2str(T.tok), tok2str(t.tok)); 418 | mlog(ERROR, "error index %d\n",i); 419 | REQUIRE(T.tok == t.tok); 420 | } 421 | if (TokenNumber == t.tok) { 422 | REQUIRE(T.value == t.value); 423 | } 424 | i++; 425 | if (TokenEoi == T.tok) { 426 | break; 427 | } 428 | } 429 | 430 | REQUIRE(i == expect.size()); 431 | REQUIRE(Success == LexClose(prm)); 432 | REQUIRE(Success == LexDestroy()); 433 | } 434 | 435 | TEST_CASE("lex test operator: == <= >= !=") 436 | { 437 | std::ofstream outfile ("data/test10"); 438 | outfile << "& && | || ^"<< std::endl; 439 | outfile.close(); 440 | vector expect = vector{ 441 | {TokenBitAnd,-1}, 442 | {TokenAnd, -1}, 443 | {TokenBitOr, -1}, 444 | {TokenOr, 2}, 445 | {TokenBitXor,-1}, 446 | {TokenEoi ,-1} 447 | }; 448 | 449 | void* prm = NULL; 450 | REQUIRE(Success == LexCreate()); 451 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test10")); 452 | 453 | Token T; 454 | int i = 0; 455 | while(Success == LexProc(prm, &T)) { 456 | Token t = expect[i]; 457 | if (T.tok != t.tok) { 458 | mlog(ERROR,"%s == %s\n",tok2str(T.tok), tok2str(t.tok)); 459 | mlog(ERROR, "error index %d\n",i); 460 | REQUIRE(T.tok == t.tok); 461 | } 462 | if (TokenNumber == t.tok) { 463 | REQUIRE(T.value == t.value); 464 | } 465 | i++; 466 | if (TokenEoi == T.tok) { 467 | break; 468 | } 469 | } 470 | 471 | REQUIRE(i == expect.size()); 472 | REQUIRE(Success == LexClose(prm)); 473 | REQUIRE(Success == LexDestroy()); 474 | } 475 | 476 | TEST_CASE("lex test string") 477 | { 478 | std::ofstream outfile ("data/test11"); 479 | outfile << " \"conchocon\" " << std::endl; 480 | outfile.close(); 481 | 482 | vector expect = vector{ 483 | {TokenString ,-1}, 484 | {TokenEoi ,-1} 485 | }; 486 | 487 | memcpy(expect[0].str,"conchocon", strlen("conchocon")); 488 | 489 | void* prm = NULL; 490 | REQUIRE(Success == LexCreate()); 491 | REQUIRE(Success == LexOpen(&prm, (char*)"data/test11")); 492 | 493 | Token T; 494 | int i = 0; 495 | while(Success == LexProc(prm, &T)) { 496 | Token t = expect[i]; 497 | REQUIRE(T.tok == t.tok); 498 | i++; 499 | if (TokenNumber == T.tok) { 500 | REQUIRE(T.value == t.value); 501 | } else if (TokenString == T.tok) { 502 | REQUIRE(0 == strncmp(T.str, t.str, strlen(t.str))); 503 | } else if (TokenEoi == T.tok) { 504 | break; 505 | } 506 | } 507 | 508 | REQUIRE(i == expect.size()); 509 | REQUIRE(Success == LexClose(prm)); 510 | REQUIRE(Success == LexDestroy()); 511 | } 512 | -------------------------------------------------------------------------------- /test/lex/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define CATCH_CONFIG_MAIN 3 | 4 | #include "catch.hh" 5 | -------------------------------------------------------------------------------- /test/parse/Makefile: -------------------------------------------------------------------------------- 1 | CPP = g++ -std=c++11 2 | CC = gcc 3 | LD = g++ -std=c++11 4 | LDFLAGS += 5 | CPPFLAGS := -g -O0 -fpermissive -Wnarrowing -Wno-write-strings 6 | 7 | #-fpermissive -Wnarrowing 8 | 9 | TARGET = parse_test 10 | TOP_SRC = ../.. 11 | TOP_TEST = ../../test 12 | 13 | 14 | INC := -I$(TOP_SRC)/inc 15 | INC += -I$(TOP_SRC)/src 16 | INC += -I$(TOP_TEST)/inc 17 | 18 | SRC_CPP := parse_test.cpp 19 | SRC_CPP += symtable_test.cpp 20 | SRC_CPP += mock_lex.cpp 21 | SRC_CPP += mock_arch.cpp 22 | SRC_CPP += main.cpp 23 | SRC := $(TOP_SRC)/src/parse.c 24 | SRC += $(TOP_SRC)/src/gen.c 25 | SRC += $(TOP_SRC)/src/ast.c 26 | SRC += $(TOP_SRC)/src/symtable.c 27 | SRC += $(TOP_SRC)/src/log.c 28 | 29 | CFLAGS += $(INC) 30 | 31 | # generate dependence file 32 | OBJDIR = . 33 | OBJ += $(SRC:%.c=$(OBJDIR)/%.o) 34 | OBJ_CPP += $(SRC_CPP:%.cpp=$(OBJDIR)/%.o) 35 | 36 | # Add target to build library 37 | all:TARGET 38 | 39 | TARGET:$(TARGET) 40 | 41 | $(TARGET):$(OBJ) $(OBJ_CPP) 42 | $(LD) $(LDFLAGS) -o $@ $(OBJ) $(OBJ_CPP) $(LIBS) 43 | 44 | $(OBJDIR)/%.o : %.c 45 | $(CC) $(CFLAGS) -c $< -o $@ 46 | 47 | $(OBJDIR)/%.o : %.cpp 48 | $(CPP) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 49 | 50 | clean: 51 | -rm $(OBJ) $(OBJ_CPP) 52 | -rm $(TARGET) 53 | 54 | .PHONY:clean all TARGET 55 | 56 | -include $(shell mkdir $(OBJDIR) 2>/dev/null) $(wildcard $(OBJDIR)/*.d) 57 | -------------------------------------------------------------------------------- /test/parse/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #define CATCH_CONFIG_MAIN 7 | #include "catch.hh" 8 | -------------------------------------------------------------------------------- /test/parse/mock_arch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "error_code.h" 7 | #include "gen_internal.h" 8 | 9 | using namespace std; 10 | static char* mock_load(int32_t value, FILE* out_file); 11 | static char* mock_out(char* r, FILE* out_file); 12 | static char* mock_free(char* r, FILE* out_file); 13 | 14 | static char* mock_add(char* r1, char* r2, FILE* out_file); 15 | static char* mock_sub(char* r1, char* r2, FILE* out_file); 16 | static char* mock_mul(char* r1, char* r2, FILE* out_file); 17 | static char* mock_div(char* r1, char* r2, FILE* out_file); 18 | 19 | static char* mock_lt(char* r1, char* r2, FILE* out_file); 20 | static char* mock_le(char* r1, char* r2, FILE* out_file); 21 | static char* mock_gt(char* r1, char* r2, FILE* out_file); 22 | static char* mock_ge(char* r1, char* r2, FILE* out_file); 23 | static char* mock_eq(char* r1, char* r2, FILE* out_file); 24 | static char* mock_ne(char* r1, char* r2, FILE* out_file); 25 | 26 | static char* mock_or(char* r1, char* r2, FILE* out_file); 27 | static char* mock_and(char* r1, char* r2, FILE* out_file); 28 | static char* mock_b_or(char* r1, char* r2, FILE* out_file); 29 | static char* mock_b_xor(char* r1, char* r2, FILE* out_file); 30 | static char* mock_b_and(char* r1, char* r2, FILE* out_file); 31 | 32 | static char* mock_lt_j(char* r1, char* r2, char* l, FILE* out_file); 33 | static char* mock_le_j(char* r1, char* r2, char* l, FILE* out_file); 34 | static char* mock_gt_j(char* r1, char* r2, char* l, FILE* out_file); 35 | static char* mock_ge_j(char* r1, char* r2, char* l, FILE* out_file); 36 | static char* mock_eq_j(char* r1, char* r2, char* l, FILE* out_file); 37 | static char* mock_ne_j(char* r1, char* r2, char* l, FILE* out_file); 38 | static char* mock_jump(char* l, FILE* out_file); 39 | static char* mock_zero_j(char* r, char* l, FILE* out_file); 40 | static char* mock_label(char* l, FILE* out_file); 41 | static char* mock_func(char* name, int stack_size, FILE* out_file); 42 | static char* mock_func_exit(char* label, int stack_size, FILE* out_file); 43 | static char* mock_return(char* r, char* exit_label, FILE* out_file); 44 | 45 | static char* mock_var(char* var, FILE* out_file); 46 | static char* mock_local_var(char* var, int size, FILE* out_file); 47 | static char* mock_store(char* r, char* var, FILE* out_file); 48 | static char* mock_load_var(char* var, FILE* out_file); 49 | 50 | // register 51 | vector reg = {"r0","r1","r2","r3","r4"}; 52 | unordered_map g_variable; 53 | unordered_map mem; 54 | 55 | int cur = 0; 56 | vector return_value = {}; 57 | int p_index = 0; 58 | 59 | int32_t GenLoadX86_64(GenFuncTable *func) 60 | { 61 | func->f_load = &mock_load; 62 | func->f_out = &mock_out; 63 | func->f_free = &mock_free; 64 | func->f_var = &mock_var; 65 | func->f_l_var = &mock_local_var; 66 | func->f_add = &mock_add; 67 | func->f_sub = &mock_sub; 68 | func->f_mul = &mock_mul; 69 | func->f_div = &mock_div; 70 | func->f_lt = &mock_lt; 71 | func->f_le = &mock_le; 72 | func->f_gt = &mock_gt; 73 | func->f_ge = &mock_ge; 74 | func->f_eq = &mock_eq; 75 | func->f_ne = &mock_ne; 76 | 77 | func->f_or = &mock_or; 78 | func->f_and = &mock_and; 79 | func->f_b_or = &mock_b_or; 80 | func->f_b_xor = &mock_b_xor; 81 | func->f_b_and = &mock_b_and; 82 | 83 | func->f_lt_j = &mock_lt_j; 84 | func->f_le_j = &mock_le_j; 85 | func->f_gt_j = &mock_gt_j; 86 | func->f_ge_j = &mock_ge_j; 87 | func->f_eq_j = &mock_eq_j; 88 | func->f_ne_j = &mock_ne_j; 89 | func->f_jump = &mock_jump; 90 | func->f_zero_j = &mock_zero_j; 91 | func->f_label = &mock_label; 92 | func->f_func = &mock_func; 93 | func->f_func_exit = &mock_func_exit; 94 | func->f_return = &mock_return; 95 | 96 | func->f_store = &mock_store; 97 | func->f_load_var = &mock_load_var; 98 | 99 | for (auto r : reg) { 100 | mem[r] = 0; 101 | } 102 | cur = 0; 103 | p_index = 0; 104 | g_variable.clear(); 105 | return_value.clear(); 106 | 107 | return Success; 108 | } 109 | 110 | int32_t MockGetReturnValue() 111 | { 112 | if (p_index > return_value.size()) { 113 | cout << "Not having print out data" << endl; 114 | return -1; 115 | }; 116 | return return_value[p_index++]; 117 | } 118 | 119 | char* reg_alloc() { 120 | if (cur >= reg.size()) { 121 | cout << "Not have available register" << endl; 122 | return NULL; 123 | } 124 | return reg[cur++]; 125 | } 126 | 127 | void reg_free(char* r) { 128 | if (mem.find(r) == mem.end()) { 129 | // cout << "Free reg is not correct: " << r << endl; 130 | return; 131 | } 132 | reg[--cur] = r; 133 | } 134 | 135 | static char* mock_load(int32_t value, FILE* out_file) 136 | { 137 | char* r = reg_alloc(); 138 | if (NULL == r) { 139 | return NULL; 140 | } 141 | mem[r] = value; 142 | fprintf(out_file,"[LOAD]:\t %s = %d\n", r, value); 143 | return r; 144 | } 145 | 146 | static char* mock_out(char* r, FILE* out_file) 147 | { 148 | reg_free(r); 149 | return r; 150 | } 151 | 152 | static char* mock_free(char* r, FILE* out_file) 153 | { 154 | reg_free(r); 155 | return NULL; 156 | } 157 | 158 | static char* mock_add(char* r1, char* r2, FILE* out_file) 159 | { 160 | mem[r1] += mem[r2]; 161 | mem[r2] = 0; 162 | reg_free(r2); 163 | fprintf(out_file,"[ADD ]:\t %s = %s+%s\n",r1,r1,r2); 164 | return r1; 165 | } 166 | 167 | static char* mock_sub(char* r1, char* r2, FILE* out_file) 168 | { 169 | mem[r1] -= mem[r2]; 170 | mem[r2] = 0; 171 | reg_free(r2); 172 | fprintf(out_file,"[SUB ]:\t %s = %s-%s\n",r1,r1,r2); 173 | return r1; 174 | } 175 | 176 | static char* mock_mul(char* r1, char* r2, FILE* out_file) 177 | { 178 | mem[r1] *= mem[r2]; 179 | mem[r2] = 0; 180 | reg_free(r2); 181 | fprintf(out_file,"[MUL ]:\t %s = %s*%s\n",r1,r1,r2); 182 | return r1; 183 | } 184 | 185 | static char* mock_div(char* r1, char* r2, FILE* out_file) 186 | { 187 | mem[r1] /= mem[r2]; 188 | mem[r2] = 0; 189 | reg_free(r2); 190 | fprintf(out_file,"[DIV ]:\t %s = %s/%s\n",r1,r1,r2); 191 | return r1; 192 | } 193 | 194 | static char* mock_lt(char* r1, char* r2, FILE* out_file) 195 | { 196 | mem[r1] = (mem[r1] < mem[r2]); 197 | mem[r2] = 0; 198 | reg_free(r2); 199 | fprintf(out_file,"[LT ]:\t %s = %s < %s\n",r1,r1,r2); 200 | return r1; 201 | } 202 | 203 | static char* mock_le(char* r1, char* r2, FILE* out_file) 204 | { 205 | mem[r1] = (mem[r1] <= mem[r2]); 206 | mem[r2] = 0; 207 | reg_free(r2); 208 | fprintf(out_file,"[LE ]:\t %s = %s <= %s\n",r1,r1,r2); 209 | return r1; 210 | } 211 | 212 | static char* mock_gt(char* r1, char* r2, FILE* out_file) 213 | { 214 | mem[r1] = (mem[r1] > mem[r2]); 215 | mem[r2] = 0; 216 | reg_free(r2); 217 | fprintf(out_file,"[GT ]:\t %s = %s > %s\n",r1,r1,r2); 218 | return r1; 219 | } 220 | 221 | static char* mock_ge(char* r1, char* r2, FILE* out_file) 222 | { 223 | mem[r1] = (mem[r1] <= mem[r2]); 224 | mem[r2] = 0; 225 | reg_free(r2); 226 | fprintf(out_file,"[GE ]:\t %s = %s >= %s\n",r1,r1,r2); 227 | return r1; 228 | } 229 | 230 | static char* mock_eq(char* r1, char* r2, FILE* out_file) 231 | { 232 | mem[r1] = (mem[r1] == mem[r2]); 233 | mem[r2] = 0; 234 | reg_free(r2); 235 | fprintf(out_file,"[EQUA]:\t %s = %s == %s\n",r1,r1,r2); 236 | return r1; 237 | } 238 | 239 | static char* mock_ne(char* r1, char* r2, FILE* out_file) 240 | { 241 | mem[r1] = (mem[r1] != mem[r2]); 242 | mem[r2] = 0; 243 | reg_free(r2); 244 | fprintf(out_file,"[NE ]:\t %s = %s != %s\n",r1,r1,r2); 245 | return r1; 246 | } 247 | 248 | static char* mock_or(char* r1, char* r2, FILE* out_file) 249 | { 250 | mem[r1] = mem[r1] || mem[r2]; 251 | mem[r2] = 0; 252 | reg_free(r2); 253 | fprintf(out_file,"[OR ]:\t %s = %s || %s\n",r1,r1,r2); 254 | return r1; 255 | } 256 | 257 | static char* mock_and(char* r1, char* r2, FILE* out_file) 258 | { 259 | mem[r1] = mem[r1] && mem[r2]; 260 | mem[r2] = 0; 261 | reg_free(r2); 262 | fprintf(out_file,"[AND ]:\t %s = %s && %s\n",r1,r1,r2); 263 | return r1; 264 | } 265 | 266 | static char* mock_b_or(char* r1, char* r2, FILE* out_file) 267 | { 268 | mem[r1] = mem[r1] | mem[r2]; 269 | mem[r2] = 0; 270 | reg_free(r2); 271 | fprintf(out_file,"[BOR ]:\t %s = %s | %s\n",r1,r1,r2); 272 | return r1; 273 | } 274 | 275 | static char* mock_b_xor(char* r1, char* r2, FILE* out_file) 276 | { 277 | mem[r1] = mem[r1] ^ mem[r2]; 278 | mem[r2] = 0; 279 | reg_free(r2); 280 | fprintf(out_file,"[BXOR]:\t %s = %s ^ %s\n",r1,r1,r2); 281 | return r1; 282 | } 283 | 284 | static char* mock_b_and(char* r1, char* r2, FILE* out_file) 285 | { 286 | mem[r1] = mem[r1] & mem[r2]; 287 | mem[r2] = 0; 288 | reg_free(r2); 289 | fprintf(out_file,"[BAND]:\t %s = %s & %s\n",r1,r1,r2); 290 | return r1; 291 | } 292 | 293 | static char* mock_lt_j(char* r1, char* r2, char* l, FILE* out_file) 294 | { 295 | // TODO : add mock processing 296 | reg_free(r1); 297 | reg_free(r2); 298 | fprintf(out_file,"[JUMP]:\t %s if %s < %s\n",l,r1,r2); 299 | return l; 300 | } 301 | 302 | static char* mock_le_j(char* r1, char* r2, char* l, FILE* out_file) 303 | { 304 | // TODO : add mock processing 305 | reg_free(r1); 306 | reg_free(r2); 307 | fprintf(out_file,"[JUMP]:\t %s if %s <= %s\n",l,r1,r2); 308 | return l; 309 | } 310 | 311 | static char* mock_gt_j(char* r1, char* r2, char* l, FILE* out_file) 312 | { 313 | reg_free(r1); 314 | reg_free(r2); 315 | fprintf(out_file,"[JUMP]:\t %s if %s > %s\n",l,r1,r2); 316 | return l; 317 | } 318 | 319 | static char* mock_ge_j(char* r1, char* r2, char* l, FILE* out_file) 320 | { 321 | reg_free(r1); 322 | reg_free(r2); 323 | fprintf(out_file,"[JUMP]:\t %s if %s >= %s\n",l,r1,r2); 324 | return l; 325 | } 326 | 327 | static char* mock_eq_j(char* r1, char* r2, char* l, FILE* out_file) 328 | { 329 | reg_free(r1); 330 | reg_free(r2); 331 | fprintf(out_file,"[JUMP]:\t %s if %s == %s\n",l,r1,r2); 332 | return l; 333 | } 334 | 335 | static char* mock_ne_j(char* r1, char* r2, char* l, FILE* out_file) 336 | { 337 | reg_free(r1); 338 | reg_free(r2); 339 | fprintf(out_file,"[JUMP]:\t %s if %s != %s\n",l,r1,r2); 340 | return l; 341 | } 342 | 343 | static char* mock_jump(char* l, FILE* out_file) 344 | { 345 | fprintf(out_file,"[JUMP]:\t %s\n",l); 346 | return l; 347 | } 348 | 349 | static char* mock_zero_j(char* r, char* l, FILE* out_file) 350 | { 351 | fprintf(out_file,"[JPZR]:\t %s if %s == 0\n",l,r); 352 | } 353 | 354 | static char* mock_label(char* l, FILE* out_file) 355 | { 356 | fprintf(out_file,"[LBEL]:\t %s: <- label\n",l); 357 | return l; 358 | } 359 | 360 | static char* mock_func(char* name, int stack_size, FILE* out_file) 361 | { 362 | (void)stack_size; 363 | fprintf(out_file,"[FUNC]:\t %s:\n",name); 364 | return name; 365 | } 366 | 367 | static char* mock_func_exit(char* label, int stack_size, FILE* out_file) 368 | { 369 | (void)stack_size; 370 | fprintf(out_file,"[EXIT]:\t %s:\n",label); 371 | return label; 372 | } 373 | 374 | static char* mock_return(char* r, char* exit_label, FILE* out_file) 375 | { 376 | return_value.push_back(mem[r]); 377 | reg_free(r); 378 | fprintf(out_file,"[RET ]:\t %s\n",r); 379 | fprintf(out_file,"[GOTO]:\t %s\n",exit_label); 380 | return exit_label; 381 | } 382 | static char* mock_var(char* var, FILE* out_file) 383 | { 384 | // just allocate buffer for var 385 | string s_var(var); 386 | g_variable[s_var] = 0; 387 | 388 | fprintf(out_file,"[DECL]:\t %s\n",var); 389 | return var; 390 | } 391 | 392 | static char* mock_local_var(char* var, int size, FILE* out_file) 393 | { 394 | string s_var(var); 395 | g_variable[s_var] = 0; 396 | fprintf(out_file,"[DECL]:\t %s\n",var); 397 | return var; 398 | } 399 | 400 | static char* mock_store(char* var, char* r, FILE* out_file) 401 | { 402 | string s_var(var); 403 | if (g_variable.find(s_var) == g_variable.end()) { 404 | fprintf(out_file,"[FUCK]:\t %s not found\n",var); 405 | return NULL; 406 | } 407 | g_variable[s_var] = mem[r]; 408 | reg_free(r); 409 | 410 | fprintf(out_file,"[STOR]:\t %s = %s(%d)\n",var,r,mem[r]); 411 | return var; 412 | } 413 | 414 | static char* mock_load_var(char* var, FILE* out_file) 415 | { 416 | string s_var(var); 417 | char* r = reg_alloc(); 418 | mem[r] = g_variable[s_var]; 419 | fprintf(out_file,"[LOAD]:\t %s = %s(%d)\n",r,var,g_variable[s_var]); 420 | return r; 421 | } 422 | 423 | -------------------------------------------------------------------------------- /test/parse/mock_lex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include "lex.h" 7 | #include "error_code.h" 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | vector g_tok_array; 13 | int32_t tok_idx = 0; 14 | 15 | int32_t MockLexCreate(vector tok_array) 16 | { 17 | g_tok_array = tok_array; 18 | //g_tok_array(tok_array.begin(), tok_array.end()); 19 | tok_idx = 0; 20 | return Success; 21 | } 22 | 23 | int32_t MockLexDestroy() 24 | { 25 | g_tok_array.clear(); 26 | tok_idx = 0; 27 | return Success; 28 | } 29 | 30 | int32_t LexCreate(void) 31 | { 32 | return Success; 33 | } 34 | int32_t LexDestroy(void) 35 | { 36 | return Success; 37 | 38 | } 39 | 40 | int32_t LexOpen(void** prm, const char* file) 41 | { 42 | *prm = malloc(1); 43 | return Success; 44 | } 45 | int32_t LexClose(void* prm) 46 | { 47 | free(prm); 48 | return Success; 49 | } 50 | 51 | int32_t LexProc(void* prm, Token *t) 52 | { 53 | if (tok_idx >= g_tok_array.size()) { 54 | return -1; 55 | } 56 | *t = g_tok_array[tok_idx++]; 57 | return Success; 58 | } 59 | 60 | int32_t LexGetLine(void* prm) 61 | { 62 | return Success; 63 | } 64 | -------------------------------------------------------------------------------- /test/parse/parse_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/07 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "lex.h" 12 | #include "gen.h" 13 | #include "parse.h" 14 | #include "error_code.h" 15 | 16 | #include "common.h" 17 | #include "catch.hh" 18 | 19 | using namespace std; 20 | int32_t MockLexCreate(vector tok_array); 21 | int32_t MockLexDestroy(); 22 | int32_t MockGetReturnValue(); 23 | 24 | TEST_CASE("parse test get single resource") 25 | { 26 | create_folder("data"); 27 | std::ofstream outfile ("data/testp0"); 28 | 29 | outfile << "0" << std::endl; 30 | 31 | outfile.close(); 32 | 33 | void* lex_prm = NULL; 34 | REQUIRE(Success == LexCreate()); 35 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/in0")); 36 | 37 | void* gen_prm = NULL; 38 | REQUIRE(Success == GenCreate()); 39 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out0")); 40 | 41 | void* prm = NULL; 42 | REQUIRE(Success == ParseCreate()); 43 | REQUIRE(Success == ParseOpen(&prm, lex_prm, gen_prm, false)); 44 | 45 | REQUIRE(Success == ParseClose(prm)); 46 | REQUIRE(Success == ParseDestroy()); 47 | 48 | REQUIRE(Success == LexClose(lex_prm)); 49 | REQUIRE(Success == LexDestroy()); 50 | 51 | REQUIRE(Success == GenClose(gen_prm)); 52 | REQUIRE(Success == GenDestroy()); 53 | } 54 | 55 | TEST_CASE("parse test get multi resource") 56 | { 57 | std::ofstream outfile ("data/testp1"); 58 | outfile << "0" << std::endl; 59 | outfile.close(); 60 | 61 | void* lex_prm = NULL; 62 | REQUIRE(Success == LexCreate()); 63 | REQUIRE(Success == LexOpen(&lex_prm, (char*)"data/in1")); 64 | 65 | void* gen_prm = NULL; 66 | REQUIRE(Success == GenCreate()); 67 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out1")); 68 | 69 | int max_rsc = 10; 70 | vector prm = vector(10,NULL); 71 | REQUIRE(Success == ParseCreate()); 72 | for (auto& p : prm) { 73 | REQUIRE(Success == ParseOpen(&p, lex_prm, gen_prm, false)); 74 | REQUIRE(NULL != p); 75 | } 76 | 77 | REQUIRE(InParameterInvalid == ParseOpen(&prm[0], lex_prm, gen_prm, false)); 78 | 79 | void* a_prm = NULL; 80 | REQUIRE(ParseLimitResource == ParseOpen(&a_prm, lex_prm, gen_prm, false)); 81 | REQUIRE(NULL == a_prm); 82 | 83 | for (auto& p : prm) { 84 | REQUIRE(Success == ParseClose(p)); 85 | } 86 | 87 | REQUIRE(Success == ParseDestroy()); 88 | 89 | REQUIRE(Success == LexClose(lex_prm)); 90 | REQUIRE(Success == LexDestroy()); 91 | 92 | REQUIRE(Success == GenClose(gen_prm)); 93 | REQUIRE(Success == GenDestroy()); 94 | } 95 | 96 | 97 | TEST_CASE("parse test plus token: (1+2);") 98 | { 99 | 100 | int32_t mock_lex_prm; 101 | 102 | vector token_test = { 103 | {TokenIntType, -1}, 104 | {TokenIdentifier, -1}, 105 | {TokenLP, -1}, 106 | {TokenRP, -1}, 107 | {TokenLBracket, -1}, 108 | {TokenReturn, -1}, 109 | {TokenLP, -1}, 110 | {TokenNumber, 1}, 111 | {TokenPlus, -1}, 112 | {TokenNumber, 2}, 113 | {TokenRP, -1}, 114 | {TokenSemi, -1}, 115 | {TokenRBracket, -1}, 116 | {TokenEoi, -1} 117 | }; 118 | 119 | memcpy(token_test[1].id_str,"main", strlen("main")); 120 | 121 | MockLexCreate(token_test); 122 | 123 | void* gen_prm = NULL; 124 | REQUIRE(Success == GenCreate()); 125 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out2")); 126 | 127 | void* parse_prm = NULL; 128 | REQUIRE(Success == ParseCreate()); 129 | REQUIRE(Success == ParseOpen(&parse_prm, (void*)&mock_lex_prm, gen_prm, false)); 130 | 131 | REQUIRE(Success == ParseProc(parse_prm)); 132 | REQUIRE(MockGetReturnValue() == (1+2)); 133 | 134 | ParseClose(parse_prm); 135 | ParseDestroy(); 136 | 137 | MockLexDestroy(); 138 | } 139 | 140 | TEST_CASE("parse test plus token: (2*3);") 141 | { 142 | 143 | int32_t mock_lex_prm; 144 | vector token_test = { 145 | {TokenIntType, -1}, 146 | {TokenIdentifier, -1}, 147 | {TokenLP, -1}, 148 | {TokenRP, -1}, 149 | {TokenLBracket, -1}, 150 | {TokenReturn, -1}, 151 | {TokenLP, -1}, 152 | {TokenNumber, 2}, 153 | {TokenMul, -1}, 154 | {TokenNumber, 3}, 155 | {TokenRP, -1}, 156 | {TokenSemi, -1}, 157 | {TokenRBracket, -1}, 158 | {TokenEoi, -1} 159 | }; 160 | 161 | memcpy(token_test[1].id_str,"main", strlen("main")); 162 | 163 | MockLexCreate(token_test); 164 | 165 | void* gen_prm = NULL; 166 | REQUIRE(Success == GenCreate()); 167 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out2")); 168 | 169 | void* parse_prm = NULL; 170 | REQUIRE(Success == ParseCreate()); 171 | REQUIRE(Success == ParseOpen(&parse_prm, (void*)&mock_lex_prm, gen_prm, false)); 172 | 173 | REQUIRE(Success == ParseProc(parse_prm)); 174 | 175 | REQUIRE(MockGetReturnValue() == (2*3)); 176 | 177 | ParseClose(parse_prm); 178 | ParseDestroy(); 179 | 180 | MockLexDestroy(); 181 | } 182 | 183 | TEST_CASE("parse test plus token: (1+2*3+4);") 184 | { 185 | 186 | int32_t mock_lex_prm; 187 | vector token_test = { 188 | {TokenIntType, -1}, 189 | {TokenIdentifier, -1}, 190 | {TokenLP, -1}, 191 | {TokenRP, -1}, 192 | {TokenLBracket, -1}, 193 | {TokenReturn, -1}, 194 | {TokenLP, -1}, 195 | {TokenNumber, 1}, 196 | {TokenPlus, -1}, 197 | {TokenNumber, 2}, 198 | {TokenMul, -1}, 199 | {TokenNumber, 3}, 200 | {TokenPlus, -1}, 201 | {TokenNumber, 4}, 202 | {TokenRP, -1}, 203 | {TokenSemi, -1}, 204 | {TokenRBracket, -1}, 205 | {TokenEoi, -1} 206 | }; 207 | 208 | memcpy(token_test[1].id_str,"main", strlen("main")); 209 | MockLexCreate(token_test); 210 | 211 | void* gen_prm = NULL; 212 | REQUIRE(Success == GenCreate()); 213 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out3")); 214 | 215 | void* parse_prm = NULL; 216 | REQUIRE(Success == ParseCreate()); 217 | REQUIRE(Success == ParseOpen(&parse_prm, (void*)&mock_lex_prm, gen_prm, false)); 218 | 219 | REQUIRE(Success == ParseProc(parse_prm)); 220 | 221 | REQUIRE(MockGetReturnValue() == (1+2*3+4)); 222 | 223 | ParseClose(parse_prm); 224 | ParseDestroy(); 225 | 226 | MockLexDestroy(); 227 | } 228 | 229 | TEST_CASE("parse test plus token: (1+2)*(3+4);") 230 | { 231 | 232 | int32_t mock_lex_prm; 233 | 234 | vector token_test = { 235 | {TokenIntType, -1}, 236 | {TokenIdentifier, -1}, 237 | {TokenLP, -1}, 238 | {TokenRP, -1}, 239 | {TokenLBracket, -1}, 240 | {TokenReturn, -1}, 241 | {TokenLP, -1}, 242 | {TokenNumber, 1}, 243 | {TokenPlus, -1}, 244 | {TokenNumber, 2}, 245 | {TokenRP, -1}, 246 | {TokenMul, -1}, 247 | {TokenLP, -1}, 248 | {TokenNumber, 3}, 249 | {TokenPlus, -1}, 250 | {TokenNumber, 4}, 251 | {TokenRP, -1}, 252 | {TokenSemi, -1}, 253 | {TokenRBracket, -1}, 254 | {TokenEoi, -1} 255 | }; 256 | 257 | memcpy(token_test[1].id_str,"main", strlen("main")); 258 | MockLexCreate(token_test); 259 | 260 | void* gen_prm = NULL; 261 | REQUIRE(Success == GenCreate()); 262 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out4")); 263 | 264 | void* parse_prm = NULL; 265 | REQUIRE(Success == ParseCreate()); 266 | REQUIRE(Success == ParseOpen(&parse_prm, (void*)&mock_lex_prm, gen_prm, false)); 267 | 268 | REQUIRE(Success == ParseProc(parse_prm)); 269 | REQUIRE(MockGetReturnValue() == ((1+2)*(3+4))); 270 | 271 | ParseClose(parse_prm); 272 | ParseDestroy(); 273 | 274 | MockLexDestroy(); 275 | } 276 | 277 | TEST_CASE("parse test pattern: int xyz;") 278 | { 279 | int32_t mock_lex_prm; 280 | 281 | vector token_test = { 282 | {TokenIntType, -1}, 283 | {TokenIdentifier, -1}, 284 | {TokenLP, -1}, 285 | {TokenRP, -1}, 286 | {TokenLBracket, -1}, 287 | {TokenIntType, -1}, 288 | {TokenIdentifier, -1}, 289 | {TokenSemi, -1}, 290 | {TokenRBracket, -1}, 291 | {TokenEoi, -1} 292 | }; 293 | 294 | memcpy(token_test[1].id_str,"main", strlen("main")); 295 | memcpy(token_test[6].id_str,"xyz", strlen("xyz")); 296 | 297 | MockLexCreate(token_test); 298 | 299 | void* gen_prm = NULL; 300 | REQUIRE(Success == GenCreate()); 301 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out5")); 302 | 303 | void* parse_prm = NULL; 304 | REQUIRE(Success == ParseCreate()); 305 | REQUIRE(Success == ParseOpen(&parse_prm, (void*)&mock_lex_prm, gen_prm, false)); 306 | 307 | REQUIRE(Success == ParseProc(parse_prm)); 308 | // TODO check result 309 | 310 | ParseClose(parse_prm); 311 | ParseDestroy(); 312 | 313 | MockLexDestroy(); 314 | } 315 | 316 | 317 | TEST_CASE("parse test return token: return (1+2);") 318 | { 319 | int32_t mock_lex_prm; 320 | vector token_test = { 321 | {TokenIntType, -1}, 322 | {TokenIdentifier, -1}, 323 | {TokenLP, -1}, 324 | {TokenRP, -1}, 325 | {TokenLBracket, -1}, 326 | {TokenReturn, -1}, 327 | {TokenLP, -1}, 328 | {TokenNumber, 1}, 329 | {TokenPlus, -1}, 330 | {TokenNumber, 2}, 331 | {TokenRP, -1}, 332 | {TokenSemi, -1}, 333 | {TokenRBracket, -1}, 334 | {TokenEoi, -1} 335 | }; 336 | 337 | memcpy(token_test[1].id_str,"main", strlen("main")); 338 | 339 | MockLexCreate(token_test); 340 | 341 | void* gen_prm = NULL; 342 | REQUIRE(Success == GenCreate()); 343 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out2")); 344 | 345 | void* parse_prm = NULL; 346 | REQUIRE(Success == ParseCreate()); 347 | REQUIRE(Success == ParseOpen(&parse_prm, (void*)&mock_lex_prm, gen_prm, false)); 348 | 349 | REQUIRE(Success == ParseProc(parse_prm)); 350 | // todo: consider method to confirm 351 | 352 | ParseClose(parse_prm); 353 | ParseDestroy(); 354 | 355 | MockLexDestroy(); 356 | } 357 | 358 | 359 | TEST_CASE("parse test pattern: int a; a = 10; return a;") 360 | { 361 | int32_t mock_lex_prm; 362 | 363 | vector token_test = { 364 | {TokenIntType, -1}, 365 | {TokenIdentifier, -1}, 366 | {TokenLP, -1}, 367 | {TokenRP, -1}, 368 | {TokenLBracket, -1}, 369 | {TokenIntType, -1}, 370 | {TokenIdentifier, -1}, 371 | {TokenSemi, -1}, 372 | {TokenIdentifier, -1}, 373 | {TokenAssign, -1}, 374 | {TokenNumber, 10}, 375 | {TokenSemi, -1}, 376 | {TokenReturn, -1}, 377 | {TokenIdentifier, -1}, 378 | {TokenSemi, -1}, 379 | {TokenRBracket, -1}, 380 | {TokenEoi, -1} 381 | }; 382 | 383 | memcpy(token_test[1].id_str,"main", strlen("main")); 384 | memcpy(token_test[6].id_str,"abc", strlen("abc")); 385 | memcpy(token_test[8].id_str,"abc", strlen("abc")); 386 | memcpy(token_test[13].id_str,"abc", strlen("abc")); 387 | MockLexCreate(token_test); 388 | void* gen_prm = NULL; 389 | REQUIRE(Success == GenCreate()); 390 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out6")); 391 | 392 | void* parse_prm = NULL; 393 | REQUIRE(Success == ParseCreate()); 394 | REQUIRE(Success == ParseOpen(&parse_prm, (void*)&mock_lex_prm, gen_prm, false)); 395 | 396 | REQUIRE(Success == ParseProc(parse_prm)); 397 | REQUIRE(MockGetReturnValue() == 10); 398 | 399 | ParseClose(parse_prm); 400 | ParseDestroy(); 401 | 402 | MockLexDestroy(); 403 | } 404 | 405 | TEST_CASE("parse test pattern: a+b;") 406 | { 407 | int32_t mock_lex_prm; 408 | vector token_test = { 409 | {TokenIntType, -1}, 410 | {TokenIdentifier,-1}, 411 | {TokenLP, -1}, 412 | {TokenRP, -1}, 413 | {TokenLBracket, -1}, 414 | {TokenIntType, -1}, 415 | {TokenIdentifier,-1}, //1 416 | {TokenSemi, -1}, // int a; 417 | {TokenIntType, -1}, 418 | {TokenIdentifier,-1}, //4 419 | {TokenSemi, -1}, // int b;/ 420 | {TokenIdentifier,-1}, //6: a = 1 421 | {TokenAssign, -1}, 422 | {TokenNumber, 1}, 423 | {TokenSemi, -1}, 424 | {TokenIdentifier,-1}, //10: b = 2 425 | {TokenAssign, -1}, 426 | {TokenNumber, 2}, 427 | {TokenSemi, -1}, 428 | {TokenReturn, -1}, // return a+b; 429 | {TokenIdentifier,-1}, //15 a 430 | {TokenPlus, -1}, 431 | {TokenIdentifier,-1}, // 17 b 432 | {TokenSemi, -1}, 433 | {TokenRBracket, -1}, 434 | {TokenEoi, -1} 435 | }; 436 | 437 | memcpy(token_test[1].id_str,"main", strlen("main")); 438 | 439 | memcpy(token_test[6].id_str,"a", strlen("a")); 440 | memcpy(token_test[9].id_str,"b", strlen("b")); 441 | memcpy(token_test[11].id_str,"a", strlen("a")); 442 | memcpy(token_test[15].id_str,"b", strlen("b")); 443 | memcpy(token_test[20].id_str,"a", strlen("a")); 444 | memcpy(token_test[22].id_str,"b", strlen("b")); 445 | 446 | MockLexCreate(token_test); 447 | void* gen_prm = NULL; 448 | REQUIRE(Success == GenCreate()); 449 | REQUIRE(Success == GenOpen(&gen_prm, GenX86_64, (char*)"data/out7")); 450 | 451 | void* parse_prm = NULL; 452 | REQUIRE(Success == ParseCreate()); 453 | REQUIRE(Success == ParseOpen(&parse_prm, (void*)&mock_lex_prm, gen_prm, false)); 454 | 455 | REQUIRE(Success == ParseProc(parse_prm)); 456 | REQUIRE(MockGetReturnValue() == (1+2)); 457 | 458 | ParseClose(parse_prm); 459 | ParseDestroy(); 460 | 461 | MockLexDestroy(); 462 | } 463 | -------------------------------------------------------------------------------- /test/parse/symtable_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020/08 gravieb 3 | * This file is released under the GPLv3 4 | */ 5 | #include "symtable.h" 6 | #include "error_code.h" 7 | 8 | #include "catch.hh" 9 | 10 | TEST_CASE("symtable add - find work") 11 | { 12 | SymbolTable st; 13 | char* s1 = "conchocon"; 14 | char* s2 = "conmeo"; 15 | char* s3 = "conchocanconmeoconmeoduoiconchuot"; 16 | REQUIRE(Success == symtable_init(&st)); 17 | REQUIRE(Success == symtable_add(&st, s1, 0)); 18 | REQUIRE(-1 != symtable_find(&st, s1, 0)); 19 | REQUIRE(-1 == symtable_find(&st, s2, 0)); 20 | REQUIRE(Success == symtable_add(&st, s2, 0)); 21 | REQUIRE(-1 != symtable_find(&st, s2, 0)); 22 | 23 | REQUIRE(-1 == symtable_find(&st, s3, 0)); 24 | REQUIRE(Success == symtable_add(&st, s3, 0)); 25 | REQUIRE(-1 != symtable_find(&st, s3, 0)); 26 | } 27 | 28 | TEST_CASE("symtable add - find valid work") 29 | { 30 | SymbolTable st; 31 | char* s1 = "a"; 32 | char* s2 = "b"; 33 | char* s3 = "c"; 34 | REQUIRE(Success == symtable_init(&st)); 35 | REQUIRE(Success == symtable_add(&st, s1, 0)); 36 | REQUIRE(Success == symtable_add(&st, s2, 1)); 37 | REQUIRE(Success == symtable_add(&st, s3, 2)); 38 | 39 | REQUIRE(-1 != symtable_find_valid(&st, s1, 100)); 40 | REQUIRE(-1 != symtable_find_valid(&st, s2, 100)); 41 | REQUIRE(-1 != symtable_find_valid(&st, s3, 100)); 42 | } 43 | --------------------------------------------------------------------------------