├── .gitignore ├── .idea ├── .gitignore ├── misc.xml ├── modules.xml └── vcs.xml ├── CMakeLists.txt ├── crystal ├── Lab1BatchTest.sh ├── Lab2BatchTest.sh ├── Lab3BatchTest.sh ├── testLab1 │ ├── SyntaxTest.cmm │ ├── extra10.cmm │ ├── extra5.cmm │ ├── extra6.cmm │ ├── extra7.cmm │ ├── extra8.cmm │ ├── extra9.cmm │ ├── output │ │ ├── extra10.cmm.pst │ │ ├── extra5.cmm.pst │ │ ├── extra6.cmm.pst │ │ ├── extra7.cmm.pst │ │ ├── extra8.cmm.pst │ │ ├── extra9.cmm.pst │ │ ├── test1.cmm.pst │ │ ├── test2.cmm.pst │ │ ├── test3.cmm.pst │ │ └── test4.cmm.pst │ ├── relopTest.cmm │ ├── test1.cmm │ ├── test2.cmm │ ├── test3.cmm │ └── test4.cmm ├── testLab2 │ ├── extra1.cmm │ ├── extra2.cmm │ ├── extra3.cmm │ ├── extra4.cmm │ ├── extra5.cmm │ ├── extra6.cmm │ ├── output │ │ ├── extra1.cmm.pst │ │ ├── extra18.cmm.pst │ │ ├── extra19.cmm.pst │ │ ├── extra2.cmm.pst │ │ ├── extra20.cmm.pst │ │ ├── extra21.cmm.pst │ │ ├── extra22.cmm.pst │ │ ├── extra23.cmm.pst │ │ ├── extra3.cmm.pst │ │ ├── extra4.cmm.pst │ │ ├── extra5.cmm.pst │ │ ├── extra6.cmm.pst │ │ ├── test1.cmm.pst │ │ ├── test10.cmm.pst │ │ ├── test11.cmm.pst │ │ ├── test12.cmm.pst │ │ ├── test13.cmm.pst │ │ ├── test14.cmm.pst │ │ ├── test15.cmm.pst │ │ ├── test16.cmm.pst │ │ ├── test17.cmm.pst │ │ ├── test2.cmm.pst │ │ ├── test3.cmm.pst │ │ ├── test4.cmm.pst │ │ ├── test5.cmm.pst │ │ ├── test6.cmm.pst │ │ ├── test7.cmm.pst │ │ ├── test8.cmm.pst │ │ └── test9.cmm.pst │ ├── test1.cmm │ ├── test10.cmm │ ├── test11.cmm │ ├── test12.cmm │ ├── test13.cmm │ ├── test14.cmm │ ├── test15.cmm │ ├── test16.cmm │ ├── test17.cmm │ ├── test2.cmm │ ├── test3.cmm │ ├── test4.cmm │ ├── test5.cmm │ ├── test6.cmm │ ├── test7.cmm │ ├── test8.cmm │ └── test9.cmm └── testLab3 │ ├── extra1.cmm │ ├── extra2.cmm │ ├── test1.cmm │ └── test2.cmm ├── include ├── CmmParser.tab.h ├── CmmParserTypes.h ├── CmmScanner.tab.h ├── ErrorReporter.h ├── InterCodeGenerator.h ├── Lab1.h ├── Lab2.h ├── Lab3.h ├── SemanticAnalyzer.h └── Structure │ ├── ParserNodes.h │ ├── SemanticInfo.h │ ├── SimpleArray.h │ ├── SimpleHashTable.h │ ├── SimpleList.h │ ├── SymbolTable.h │ └── TokenName.h ├── readme.md └── src ├── CmmLexer.l ├── CmmParser.y ├── ErrorReporter.c ├── InterCodeGenerator.c ├── Lab1.c ├── Lab2.c ├── Lab3.c ├── SemanticAnalyzer.c └── Structure ├── ParserNodes.c ├── SemanticInfo.c ├── SimpleArray.c ├── SimpleHashTable.c ├── SimpleList.c ├── SymbolTable.c └── TokenName.c /.gitignore: -------------------------------------------------------------------------------- 1 | /CmakeDebug/ 2 | /CmakeBuild/ 3 | /.idea 4 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | # 基于编辑器的 HTTP 客户端请求 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ~~~~~~Basic CMakeList Settings~~~~~~ 2 | cmake_minimum_required(VERSION 3.22) 3 | project(Lab1 C) 4 | 5 | set(CMAKE_C_STANDARD 11) 6 | 7 | # ~~~~~~Variables~~~~~~ 8 | set(RequiredMinimumVersion_Flex 2.5.35) 9 | set(RequiredMinimumVersion_Bison 2.5.0) 10 | set(Lab1Source src/Lab1.c) 11 | set(Lab2Source src/Lab2.c) 12 | set(Lab3Source src/Lab3.c) 13 | # ~~~~~~End of Variables~~~~~~ 14 | 15 | # Find Flex and Bison 16 | find_package(FLEX REQUIRED) 17 | 18 | if(NOT FLEX_FOUND) 19 | message(FATAL_ERROR "Flex is not found on your system.") 20 | elseif(${FLEX_VERSION} VERSION_LESS ${RequiredMinimumVersion_Flex}) 21 | message(FATAL_ERROR "Flex version is less than the required minimum version. Required: ${FLEX_VERSION}") 22 | endif() 23 | 24 | find_package(BISON REQUIRED) 25 | 26 | 27 | if(NOT BISON_FOUND) 28 | message(FATAL_ERROR "Bison is not found on your system.") 29 | elseif(${BISON_VERSION} VERSION_LESS ${RequiredMinimumVersion_Bison}) 30 | message(FATAL_ERROR "Bison version is less than the required minimum version. Required: ${BISON_VERSION}") 31 | endif() 32 | 33 | # Set output directories 34 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 35 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 36 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/crystal) 37 | 38 | # Collect source files 39 | aux_source_directory(src SRC) 40 | include_directories(include) 41 | 42 | # Generate lexer and parser 43 | flex_target(Lexer src/CmmLexer.l ${CMAKE_CURRENT_BINARY_DIR}/CmmScanner.c DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/include/CmmScanner.tab.h COMPILE_FLAGS "-d") 44 | bison_target(Parser src/CmmParser.y ${CMAKE_CURRENT_BINARY_DIR}/CmmParser.c DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/include/CmmParser.tab.h COMPILE_FLAGS "-d") 45 | add_flex_bison_dependency(Lexer Parser) 46 | 47 | # Add and Link lexer and parser 48 | add_library(Lexer STATIC ${FLEX_Lexer_OUTPUTS}) 49 | add_library(Parser STATIC ${BISON_Parser_OUTPUTS}) 50 | target_link_libraries(Lexer ${FLEX_LIBRARIES}) 51 | target_link_libraries(Parser ${BISON_LIBRARIES}) 52 | 53 | # Add Libs 54 | add_library(SimpleContainers STATIC src/Structure/SimpleArray.c src/Structure/SimpleHashTable.c src/Structure/SimpleList.c) 55 | add_library(ErrorReporter STATIC src/ErrorReporter.c) 56 | target_link_libraries(ErrorReporter SimpleContainers) 57 | 58 | add_library(ParserAnalyzer STATIC src/Structure/ParserNodes.c src/Structure/TokenName.c) 59 | target_link_libraries(ParserAnalyzer Parser Lexer ErrorReporter) 60 | 61 | add_library(SemanticAnalyzer STATIC src/Structure/SymbolTable.c src/Structure/SemanticInfo.c src/SemanticAnalyzer.c) 62 | target_link_libraries(SemanticAnalyzer ParserAnalyzer ErrorReporter) 63 | 64 | add_library(InterCodeGenerator STATIC src/InterCodeGenerator.c) 65 | target_link_libraries(InterCodeGenerator SemanticAnalyzer) 66 | 67 | # Compile the project 68 | add_executable(Lab1 ${Lab1Source}) 69 | add_executable(Lab2 ${Lab2Source}) 70 | add_executable(Lab3 ${Lab3Source}) 71 | 72 | # Link the project 73 | target_link_libraries(Lab1 ParserAnalyzer) 74 | target_link_libraries(Lab2 SemanticAnalyzer) 75 | target_link_libraries(Lab3 InterCodeGenerator) -------------------------------------------------------------------------------- /crystal/Lab1BatchTest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ ! -f Lab1 ]; then 4 | echo "Lab1 not found, please compile it first" 5 | exit 1 6 | fi 7 | 8 | if [ ! -d testLab1 ]; then 9 | echo "test directory not found" 10 | exit 1 11 | fi 12 | 13 | if [ ! -d testLab1/output ]; then 14 | mkdir testLab1/output 15 | fi 16 | 17 | echo "---------------------------------" 18 | for file in testLab1/*.cmm 19 | do 20 | echo "Testing $file" 21 | ./Lab1 $file > "testLab1/output/${file#testLab1/}.pst" 22 | echo "---------------------------------" 23 | done -------------------------------------------------------------------------------- /crystal/Lab2BatchTest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ ! -f Lab2 ]; then 4 | echo "Lab2 not found, please compile it first" 5 | exit 1 6 | fi 7 | 8 | if [ ! -d testLab2 ]; then 9 | echo "testLab2 directory not found" 10 | exit 1 11 | fi 12 | 13 | if [ ! -d testLab2/output ]; then 14 | mkdir testLab2/output 15 | fi 16 | 17 | echo "---------------------------------" 18 | for file in testLab2/*.cmm 19 | do 20 | echo "Testing $file" 21 | ./Lab2 $file > "testLab2/output/${file#testLab2/}.pst" 22 | echo "---------------------------------" 23 | done -------------------------------------------------------------------------------- /crystal/Lab3BatchTest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ ! -f Lab3 ]; then 4 | echo "Lab3 not found, please compile it first" 5 | exit 1 6 | fi 7 | 8 | if [ ! -d testLab3 ]; then 9 | echo "testLab3 directory not found" 10 | exit 1 11 | fi 12 | 13 | if [ ! -d testLab3/output ]; then 14 | mkdir testLab3/output 15 | fi 16 | 17 | echo "---------------------------------" 18 | for file in testLab3/*.cmm 19 | do 20 | echo "Testing $file" 21 | ./Lab3 $file > "testLab3/output/${file#testLab3/}.ir" 22 | echo "---------------------------------" 23 | done -------------------------------------------------------------------------------- /crystal/testLab1/SyntaxTest.cmm: -------------------------------------------------------------------------------- 1 | int main(int a{ 2 | } -------------------------------------------------------------------------------- /crystal/testLab1/extra10.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | /* 4 | comment 5 | /* 6 | nested comment 7 | */ 8 | */ 9 | int i = 1; 10 | } -------------------------------------------------------------------------------- /crystal/testLab1/extra5.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i = 0123; 4 | int j = 0x3F; 5 | } -------------------------------------------------------------------------------- /crystal/testLab1/extra6.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i = 09; 4 | int j = 0x3G; 5 | } -------------------------------------------------------------------------------- /crystal/testLab1/extra7.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | float i = 1.05e-4; 4 | } -------------------------------------------------------------------------------- /crystal/testLab1/extra8.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | float i = 1.05e; 4 | } -------------------------------------------------------------------------------- /crystal/testLab1/extra9.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | // line comment 4 | /* 5 | block comment 6 | */ 7 | int i=1; 8 | } -------------------------------------------------------------------------------- /crystal/testLab1/output/extra10.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab1/output/extra10.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab1/output/extra5.cmm.pst: -------------------------------------------------------------------------------- 1 | Program (1) 2 | ExtDefList (1) 3 | ExtDef (1) 4 | Specifier (1) 5 | TYPE: int 6 | FunDec (1) 7 | ID: main 8 | LP 9 | RP 10 | CompSt (2) 11 | LC 12 | DefList (3) 13 | Def (3) 14 | Specifier (3) 15 | TYPE: int 16 | DecList (3) 17 | Dec (3) 18 | VarDec (3) 19 | ID: i 20 | ASSIGNOP 21 | Exp (3) 22 | INT: 83 23 | SEMI 24 | DefList (4) 25 | Def (4) 26 | Specifier (4) 27 | TYPE: int 28 | DecList (4) 29 | Dec (4) 30 | VarDec (4) 31 | ID: j 32 | ASSIGNOP 33 | Exp (4) 34 | INT: 63 35 | SEMI 36 | RC 37 | -------------------------------------------------------------------------------- /crystal/testLab1/output/extra6.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab1/output/extra6.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab1/output/extra7.cmm.pst: -------------------------------------------------------------------------------- 1 | Program (1) 2 | ExtDefList (1) 3 | ExtDef (1) 4 | Specifier (1) 5 | TYPE: int 6 | FunDec (1) 7 | ID: main 8 | LP 9 | RP 10 | CompSt (2) 11 | LC 12 | DefList (3) 13 | Def (3) 14 | Specifier (3) 15 | TYPE: float 16 | DecList (3) 17 | Dec (3) 18 | VarDec (3) 19 | ID: i 20 | ASSIGNOP 21 | Exp (3) 22 | FLOAT: 0.000105 23 | SEMI 24 | RC 25 | -------------------------------------------------------------------------------- /crystal/testLab1/output/extra8.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab1/output/extra8.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab1/output/extra9.cmm.pst: -------------------------------------------------------------------------------- 1 | Program (1) 2 | ExtDefList (1) 3 | ExtDef (1) 4 | Specifier (1) 5 | TYPE: int 6 | FunDec (1) 7 | ID: main 8 | LP 9 | RP 10 | CompSt (2) 11 | LC 12 | DefList (7) 13 | Def (7) 14 | Specifier (7) 15 | TYPE: int 16 | DecList (7) 17 | Dec (7) 18 | VarDec (7) 19 | ID: i 20 | ASSIGNOP 21 | Exp (7) 22 | INT: 1 23 | SEMI 24 | RC 25 | -------------------------------------------------------------------------------- /crystal/testLab1/output/test1.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab1/output/test1.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab1/output/test2.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab1/output/test2.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab1/output/test3.cmm.pst: -------------------------------------------------------------------------------- 1 | Program (1) 2 | ExtDefList (1) 3 | ExtDef (1) 4 | Specifier (1) 5 | TYPE: int 6 | FunDec (1) 7 | ID: inc 8 | LP 9 | RP 10 | CompSt (2) 11 | LC 12 | DefList (3) 13 | Def (3) 14 | Specifier (3) 15 | TYPE: int 16 | DecList (3) 17 | Dec (3) 18 | VarDec (3) 19 | ID: i 20 | SEMI 21 | StmtList (4) 22 | Stmt (4) 23 | Exp (4) 24 | Exp (4) 25 | ID: i 26 | ASSIGNOP 27 | Exp (4) 28 | Exp (4) 29 | ID: i 30 | PLUS 31 | Exp (4) 32 | INT: 1 33 | SEMI 34 | RC 35 | -------------------------------------------------------------------------------- /crystal/testLab1/output/test4.cmm.pst: -------------------------------------------------------------------------------- 1 | Program (1) 2 | ExtDefList (1) 3 | ExtDef (1) 4 | Specifier (1) 5 | StructSpecifier (1) 6 | STRUCT 7 | OptTag (1) 8 | ID: Complex 9 | LC 10 | DefList (3) 11 | Def (3) 12 | Specifier (3) 13 | TYPE: float 14 | DecList (3) 15 | Dec (3) 16 | VarDec (3) 17 | ID: real 18 | COMMA 19 | DecList (3) 20 | Dec (3) 21 | VarDec (3) 22 | ID: image 23 | SEMI 24 | RC 25 | SEMI 26 | ExtDefList (5) 27 | ExtDef (5) 28 | Specifier (5) 29 | TYPE: int 30 | FunDec (5) 31 | ID: main 32 | LP 33 | RP 34 | CompSt (6) 35 | LC 36 | DefList (7) 37 | Def (7) 38 | Specifier (7) 39 | StructSpecifier (7) 40 | STRUCT 41 | Tag (7) 42 | ID: Complex 43 | DecList (7) 44 | Dec (7) 45 | VarDec (7) 46 | ID: x 47 | SEMI 48 | StmtList (8) 49 | Stmt (8) 50 | Exp (8) 51 | Exp (8) 52 | Exp (8) 53 | ID: y 54 | DOT 55 | ID: image 56 | ASSIGNOP 57 | Exp (8) 58 | FLOAT: 3.500000 59 | SEMI 60 | RC 61 | -------------------------------------------------------------------------------- /crystal/testLab1/relopTest.cmm: -------------------------------------------------------------------------------- 1 | int main () 2 | { 3 | int i = 1; 4 | int j = 1 == 2; 5 | } -------------------------------------------------------------------------------- /crystal/testLab1/test1.cmm: -------------------------------------------------------------------------------- 1 | int main () 2 | { 3 | int i = 1; 4 | int j = ~i; 5 | } -------------------------------------------------------------------------------- /crystal/testLab1/test2.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | float a[10][2]; 4 | int i; 5 | a[5,3] = 1.5; 6 | if (a[1][2] == 0) i = 1 else i = 0; 7 | } -------------------------------------------------------------------------------- /crystal/testLab1/test3.cmm: -------------------------------------------------------------------------------- 1 | int inc() 2 | { 3 | int i; 4 | i = i + 1; 5 | } -------------------------------------------------------------------------------- /crystal/testLab1/test4.cmm: -------------------------------------------------------------------------------- 1 | struct Complex 2 | { 3 | float real,image; 4 | }; 5 | int main() 6 | { 7 | struct Complex x; 8 | y.image=3.5; 9 | } -------------------------------------------------------------------------------- /crystal/testLab2/extra1.cmm: -------------------------------------------------------------------------------- 1 | int func(int a); 2 | 3 | int func(int a) 4 | { 5 | return 1; 6 | } 7 | 8 | int main() 9 | { 10 | 11 | } -------------------------------------------------------------------------------- /crystal/testLab2/extra2.cmm: -------------------------------------------------------------------------------- 1 | struct Position 2 | { 3 | float x,y; 4 | }; 5 | 6 | int func(int a); 7 | 8 | int func(struct Position p); 9 | 10 | int main() 11 | { 12 | 13 | } -------------------------------------------------------------------------------- /crystal/testLab2/extra3.cmm: -------------------------------------------------------------------------------- 1 | int func() 2 | { 3 | int i = 10; 4 | return i; 5 | } 6 | 7 | int main() 8 | { 9 | int i; 10 | i = func(); 11 | } -------------------------------------------------------------------------------- /crystal/testLab2/extra4.cmm: -------------------------------------------------------------------------------- 1 | int func(){ 2 | int i = 10; 3 | return i; 4 | } 5 | 6 | int main() 7 | { 8 | int i; 9 | int i, j; 10 | i = func(); 11 | } -------------------------------------------------------------------------------- /crystal/testLab2/extra5.cmm: -------------------------------------------------------------------------------- 1 | struct Temp1 2 | { 3 | int i; 4 | float j; 5 | }; 6 | struct Temp2 7 | { 8 | int x; 9 | float y; 10 | }; 11 | int main() 12 | { 13 | struct Temp1 t1; 14 | struct Temp2 t2; 15 | t1 = t2; 16 | } 17 | -------------------------------------------------------------------------------- /crystal/testLab2/extra6.cmm: -------------------------------------------------------------------------------- 1 | struct Temp1 2 | { 3 | int i; 4 | float j; 5 | }; 6 | 7 | struct Temp2 8 | { 9 | int x; 10 | }; 11 | 12 | int main() 13 | { 14 | struct Temp1 t1; 15 | struct Temp2 t2; 16 | t1 = t2; 17 | } 18 | -------------------------------------------------------------------------------- /crystal/testLab2/output/extra1.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra1.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra18.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra18.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra19.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra19.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra2.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra2.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra20.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra20.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra21.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra21.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra22.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra22.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra23.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra23.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra3.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra3.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra4.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra4.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra5.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra5.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/extra6.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/extra6.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test1.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test1.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test10.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test10.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test11.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test11.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test12.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test12.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test13.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test13.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test14.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test14.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test15.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test15.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test16.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test16.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test17.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test17.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test2.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test2.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test3.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test3.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test4.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test4.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test5.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test5.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test6.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test6.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test7.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test7.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test8.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test8.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/output/test9.cmm.pst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrystalVapor/HITCompilerPrincipleLab/bed9bf9cdddf9b9e032665d29686d7c78cc535cc/crystal/testLab2/output/test9.cmm.pst -------------------------------------------------------------------------------- /crystal/testLab2/test1.cmm: -------------------------------------------------------------------------------- 1 | int main(){ 2 | int i = 0; 3 | j = i + 1; 4 | } -------------------------------------------------------------------------------- /crystal/testLab2/test10.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i; 4 | i[0]; 5 | } -------------------------------------------------------------------------------- /crystal/testLab2/test11.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i; 4 | i(10); 5 | } -------------------------------------------------------------------------------- /crystal/testLab2/test12.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i[10]; 4 | i[1.5] = 10; 5 | } -------------------------------------------------------------------------------- /crystal/testLab2/test13.cmm: -------------------------------------------------------------------------------- 1 | struct Position 2 | { 3 | float x, y; 4 | }; 5 | 6 | int main() 7 | { 8 | int i; 9 | i.x; 10 | } -------------------------------------------------------------------------------- /crystal/testLab2/test14.cmm: -------------------------------------------------------------------------------- 1 | struct Position 2 | { 3 | float x, y; 4 | }; 5 | int main() 6 | { 7 | struct Position p; 8 | if (p.n == 3.7) 9 | return 0; 10 | } -------------------------------------------------------------------------------- /crystal/testLab2/test15.cmm: -------------------------------------------------------------------------------- 1 | struct Position 2 | { 3 | float x, y; 4 | int x; 5 | }; 6 | int main() 7 | { 8 | 9 | } -------------------------------------------------------------------------------- /crystal/testLab2/test16.cmm: -------------------------------------------------------------------------------- 1 | struct Position 2 | { 3 | float x; 4 | }; 5 | 6 | struct Position 7 | { 8 | int y; 9 | }; 10 | 11 | int main() 12 | { 13 | } -------------------------------------------------------------------------------- /crystal/testLab2/test17.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | struct Position pos; 4 | } 5 | -------------------------------------------------------------------------------- /crystal/testLab2/test2.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i = 0; 4 | inc(i); 5 | } -------------------------------------------------------------------------------- /crystal/testLab2/test3.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i, j; 4 | int i; 5 | } -------------------------------------------------------------------------------- /crystal/testLab2/test4.cmm: -------------------------------------------------------------------------------- 1 | int func(int i) 2 | { 3 | return i; 4 | } 5 | 6 | int func() 7 | { 8 | return 0; 9 | } 10 | 11 | int main() 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /crystal/testLab2/test5.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i; 4 | i = 3.7; 5 | } -------------------------------------------------------------------------------- /crystal/testLab2/test6.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int i; 4 | 10 = i; 5 | } -------------------------------------------------------------------------------- /crystal/testLab2/test7.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | float j; 4 | 10 + j; 5 | } -------------------------------------------------------------------------------- /crystal/testLab2/test8.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | float j = 1.7; 4 | return j; 5 | } -------------------------------------------------------------------------------- /crystal/testLab2/test9.cmm: -------------------------------------------------------------------------------- 1 | int func(int i) 2 | { 3 | return i; 4 | } 5 | 6 | int main() 7 | { 8 | func(1, 2); 9 | } -------------------------------------------------------------------------------- /crystal/testLab3/extra1.cmm: -------------------------------------------------------------------------------- 1 | struct Operands 2 | { 3 | int o1; 4 | int o2; 5 | }; 6 | 7 | int add(struct Operands temp) 8 | { 9 | return (temp.o1 + temp.o2); 10 | } 11 | 12 | int main() 13 | { 14 | int n; 15 | struct Operands op; 16 | op.o1 = 1; 17 | op.o2 = 2; 18 | n = add(op); 19 | write(n); 20 | return 0; 21 | } -------------------------------------------------------------------------------- /crystal/testLab3/extra2.cmm: -------------------------------------------------------------------------------- 1 | int add(int temp[2]) 2 | { 3 | return (temp[0] + temp[1]); 4 | } 5 | 6 | int main() 7 | { 8 | int op[2]; 9 | int r[1][2]; 10 | int i = 0, j = 0; 11 | while (i < 2) 12 | { 13 | while (j < 2) 14 | { 15 | op[j] = i + j; 16 | j = j + 1; 17 | } 18 | r[0][i] = add(op); 19 | write(r[0][i]); 20 | i = i + 1; 21 | j = 0; 22 | } 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /crystal/testLab3/test1.cmm: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int n; 4 | n = read(); 5 | if (n > 0) write(1); 6 | else if (n < 0) write (-1); 7 | else write(0); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /crystal/testLab3/test2.cmm: -------------------------------------------------------------------------------- 1 | int fact(int n) 2 | { 3 | if (n == 1) 4 | return n; 5 | else 6 | return (n * fact(n - 1)); 7 | } 8 | int main() 9 | { 10 | int m, result; 11 | m = read(); 12 | if (m > 1) 13 | result = fact(m); 14 | else 15 | result = 1; 16 | write(result); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /include/CmmParser.tab.h: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 3.8.2. */ 2 | 3 | /* Bison interface for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, 6 | Inc. 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . */ 20 | 21 | /* As a special exception, you may create a larger work that contains 22 | part or all of the Bison parser skeleton and distribute that work 23 | under terms of your choice, so long as that work isn't itself a 24 | parser generator using the skeleton or a modified version thereof 25 | as a parser skeleton. Alternatively, if you modify or redistribute 26 | the parser skeleton itself, you may (at your option) remove this 27 | special exception, which will cause the skeleton and the resulting 28 | Bison output files to be licensed under the GNU General Public 29 | License without this special exception. 30 | 31 | This special exception was added by the Free Software Foundation in 32 | version 2.2 of Bison. */ 33 | 34 | /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, 35 | especially those whose name start with YY_ or yy_. They are 36 | private implementation details that can be changed or removed. */ 37 | 38 | #ifndef YY_YY_HOME_CRYSTAL_COMPILERPRICIPLE_LAB_INCLUDE_CMMPARSER_TAB_H_INCLUDED 39 | # define YY_YY_HOME_CRYSTAL_COMPILERPRICIPLE_LAB_INCLUDE_CMMPARSER_TAB_H_INCLUDED 40 | /* Debug traces. */ 41 | #ifndef YYDEBUG 42 | # define YYDEBUG 0 43 | #endif 44 | #if YYDEBUG 45 | extern int yydebug; 46 | #endif 47 | 48 | /* Token kinds. */ 49 | #ifndef YYTOKENTYPE 50 | # define YYTOKENTYPE 51 | enum yytokentype 52 | { 53 | YYEMPTY = -2, 54 | YYEOF = 0, /* "end of file" */ 55 | YYerror = 256, /* error */ 56 | YYUNDEF = 257, /* "invalid token" */ 57 | INT = 258, /* INT */ 58 | FLOAT = 259, /* FLOAT */ 59 | ID = 260, /* ID */ 60 | SEMI = 261, /* SEMI */ 61 | COMMA = 262, /* COMMA */ 62 | ASSIGNOP = 263, /* ASSIGNOP */ 63 | EQ = 264, /* EQ */ 64 | NEQ = 265, /* NEQ */ 65 | LE = 266, /* LE */ 66 | LT = 267, /* LT */ 67 | GE = 268, /* GE */ 68 | GT = 269, /* GT */ 69 | PLUS = 270, /* PLUS */ 70 | MINUS = 271, /* MINUS */ 71 | STAR = 272, /* STAR */ 72 | DIV = 273, /* DIV */ 73 | AND = 274, /* AND */ 74 | OR = 275, /* OR */ 75 | DOT = 276, /* DOT */ 76 | NOT = 277, /* NOT */ 77 | TYPE = 278, /* TYPE */ 78 | LP = 279, /* LP */ 79 | RP = 280, /* RP */ 80 | LB = 281, /* LB */ 81 | RB = 282, /* RB */ 82 | LC = 283, /* LC */ 83 | RC = 284, /* RC */ 84 | STRUCT = 285, /* STRUCT */ 85 | RETURN = 286, /* RETURN */ 86 | IF = 287, /* IF */ 87 | ELSE = 288, /* ELSE */ 88 | WHILE = 289, /* WHILE */ 89 | LELSE = 290, /* LELSE */ 90 | pri3 = 291, /* pri3 */ 91 | pri2 = 292, /* pri2 */ 92 | pri1 = 293, /* pri1 */ 93 | pri0 = 294 /* pri0 */ 94 | }; 95 | typedef enum yytokentype yytoken_kind_t; 96 | #endif 97 | 98 | /* Value type. */ 99 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED 100 | union YYSTYPE 101 | { 102 | #line 13 "/home/crystal/compilerPriciple/Lab/src/CmmParser.y" 103 | 104 | ParserNode_I nodeIndex; 105 | 106 | #line 107 "/home/crystal/compilerPriciple/Lab/include/CmmParser.tab.h" 107 | 108 | }; 109 | typedef union YYSTYPE YYSTYPE; 110 | # define YYSTYPE_IS_TRIVIAL 1 111 | # define YYSTYPE_IS_DECLARED 1 112 | #endif 113 | 114 | 115 | extern YYSTYPE yylval; 116 | 117 | 118 | int yyparse (void); 119 | 120 | 121 | #endif /* !YY_YY_HOME_CRYSTAL_COMPILERPRICIPLE_LAB_INCLUDE_CMMPARSER_TAB_H_INCLUDED */ 122 | -------------------------------------------------------------------------------- /include/CmmParserTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/17. 3 | // 4 | 5 | #ifndef LAB1_CMMPARSERTYPES_H 6 | #define LAB1_CMMPARSERTYPES_H 7 | 8 | struct SimpleArray_s; 9 | typedef struct SimpleArray_s* SimpleArray_t; 10 | enum yytokentype; 11 | typedef enum yytokentype yytoken; 12 | 13 | typedef struct ParserNode_s* ParserNode_t; 14 | typedef struct ParserNode_s ParserNode; 15 | typedef SimpleArray_t ParserNodeIndexContainer_t; 16 | typedef int ParserNode_I; 17 | 18 | typedef enum SyntaxToken_e{ 19 | PROGRAM = 513, 20 | EXT_DEF_LIST = 514, 21 | EXT_DEF = 515, 22 | EXT_DEC_LIST = 516, 23 | SPECIFIER = 517, 24 | STRUCT_SPECIFIER = 518, 25 | OPT_TAG = 519, 26 | TAG = 520, 27 | VAR_DEC = 521, 28 | FUN_DEC = 522, 29 | VAR_LIST = 523, 30 | PARAM_DEC = 524, 31 | COMP_STM = 525, 32 | STMT_LIST = 526, 33 | STMT = 527, 34 | DEF_LIST = 528, 35 | DEF = 529, 36 | DEC_LIST = 530, 37 | DEC = 531, 38 | EXP = 532, 39 | ARGS = 533 40 | }SyntaxToken; 41 | 42 | struct YYSTYPE_s{ 43 | ParserNode_I nodeIndex; 44 | }; 45 | typedef struct YYSTYPE_s YYSTYPE; 46 | 47 | #define YYSTYPE_IS_DECLARED 1 48 | #include "CmmParser.tab.h" 49 | 50 | struct SemanticInfo_s; 51 | 52 | struct ParserNode_s{ 53 | int token; 54 | int lineNum; 55 | ParserNodeIndexContainer_t children; 56 | union{ 57 | int intVal; 58 | float floatVal; 59 | char* ID; 60 | }; 61 | struct SemanticInfo_s* semanticInfo; 62 | }; 63 | 64 | #ifndef NOINCLUDE_CMM_SCANNER_TAB_H 65 | #include "CmmScanner.tab.h" 66 | #endif 67 | 68 | #define IS_SYNTAX_TOKEN(token) ((token) >= PROGRAM && (token) <= ARGS) 69 | #define IS_TERMINAL_TOKEN(token) ((token) >= INT && (token) <= WHILE) 70 | 71 | #include "Structure/TokenName.h" 72 | #include "Structure/SimpleArray.h" 73 | 74 | #define NO_LINE_NUMBER (0) 75 | #endif //LAB1_CMMPARSERTYPES_H 76 | -------------------------------------------------------------------------------- /include/CmmScanner.tab.h: -------------------------------------------------------------------------------- 1 | #ifndef yyHEADER_H 2 | #define yyHEADER_H 1 3 | #define yyIN_HEADER 1 4 | 5 | #line 6 "/home/crystal/compilerPriciple/Lab/include/CmmScanner.tab.h" 6 | 7 | #line 8 "/home/crystal/compilerPriciple/Lab/include/CmmScanner.tab.h" 8 | 9 | #define YY_INT_ALIGNED short int 10 | 11 | /* A lexical scanner generated by flex */ 12 | 13 | /* %not-for-header */ 14 | 15 | #define FLEX_SCANNER 16 | #define YY_FLEX_MAJOR_VERSION 2 17 | #define YY_FLEX_MINOR_VERSION 6 18 | #define YY_FLEX_SUBMINOR_VERSION 4 19 | #if YY_FLEX_SUBMINOR_VERSION > 0 20 | #define FLEX_BETA 21 | #endif 22 | 23 | /* %if-c++-only */ 24 | /* %endif */ 25 | 26 | /* %if-c-only */ 27 | 28 | /* %endif */ 29 | 30 | /* %if-c-only */ 31 | 32 | /* %endif */ 33 | 34 | /* First, we deal with platform-specific or compiler-specific issues. */ 35 | 36 | /* begin standard C headers. */ 37 | /* %if-c-only */ 38 | #include 39 | #include 40 | #include 41 | #include 42 | /* %endif */ 43 | 44 | /* %if-tables-serialization */ 45 | /* %endif */ 46 | /* end standard C headers. */ 47 | 48 | /* %if-c-or-c++ */ 49 | /* flex integer type definitions */ 50 | 51 | #ifndef FLEXINT_H 52 | #define FLEXINT_H 53 | 54 | /* C99 systems have . Non-C99 systems may or may not. */ 55 | 56 | #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 57 | 58 | /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, 59 | * if you want the limit (max/min) macros for int types. 60 | */ 61 | #ifndef __STDC_LIMIT_MACROS 62 | #define __STDC_LIMIT_MACROS 1 63 | #endif 64 | 65 | #include 66 | typedef int8_t flex_int8_t; 67 | typedef uint8_t flex_uint8_t; 68 | typedef int16_t flex_int16_t; 69 | typedef uint16_t flex_uint16_t; 70 | typedef int32_t flex_int32_t; 71 | typedef uint32_t flex_uint32_t; 72 | #else 73 | typedef signed char flex_int8_t; 74 | typedef short int flex_int16_t; 75 | typedef int flex_int32_t; 76 | typedef unsigned char flex_uint8_t; 77 | typedef unsigned short int flex_uint16_t; 78 | typedef unsigned int flex_uint32_t; 79 | 80 | /* Limits of integral types. */ 81 | #ifndef INT8_MIN 82 | #define INT8_MIN (-128) 83 | #endif 84 | #ifndef INT16_MIN 85 | #define INT16_MIN (-32767-1) 86 | #endif 87 | #ifndef INT32_MIN 88 | #define INT32_MIN (-2147483647-1) 89 | #endif 90 | #ifndef INT8_MAX 91 | #define INT8_MAX (127) 92 | #endif 93 | #ifndef INT16_MAX 94 | #define INT16_MAX (32767) 95 | #endif 96 | #ifndef INT32_MAX 97 | #define INT32_MAX (2147483647) 98 | #endif 99 | #ifndef UINT8_MAX 100 | #define UINT8_MAX (255U) 101 | #endif 102 | #ifndef UINT16_MAX 103 | #define UINT16_MAX (65535U) 104 | #endif 105 | #ifndef UINT32_MAX 106 | #define UINT32_MAX (4294967295U) 107 | #endif 108 | 109 | #ifndef SIZE_MAX 110 | #define SIZE_MAX (~(size_t)0) 111 | #endif 112 | 113 | #endif /* ! C99 */ 114 | 115 | #endif /* ! FLEXINT_H */ 116 | 117 | /* %endif */ 118 | 119 | /* begin standard C++ headers. */ 120 | /* %if-c++-only */ 121 | /* %endif */ 122 | 123 | /* TODO: this is always defined, so inline it */ 124 | #define yyconst const 125 | 126 | #if defined(__GNUC__) && __GNUC__ >= 3 127 | #define yynoreturn __attribute__((__noreturn__)) 128 | #else 129 | #define yynoreturn 130 | #endif 131 | 132 | /* %not-for-header */ 133 | 134 | /* %not-for-header */ 135 | 136 | /* %if-reentrant */ 137 | /* %endif */ 138 | 139 | /* %if-not-reentrant */ 140 | 141 | /* %endif */ 142 | 143 | /* Size of default input buffer. */ 144 | #ifndef YY_BUF_SIZE 145 | #ifdef __ia64__ 146 | /* On IA-64, the buffer size is 16k, not 8k. 147 | * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. 148 | * Ditto for the __ia64__ case accordingly. 149 | */ 150 | #define YY_BUF_SIZE 32768 151 | #else 152 | #define YY_BUF_SIZE 16384 153 | #endif /* __ia64__ */ 154 | #endif 155 | 156 | #ifndef YY_TYPEDEF_YY_BUFFER_STATE 157 | #define YY_TYPEDEF_YY_BUFFER_STATE 158 | typedef struct yy_buffer_state *YY_BUFFER_STATE; 159 | #endif 160 | 161 | #ifndef YY_TYPEDEF_YY_SIZE_T 162 | #define YY_TYPEDEF_YY_SIZE_T 163 | typedef size_t yy_size_t; 164 | #endif 165 | 166 | /* %if-not-reentrant */ 167 | extern int yyleng; 168 | /* %endif */ 169 | 170 | /* %if-c-only */ 171 | /* %if-not-reentrant */ 172 | extern FILE *yyin, *yyout; 173 | /* %endif */ 174 | /* %endif */ 175 | 176 | #ifndef YY_STRUCT_YY_BUFFER_STATE 177 | #define YY_STRUCT_YY_BUFFER_STATE 178 | struct yy_buffer_state 179 | { 180 | /* %if-c-only */ 181 | FILE *yy_input_file; 182 | /* %endif */ 183 | 184 | /* %if-c++-only */ 185 | /* %endif */ 186 | 187 | char *yy_ch_buf; /* input buffer */ 188 | char *yy_buf_pos; /* current position in input buffer */ 189 | 190 | /* Size of input buffer in bytes, not including room for EOB 191 | * characters. 192 | */ 193 | int yy_buf_size; 194 | 195 | /* Number of characters read into yy_ch_buf, not including EOB 196 | * characters. 197 | */ 198 | int yy_n_chars; 199 | 200 | /* Whether we "own" the buffer - i.e., we know we created it, 201 | * and can realloc() it to grow it, and should free() it to 202 | * delete it. 203 | */ 204 | int yy_is_our_buffer; 205 | 206 | /* Whether this is an "interactive" input source; if so, and 207 | * if we're using stdio for input, then we want to use getc() 208 | * instead of fread(), to make sure we stop fetching input after 209 | * each newline. 210 | */ 211 | int yy_is_interactive; 212 | 213 | /* Whether we're considered to be at the beginning of a line. 214 | * If so, '^' rules will be active on the next match, otherwise 215 | * not. 216 | */ 217 | int yy_at_bol; 218 | 219 | int yy_bs_lineno; /**< The line count. */ 220 | int yy_bs_column; /**< The column count. */ 221 | 222 | /* Whether to try to fill the input buffer when we reach the 223 | * end of it. 224 | */ 225 | int yy_fill_buffer; 226 | 227 | int yy_buffer_status; 228 | 229 | }; 230 | #endif /* !YY_STRUCT_YY_BUFFER_STATE */ 231 | 232 | /* %if-c-only Standard (non-C++) definition */ 233 | /* %not-for-header */ 234 | 235 | /* %endif */ 236 | 237 | /* %if-c-only Standard (non-C++) definition */ 238 | 239 | /* %if-not-reentrant */ 240 | /* %not-for-header */ 241 | 242 | /* %endif */ 243 | 244 | void yyrestart ( FILE *input_file ); 245 | void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); 246 | YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); 247 | void yy_delete_buffer ( YY_BUFFER_STATE b ); 248 | void yy_flush_buffer ( YY_BUFFER_STATE b ); 249 | void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); 250 | void yypop_buffer_state ( void ); 251 | 252 | YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); 253 | YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); 254 | YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); 255 | 256 | /* %endif */ 257 | 258 | void *yyalloc ( yy_size_t ); 259 | void *yyrealloc ( void *, yy_size_t ); 260 | void yyfree ( void * ); 261 | 262 | /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */ 263 | /* Begin user sect3 */ 264 | 265 | #define FLEX_DEBUG 266 | 267 | extern int yylineno; 268 | 269 | extern char *yytext; 270 | #ifdef yytext_ptr 271 | #undef yytext_ptr 272 | #endif 273 | #define yytext_ptr yytext 274 | 275 | /* %if-c-only Standard (non-C++) definition */ 276 | 277 | /* %endif */ 278 | 279 | #ifdef YY_HEADER_EXPORT_START_CONDITIONS 280 | #define INITIAL 0 281 | 282 | #endif 283 | 284 | #ifndef YY_NO_UNISTD_H 285 | /* Special case for "unistd.h", since it is non-ANSI. We include it way 286 | * down here because we want the user's section 1 to have been scanned first. 287 | * The user has a chance to override it with an option. 288 | */ 289 | /* %if-c-only */ 290 | #include 291 | /* %endif */ 292 | /* %if-c++-only */ 293 | /* %endif */ 294 | #endif 295 | 296 | #ifndef YY_EXTRA_TYPE 297 | #define YY_EXTRA_TYPE void * 298 | #endif 299 | 300 | /* %if-c-only Reentrant structure and macros (non-C++). */ 301 | /* %if-reentrant */ 302 | /* %if-c-only */ 303 | 304 | /* %endif */ 305 | /* %if-reentrant */ 306 | /* %endif */ 307 | /* %endif End reentrant structures and macros. */ 308 | 309 | /* Accessor methods to globals. 310 | These are made visible to non-reentrant scanners for convenience. */ 311 | 312 | int yylex_destroy ( void ); 313 | 314 | int yyget_debug ( void ); 315 | 316 | void yyset_debug ( int debug_flag ); 317 | 318 | YY_EXTRA_TYPE yyget_extra ( void ); 319 | 320 | void yyset_extra ( YY_EXTRA_TYPE user_defined ); 321 | 322 | FILE *yyget_in ( void ); 323 | 324 | void yyset_in ( FILE * _in_str ); 325 | 326 | FILE *yyget_out ( void ); 327 | 328 | void yyset_out ( FILE * _out_str ); 329 | 330 | int yyget_leng ( void ); 331 | 332 | char *yyget_text ( void ); 333 | 334 | int yyget_lineno ( void ); 335 | 336 | void yyset_lineno ( int _line_number ); 337 | 338 | /* %if-bison-bridge */ 339 | /* %endif */ 340 | 341 | /* Macros after this point can all be overridden by user definitions in 342 | * section 1. 343 | */ 344 | 345 | #ifndef YY_SKIP_YYWRAP 346 | #ifdef __cplusplus 347 | extern "C" int yywrap ( void ); 348 | #else 349 | extern int yywrap ( void ); 350 | #endif 351 | #endif 352 | 353 | /* %not-for-header */ 354 | 355 | /* %endif */ 356 | 357 | #ifndef yytext_ptr 358 | static void yy_flex_strncpy ( char *, const char *, int ); 359 | #endif 360 | 361 | #ifdef YY_NEED_STRLEN 362 | static int yy_flex_strlen ( const char * ); 363 | #endif 364 | 365 | #ifndef YY_NO_INPUT 366 | /* %if-c-only Standard (non-C++) definition */ 367 | /* %not-for-header */ 368 | 369 | /* %endif */ 370 | #endif 371 | 372 | /* %if-c-only */ 373 | 374 | /* %endif */ 375 | 376 | /* Amount of stuff to slurp up with each read. */ 377 | #ifndef YY_READ_BUF_SIZE 378 | #ifdef __ia64__ 379 | /* On IA-64, the buffer size is 16k, not 8k */ 380 | #define YY_READ_BUF_SIZE 16384 381 | #else 382 | #define YY_READ_BUF_SIZE 8192 383 | #endif /* __ia64__ */ 384 | #endif 385 | 386 | /* Number of entries by which start-condition stack grows. */ 387 | #ifndef YY_START_STACK_INCR 388 | #define YY_START_STACK_INCR 25 389 | #endif 390 | 391 | /* %if-tables-serialization structures and prototypes */ 392 | /* %not-for-header */ 393 | 394 | /* %not-for-header */ 395 | 396 | /* Default declaration of generated scanner - a define so the user can 397 | * easily add parameters. 398 | */ 399 | #ifndef YY_DECL 400 | #define YY_DECL_IS_OURS 1 401 | /* %if-c-only Standard (non-C++) definition */ 402 | 403 | extern int yylex (void); 404 | 405 | #define YY_DECL int yylex (void) 406 | /* %endif */ 407 | /* %if-c++-only C++ definition */ 408 | /* %endif */ 409 | #endif /* !YY_DECL */ 410 | 411 | /* %not-for-header */ 412 | 413 | /* %if-c++-only */ 414 | /* %not-for-header */ 415 | 416 | /* %endif */ 417 | 418 | /* yy_get_previous_state - get the state just before the EOB char was reached */ 419 | 420 | /* %if-c-only */ 421 | /* %not-for-header */ 422 | 423 | #undef YY_NEW_FILE 424 | #undef YY_FLUSH_BUFFER 425 | #undef yy_set_bol 426 | #undef yy_new_buffer 427 | #undef yy_set_interactive 428 | #undef YY_DO_BEFORE_ACTION 429 | 430 | #ifdef YY_DECL_IS_OURS 431 | #undef YY_DECL_IS_OURS 432 | #undef YY_DECL 433 | #endif 434 | 435 | #ifndef yy_create_buffer_ALREADY_DEFINED 436 | #undef yy_create_buffer 437 | #endif 438 | #ifndef yy_delete_buffer_ALREADY_DEFINED 439 | #undef yy_delete_buffer 440 | #endif 441 | #ifndef yy_scan_buffer_ALREADY_DEFINED 442 | #undef yy_scan_buffer 443 | #endif 444 | #ifndef yy_scan_string_ALREADY_DEFINED 445 | #undef yy_scan_string 446 | #endif 447 | #ifndef yy_scan_bytes_ALREADY_DEFINED 448 | #undef yy_scan_bytes 449 | #endif 450 | #ifndef yy_init_buffer_ALREADY_DEFINED 451 | #undef yy_init_buffer 452 | #endif 453 | #ifndef yy_flush_buffer_ALREADY_DEFINED 454 | #undef yy_flush_buffer 455 | #endif 456 | #ifndef yy_load_buffer_state_ALREADY_DEFINED 457 | #undef yy_load_buffer_state 458 | #endif 459 | #ifndef yy_switch_to_buffer_ALREADY_DEFINED 460 | #undef yy_switch_to_buffer 461 | #endif 462 | #ifndef yypush_buffer_state_ALREADY_DEFINED 463 | #undef yypush_buffer_state 464 | #endif 465 | #ifndef yypop_buffer_state_ALREADY_DEFINED 466 | #undef yypop_buffer_state 467 | #endif 468 | #ifndef yyensure_buffer_stack_ALREADY_DEFINED 469 | #undef yyensure_buffer_stack 470 | #endif 471 | #ifndef yylex_ALREADY_DEFINED 472 | #undef yylex 473 | #endif 474 | #ifndef yyrestart_ALREADY_DEFINED 475 | #undef yyrestart 476 | #endif 477 | #ifndef yylex_init_ALREADY_DEFINED 478 | #undef yylex_init 479 | #endif 480 | #ifndef yylex_init_extra_ALREADY_DEFINED 481 | #undef yylex_init_extra 482 | #endif 483 | #ifndef yylex_destroy_ALREADY_DEFINED 484 | #undef yylex_destroy 485 | #endif 486 | #ifndef yyget_debug_ALREADY_DEFINED 487 | #undef yyget_debug 488 | #endif 489 | #ifndef yyset_debug_ALREADY_DEFINED 490 | #undef yyset_debug 491 | #endif 492 | #ifndef yyget_extra_ALREADY_DEFINED 493 | #undef yyget_extra 494 | #endif 495 | #ifndef yyset_extra_ALREADY_DEFINED 496 | #undef yyset_extra 497 | #endif 498 | #ifndef yyget_in_ALREADY_DEFINED 499 | #undef yyget_in 500 | #endif 501 | #ifndef yyset_in_ALREADY_DEFINED 502 | #undef yyset_in 503 | #endif 504 | #ifndef yyget_out_ALREADY_DEFINED 505 | #undef yyget_out 506 | #endif 507 | #ifndef yyset_out_ALREADY_DEFINED 508 | #undef yyset_out 509 | #endif 510 | #ifndef yyget_leng_ALREADY_DEFINED 511 | #undef yyget_leng 512 | #endif 513 | #ifndef yyget_text_ALREADY_DEFINED 514 | #undef yyget_text 515 | #endif 516 | #ifndef yyget_lineno_ALREADY_DEFINED 517 | #undef yyget_lineno 518 | #endif 519 | #ifndef yyset_lineno_ALREADY_DEFINED 520 | #undef yyset_lineno 521 | #endif 522 | #ifndef yyget_column_ALREADY_DEFINED 523 | #undef yyget_column 524 | #endif 525 | #ifndef yyset_column_ALREADY_DEFINED 526 | #undef yyset_column 527 | #endif 528 | #ifndef yywrap_ALREADY_DEFINED 529 | #undef yywrap 530 | #endif 531 | #ifndef yyget_lval_ALREADY_DEFINED 532 | #undef yyget_lval 533 | #endif 534 | #ifndef yyset_lval_ALREADY_DEFINED 535 | #undef yyset_lval 536 | #endif 537 | #ifndef yyget_lloc_ALREADY_DEFINED 538 | #undef yyget_lloc 539 | #endif 540 | #ifndef yyset_lloc_ALREADY_DEFINED 541 | #undef yyset_lloc 542 | #endif 543 | #ifndef yyalloc_ALREADY_DEFINED 544 | #undef yyalloc 545 | #endif 546 | #ifndef yyrealloc_ALREADY_DEFINED 547 | #undef yyrealloc 548 | #endif 549 | #ifndef yyfree_ALREADY_DEFINED 550 | #undef yyfree 551 | #endif 552 | #ifndef yytext_ALREADY_DEFINED 553 | #undef yytext 554 | #endif 555 | #ifndef yyleng_ALREADY_DEFINED 556 | #undef yyleng 557 | #endif 558 | #ifndef yyin_ALREADY_DEFINED 559 | #undef yyin 560 | #endif 561 | #ifndef yyout_ALREADY_DEFINED 562 | #undef yyout 563 | #endif 564 | #ifndef yy_flex_debug_ALREADY_DEFINED 565 | #undef yy_flex_debug 566 | #endif 567 | #ifndef yylineno_ALREADY_DEFINED 568 | #undef yylineno 569 | #endif 570 | #ifndef yytables_fload_ALREADY_DEFINED 571 | #undef yytables_fload 572 | #endif 573 | #ifndef yytables_destroy_ALREADY_DEFINED 574 | #undef yytables_destroy 575 | #endif 576 | #ifndef yyTABLES_NAME_ALREADY_DEFINED 577 | #undef yyTABLES_NAME 578 | #endif 579 | 580 | #line 140 "/home/crystal/compilerPriciple/Lab/src/CmmLexer.l" 581 | 582 | 583 | #line 584 "/home/crystal/compilerPriciple/Lab/include/CmmScanner.tab.h" 584 | #undef yyIN_HEADER 585 | #endif /* yyHEADER_H */ 586 | -------------------------------------------------------------------------------- /include/ErrorReporter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/20. 3 | // 4 | 5 | #ifndef LAB1_ERRORREPORTER_H 6 | #define LAB1_ERRORREPORTER_H 7 | 8 | #include 9 | 10 | typedef enum ErrorType_e{ 11 | LEXICAL_ERROR_BASE = 0, 12 | 13 | UnrecognizedCharacter, 14 | InvalidIdentifier, 15 | InvalidNumber, 16 | InvalidFloat, 17 | 18 | UNDEF_LEXICAL_ERROR = 49, 19 | 20 | SYNTAX_ERROR_BASE = 50, 21 | 22 | UnexpectedStatement, 23 | UnexpectedDeclaration, 24 | MissingSemicolon, 25 | MissingRightBracket, 26 | MissingRightParenthesis, 27 | MissingComma, 28 | MissingSpecifier, 29 | UnterminatedComment, 30 | UnexpectedExpression, 31 | 32 | UNDEF_SYNTAX_ERROR = 99, 33 | 34 | SEMANTIC_ERROR_BASE = 100, 35 | 36 | UndefinedVariable, // Error 1 37 | UndefinedFunctionCalled, // Error 2 38 | VariableNameRedefinition, // Error 3 39 | FunctionRedefinition, // Error 4 40 | AssignmentTypeMismatch, // Error 5 41 | AssignToRvalue, // Error 6 42 | OperatorTypeMismatch, // Error 7 43 | ReturnTypeMismatch, // Error 8 44 | ParameterListMismatch, // Error 9 45 | ArrayAccessOnNonArray, // Error 10 46 | FunctionCalledOnNonFunction,// Error 11 47 | ArrayIndexTypeMismatch, // Error 12 48 | MemberAccessOnNonStruct, // Error 13 49 | UndefinedStructMember, // Error 14 50 | InvalidMemberDefinition, // Error 15 51 | ConflictStructDefinition, // Error 16 52 | UndefinedStruct, // Error 17 53 | UndefinedExternalFunction, // Error 18 54 | ImplicitFunctionDeclaration,// Error 19 55 | 56 | UNDEF_SEMANTIC_ERROR = 149, 57 | }ErrorType; 58 | 59 | /** 60 | * register an error to reporter, content of externalMessage will be malloc copied 61 | * if there's already an error on the same line, the new one will be ignored 62 | * @param line line number of the error 63 | * @param errorType error type 64 | * @param externalMessage error message 65 | */ 66 | void reportError(int line, int errorType, char* externalMessage); 67 | 68 | /** 69 | * register an error to reporter, content of externalMessage will be malloc copied and formatted 70 | * if there's already an error on the same line, the new one will be ignored 71 | * @param line line number of the error 72 | * @param errorType error type 73 | * @param format format string 74 | * @param ... format arguments 75 | */ 76 | void reportErrorFormat(int line, int errorType, const char* format, ...); 77 | 78 | /** 79 | * print all errors to file 80 | * @param file file to print 81 | */ 82 | void printError(FILE* file); 83 | 84 | /** 85 | * reset the error reporter, clear all errors, free all memory used by the reporter 86 | */ 87 | void resetErrorReporter(); 88 | 89 | /** 90 | * check if there's any error reported 91 | * @return 0 if no error, otherwise return the number of errors 92 | */ 93 | int hasError(); 94 | 95 | /** 96 | * do not use, just for disabling the default yyerror function 97 | */ 98 | void yyerror(const char* msg); 99 | 100 | #endif //LAB1_ERRORREPORTER_H 101 | -------------------------------------------------------------------------------- /include/InterCodeGenerator.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/31. 3 | // 4 | 5 | /** 6 | * 碎碎念:实际上这一部分按照我的预期应该是嵌入语义分析器的 7 | * (你可以看出来这一部分跟语义分析几乎是同一个设计思路) 8 | * 但是……这样做的话语义分析器那边复杂度估计会爆炸…… 9 | * 所以……狠狠摆了! 10 | */ 11 | 12 | #ifndef LAB1_INTERCODEGENERATOR_H 13 | #define LAB1_INTERCODEGENERATOR_H 14 | 15 | #include "CmmParserTypes.h" 16 | #include "Structure/SimpleList.h" 17 | #include "Structure/SymbolTable.h" 18 | 19 | #define MAX_INTERCODE_PARAM 3 20 | 21 | struct InterCodeInfo_s; 22 | 23 | /** 24 | * 这是个虚表,我写上只是为了好玩而已,没必要复现这玩意 25 | * 如果对虚表感到好奇可以找一下相关资料 26 | * 顺带着推荐一下我的知乎专栏,有讲虚表相关的东西(,直接去搜我ID就好 27 | */ 28 | typedef struct { 29 | void (*generateInterCode) (struct InterCodeInfo_s* interCodeInfo, FILE* file); 30 | }InterCodeInfo_VT; 31 | typedef InterCodeInfo_VT* InterCodeInfo_VT_t; 32 | 33 | typedef enum{ 34 | ICT_TEMP_VAR, 35 | ICT_TEMP_LABEL, 36 | ICT_TEMP_PARAM, 37 | }InterCodeTempType; 38 | 39 | typedef enum { 40 | IC_LABEL = 0, 41 | IC_FUNC, 42 | IC_ASSIGN, 43 | IC_ADD, 44 | IC_SUB, 45 | IC_MUL, 46 | IC_DIV, 47 | 48 | IC_ADDR, 49 | IC_ASSIGN_RDEREF, 50 | IC_ASSIGN_LDEREF, 51 | 52 | IC_GOTO, 53 | IC_EQ_GOTO, 54 | IC_NE_GOTO, 55 | IC_GE_GOTO, 56 | IC_GT_GOTO, 57 | IC_LE_GOTO, 58 | IC_LT_GOTO, 59 | 60 | IC_RETURN, 61 | 62 | IC_DEC, 63 | IC_ARG, 64 | IC_CALL, 65 | IC_PARAM, 66 | IC_READ, 67 | IC_WRITE 68 | }InterCodeType; 69 | 70 | typedef enum{ 71 | ICP_INT, 72 | ICP_VAR, 73 | ICP_PARAM, 74 | ICP_LABEL, 75 | }InterCodeParam_Type; 76 | 77 | typedef struct { 78 | InterCodeParam_Type type; 79 | union{ 80 | int intVal; 81 | int varID; 82 | int paramID; 83 | char* labelName; 84 | }; 85 | int scope; 86 | }InterCodeParam; 87 | typedef InterCodeParam* InterCodeParam_t; 88 | 89 | typedef struct InterCodeInfo_s{ 90 | InterCodeInfo_VT_t vptr; 91 | InterCodeType type; 92 | InterCodeParam params[MAX_INTERCODE_PARAM]; 93 | }InterCodeInfo; 94 | typedef InterCodeInfo* InterCodeInfo_t; 95 | 96 | /* 97 | * The container for intermediate code 98 | * will be constructed by below level and passed to above level 99 | * codes: the intermediate code generated by below level 100 | * returnType: the return type that is truly used by below level as return value 101 | * returnID: the return value's VarID or ParamID 102 | * specialReply: special result from below level used to reply above level's request 103 | */ 104 | typedef struct{ 105 | SimpleList_t codes; 106 | InterCodeParam_Type returnType; // use return type so that we can handle the situation that the return value is a parameter 107 | int returnID; 108 | int specialReply; 109 | }InterCodeContainer; 110 | typedef InterCodeContainer* InterCodeContainer_t; 111 | typedef InterCodeContainer_t InterCodeHandle; 112 | 113 | #define REP_NO 0 114 | #define REP_IS_ADDRESS 1 115 | 116 | #define INVALID_INTERCODE_HANDLE (NULL) 117 | 118 | /* 119 | * instructions for generate intermediate code 120 | * will be constructed by above level and passed to below level 121 | * trueLabel: the label for true branch expected by above level 122 | * falseLabel: the label for false branch expected by above level 123 | * specialRequest: special instruction from above level 124 | */ 125 | typedef struct{ 126 | char* trueLabel; 127 | char* falseLabel; 128 | int specialRequest; 129 | }InterCodeInstruction; 130 | typedef InterCodeInstruction* InterCodeInstruction_t; 131 | 132 | #define REQ_NO 0 133 | #define REQ_ADDRESS 1 134 | #define REQ_NORETURN 2 135 | 136 | /** 137 | * Generate intermediate code for the given syntax tree. 138 | * tree must be valid and has no error. 139 | * @param rootNodeIndex the index of the root node of the syntax tree. 140 | * @param file output file of InterCode. 141 | */ 142 | InterCodeHandle generateInterCode(ParserNode_I rootNodeIndex, FILE *file, SymbolTable_t inSymbolTable); 143 | 144 | /** 145 | * End the generation of intermediate code. 146 | * Will clear the memory used for generating intermediate code. 147 | */ 148 | void generateInterCode_End(); 149 | 150 | /** 151 | * Create a new InterCodeInfo. 152 | * @param type the type of the intermediate code. 153 | * @param paramNum the number of parameters. 154 | * @param va_list the parameters' list packed by Handle 155 | * @return the new InterCodeInfo. 156 | */ 157 | InterCodeInfo_t InterCodeInfo_create(InterCodeType type, int paramNum, va_list paramList); 158 | 159 | /** 160 | * Print the Param to buffer. 161 | * @param param the param to print 162 | * @param buffer the buffer to print 163 | * @param bufferSize size of the buffer 164 | * @return characters printed to buffer(including the null terminator) 165 | */ 166 | int InterCodeParam_printToBuffer(InterCodeParam* param, char* buffer, int bufferSize); 167 | 168 | /** 169 | * Merge two InterCodeHandle. 170 | * Do not use the two InterCodeHandle after merge, it's not safe. 171 | * Will free the handle merged in the process. 172 | * @param handle1 173 | * @param handle2 174 | * @return merged InterCodeHandle 175 | */ 176 | InterCodeHandle InterCodeHandle_merge(InterCodeHandle handle1, InterCodeHandle handle2); 177 | 178 | /** 179 | * Create a new InterCodeHandle. 180 | * @return the new InterCodeHandle. 181 | */ 182 | InterCodeHandle InterCodeHandle_create(); 183 | 184 | /** 185 | * Add a new InterCode to the InterCodeHandle at the end. 186 | * @param handle the handle to add code. 187 | * @param codeType the type of the code. 188 | * @param paramNum the number of parameters. 189 | * @param ... the parameters, format: [InterCodeParam_type, value] 190 | */ 191 | void InterCodeHandle_newCode(InterCodeHandle handle, InterCodeType codeType, int paramNum, ...); 192 | 193 | /** 194 | * Destroy the InterCodeHandle and codes in it. 195 | * @param handle the handle to destroy. 196 | */ 197 | void InterCodeHandle_destroy(InterCodeHandle handle); 198 | 199 | /** 200 | * Print the InterCodeHandle to the file. 201 | * @param file the file to print. 202 | * @param handle the handle to print. 203 | */ 204 | void InterCodeHandle_print(FILE *file, InterCodeHandle handle); 205 | 206 | /** 207 | * @return if param's a struct/array, return 1 208 | */ 209 | int InterCodeGenerator_Helper_isParamAddressReferenced(SymbolInfo_Function_t functionInfo, int paramID); 210 | 211 | #define INTERCODEPARAM_GETLABEL(param) ((param)->labelName) 212 | #define INTERCODEPARAM_GETVAR(param) ((param)->varID) 213 | #define INTERCODEPARAM_GETPARAM(param) ((param)->paramID) 214 | #define INTERCODEPARAM_GETINT(param) ((param)->intVal) 215 | 216 | #define IS_VARIABLE_ID_A_PARAM_ID(variableID) ((variableID) < 0) 217 | #define GET_VARIABLE_ID_FROM_PARAM_ID(paramID) (-(paramID)) 218 | 219 | #define INTERCODEINFO_CREATE_AND_ADD(container, type, paramNum, ...) \ 220 | do{ \ 221 | InterCodeInfo_t interCodeInfo = InterCodeInfo_create(type, paramNum, ##__VA_ARGS__); \ 222 | container->codes[container->codeNum++] = interCodeInfo; \ 223 | }while(0) 224 | 225 | #endif //LAB1_INTERCODEGENERATOR_H 226 | -------------------------------------------------------------------------------- /include/Lab1.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by CrystalVapor on 2024/3/9. 3 | // 4 | 5 | #ifndef LAB1_LAB1_H 6 | #define LAB1_LAB1_H 7 | 8 | //#define DEBUG_PARSER_TREE 9 | 10 | int main(int argc, char** argv); 11 | 12 | #endif //LAB1_LAB1_H 13 | -------------------------------------------------------------------------------- /include/Lab2.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/19. 3 | // 4 | 5 | #ifndef LAB1_LAB2_H 6 | #define LAB1_LAB2_H 7 | 8 | #include "CmmParserTypes.h" 9 | 10 | int main(int argc, char** argv); 11 | 12 | #endif //LAB1_LAB2_H 13 | -------------------------------------------------------------------------------- /include/Lab3.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/31. 3 | // 4 | 5 | #ifndef LAB1_LAB3_H 6 | #define LAB1_LAB3_H 7 | 8 | int main(int argc, char** argv); 9 | 10 | #endif //LAB1_LAB3_H 11 | -------------------------------------------------------------------------------- /include/SemanticAnalyzer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/20. 3 | // 4 | 5 | #ifndef LAB1_SEMANTICANALYZER_H 6 | #define LAB1_SEMANTICANALYZER_H 7 | 8 | struct SymbolTable_s; 9 | typedef struct SymbolTable_s* SymbolTable_t; 10 | 11 | /** 12 | * Analyze the semantic of the parser tree. 13 | * @return the number of semantic errors. 14 | */ 15 | int semanticAnalyze(ParserNode_I rootNodeIndex, SymbolTable_t inSymbolTable); 16 | 17 | /** 18 | * End the semantic analyze, free the memory used by the semantic analyzer. 19 | */ 20 | void semanticAnalyze_End(); 21 | 22 | #endif //LAB1_SEMANTICANALYZER_H 23 | -------------------------------------------------------------------------------- /include/Structure/ParserNodes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by m1504 on 2024/3/19. 3 | // 4 | 5 | /* 6 | * 碎碎念: 7 | * 这里是一开始编写的地方,当时过于迷恋动态内存管理,所以将ParserNode的管理写得很复杂。 8 | * 实际上这里parsernode应该使用保存在数组中的指针而非保存数组索引(不直接保存数组内指针的原因是因为可能realloc后失效) 9 | * (再注:不过由于没有移除节点的需求,似乎可以使用块状链表以避免不断少量申请内存产生的内存碎片,同样也可以安全地保存指针) 10 | * 另外就算如此,parsernode的子节点也应该使用一个C数组而非动态数组。 11 | * 不过懒得改了,将就着用吧( 12 | */ 13 | 14 | #ifndef LAB1_PARSERNODES_H 15 | #define LAB1_PARSERNODES_H 16 | 17 | #include "CmmParserTypes.h" 18 | 19 | #define INVALID_NODE_INDEX (-1) 20 | 21 | #define GET_NODE(nodeIndex) (getParserNode(nodeIndex)) 22 | #define GET_CHILD(nodeIndex, i) (getParserNodeChild(nodeIndex, i)) 23 | #define GET_CHILD_NODE(nodeIndex, i) (GET_NODE(GET_CHILD(nodeIndex, i))) 24 | #define GET_CHILD_NUM(nodeIndex) (getParserNodeChildNum(nodeIndex)) 25 | 26 | //#define DEBUG_PRINT_PARSER_NODE_INDEX 27 | 28 | void setParserTreeRoot(ParserNode_I InRootIndex); 29 | 30 | ParserNode_I getParserTreeRoot(); 31 | 32 | /** 33 | * Create a new parser node in the global node container, will return the index of the new node 34 | * @param symbol the symbol of the node 35 | * @param lineNum the line number of the node 36 | * @param childNum the number of children of the node 37 | * @param children the children of the node 38 | * @param fatherNodeIndex the father node of the node 39 | * @return the index of the new node 40 | */ 41 | ParserNode_I newParserNode(int symbol, int lineNum, int childNum, ParserNode_I *children, ParserNode_I fatherNodeIndex); 42 | 43 | /** 44 | * Add the parser node to the global node container 45 | * @param node the parser node to be added 46 | * @return the index of the new node 47 | */ 48 | int ParserNodeIndexContainer_addNodeIndex(ParserNodeIndexContainer_t container, ParserNode_I index); 49 | 50 | /** 51 | * Get the parser node from the global node container 52 | * @param index the index of the node 53 | * @return the parser node 54 | */ 55 | ParserNode_t getParserNode(ParserNode_I index); 56 | 57 | /** 58 | * Get the child's node index of the parser node 59 | * @param index the index of the father node 60 | * @param childIndex the index of the child(in the children array) 61 | * @return the index of the child's node(in the global node container) 62 | */ 63 | ParserNode_I getParserNodeChild(ParserNode_I index, int childIndex); 64 | 65 | /** 66 | * Get the child's node of the parser node 67 | * @param index the index of the father node 68 | * @param childIndex the index of the child(in the children array) 69 | * @return the child's node 70 | */ 71 | ParserNode_t getParserNodeChildNode(ParserNode_I index, int childIndex); 72 | 73 | /** 74 | * Get the number of children of the parser node 75 | * @param index the index of the node 76 | * @return the number of children 77 | */ 78 | int getParserNodeChildNum(ParserNode_I index); 79 | 80 | /** 81 | * Free the global node container 82 | */ 83 | void freeParserNodes(); 84 | 85 | /** 86 | * Create a new parser node index container 87 | * @return the new parser node index container 88 | */ 89 | ParserNodeIndexContainer_t ParserNodeIndexContainer_createContainer(); 90 | 91 | /** 92 | * Get the parser node from the container 93 | * @param container the container 94 | * @param index the index of the node 95 | * @return the parser node 96 | */ 97 | ParserNode_t ParserNodeIndexContainer_getNode(ParserNodeIndexContainer_t container, int index); 98 | 99 | /** 100 | * Add children to the parser node 101 | * @param nodeIndex the index of the node 102 | * @param childNum the number of children 103 | * @param children the children 104 | */ 105 | void addChildrenToNode(ParserNode_I nodeIndex, int childNum, ParserNode_I* children); 106 | 107 | /** 108 | * Add a child to the parser node 109 | * @param nodeIndex the index of the node 110 | * @param childIndex the index of the child 111 | */ 112 | void addChildToNode(ParserNode_I nodeIndex, ParserNode_I childIndex); 113 | 114 | /** 115 | * Convert a string(HEX,DEC,OCT) to an integer 116 | * @param str the string to be converted 117 | * @return integer converted from the string 118 | */ 119 | int stoi(const char* str); 120 | 121 | /** 122 | * Get the parser node index from the container 123 | * @param container the container 124 | * @param index the index of the node 125 | * @return the parser node index 126 | */ 127 | ParserNode_I ParserNodeIndexContainer_getNodeIndex(ParserNodeIndexContainer_t container, int index); 128 | 129 | /** 130 | * Traverse the parser tree in pre-order and print the tree 131 | * @param nodeIndex the index of the root node 132 | * @param depth the depth of the root node(used for printing) 133 | */ 134 | void printParserTree_PreOrder(ParserNode_I nodeIndex, int depth); 135 | 136 | /** 137 | * Print all the nodes in the global node container linearly 138 | */ 139 | void printAllNodes(); 140 | 141 | /** 142 | * Print the parser node 143 | * @param nodeIndex the index of the node 144 | * @param depth the depth of the node(used for printing) 145 | */ 146 | void printParserNode(ParserNode_I nodeIndex, int depth); 147 | 148 | /** 149 | * do not use. 150 | */ 151 | void yyerror(const char* msg); 152 | 153 | /** 154 | * Check if the children of the node match the rule 155 | * @param nodeIndex the node to be checked 156 | * @param ruleSize the size of rule 157 | * @param ... rule, should be a list of token(Lexical or Syntax) 158 | * @return 1 if match, 0 if not match 159 | */ 160 | int isChildrenMatchRule(ParserNode_I nodeIndex, int ruleSize, ...); 161 | 162 | #endif //LAB1_PARSERNODES_H 163 | -------------------------------------------------------------------------------- /include/Structure/SemanticInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/19. 3 | // 4 | 5 | #ifndef LAB1_SEMANTICINFO_H 6 | #define LAB1_SEMANTICINFO_H 7 | 8 | #include "Structure/SemanticInfo.h" 9 | #include "Structure/SymbolTable.h" 10 | #include "SimpleArray.h" 11 | #include "SymbolTable.h" 12 | 13 | //////////////////////////////////////// 14 | // SemanticInfo 15 | //////////////////////////////////////// 16 | 17 | typedef struct SemanticInfo_s{ 18 | // Rvalue members, following members are only valid when isLValue is false 19 | Symbol_Value_Type valueType; 20 | SymbolInfo_t valueTypeMeta; 21 | 22 | // Semantic information 23 | int isLValue; 24 | 25 | // used for intercode generate 26 | int varID; 27 | }SemanticInfo; 28 | typedef SemanticInfo* SemanticInfo_t; 29 | 30 | /** 31 | * Create a new Lvalue SemanticInfo object 32 | * @note IN Cmm, ALL Lvalue should be Variable 33 | * @param valueType the value type of the LValue 34 | * @param valueInfo the value information of the LValue 35 | * @param semanticInfoList the list to collect recently created semanticInfo, used for garbage collection 36 | * @return a new SemanticInfo object 37 | */ 38 | SemanticInfo_t 39 | SemanticInfo_createLvalue(Symbol_Value_Type valueType, SymbolInfo_t valueInfo, SimpleArray_t semanticInfoList); 40 | 41 | /** 42 | * Create a new Rvalue SemanticInfo object 43 | * @note IN Cmm, ALL Rvalue act like a variable 44 | * @param valueType the value type of the RValue 45 | * @param valueInfo the valueTypeMeta information of the RValue 46 | * @param semanticInfoList the list to collect recently created semanticInfo, used for garbage collection 47 | * @return a new SemanticInfo object 48 | */ 49 | SemanticInfo_t SemanticInfo_createRvalue(Symbol_Value_Type valueType, SymbolInfo_t valueInfo, SimpleArray_t semanticInfoList); 50 | 51 | /** 52 | * Make a semantic variable to a RValue object whether it is a LValue or RValue 53 | * @param lvalue the LValue object 54 | * @param semanticInfoList the list to collect recently created semanticInfo, used for garbage collection 55 | * @return a new RValue object 56 | */ 57 | SemanticInfo_t SemanticInfo_makeRvalue(SemanticInfo_t semanticInfo, SimpleArray_t semanticInfoList); 58 | 59 | /** 60 | * Destroy a SemanticInfo object 61 | * @param semanticInfoToDestroy the SemanticInfo object to be destroyed 62 | */ 63 | void SemanticInfo_destroy(void* semanticInfoToDestroy); 64 | 65 | /** 66 | * Compare two SemanticInfo objects' types 67 | * int => int, float => float 68 | * for struct, if their members are matched(order and type), they are matched 69 | * for array, if their element type and dimension count are matched, they are matched 70 | * @param a the first SemanticInfo object 71 | * @param b the second SemanticInfo object 72 | * @return 1 if the two objects are matched, 0 otherwise 73 | */ 74 | int SemanticInfo_isTypeMatched(SemanticInfo_t a, SemanticInfo_t b); 75 | 76 | /** 77 | * Check if the given two FunctionInfo have the same return type 78 | * @param a the first FunctionInfo 79 | * @param b the second FunctionInfo 80 | * @return 1 if the two FunctionInfo have the same return type, 0 otherwise 81 | */ 82 | int SymbolInfo_Function_isReturnTypeMatched(SymbolInfo_Function_t a, SymbolInfo_Function_t b); 83 | 84 | /** 85 | * Check if the given two FunctionInfo have the same parameter list 86 | * @param a the first FunctionInfo 87 | * @param b the second FunctionInfo 88 | * @return 1 if the two FunctionInfo have the same parameter list, 0 otherwise 89 | */ 90 | int SymbolInfo_Function_isParameterListMatched(SymbolInfo_Function_t a, SymbolInfo_Function_t b); 91 | 92 | /** 93 | * Check if the given semanticInfo is the same as the given type(whether it is a RValue or LValue) 94 | * @param semanticInfo the semanticInfo to be checked 95 | * @param type the type to be checked 96 | * @return 1 if the semanticInfo is the same as the given type, 0 otherwise 97 | */ 98 | int SemanticInfo_checkValueType(SemanticInfo_t semanticInfo, Symbol_Value_Type type); 99 | 100 | /** 101 | * Check if the value of semanticInfo matched the return type of the functionInfo 102 | * @param functionInfo the functionInfo to be checked 103 | * @param semanticInfo the semanticInfo to be checked 104 | * @return 1 if the value of semanticInfo matched the return type of the functionInfo, 0 otherwise 105 | */ 106 | int SemanticInfo_checkReturnType(SymbolInfo_Function_t functionInfo, SemanticInfo_t semanticInfo); 107 | 108 | /** 109 | * Check if the parameter list of the functionInfo matched the given semanticInfos 110 | * @param functionInfo the functionInfo to be checked 111 | * @param semanticInfos the semanticInfos to be checked 112 | * @param paramCount the count of the semanticInfos 113 | * @return 1 if the parameter list of the functionInfo matched the given semanticInfos, 0 otherwise 114 | */ 115 | int SemanticInfo_checkParameterList(SymbolInfo_Function_t functionInfo, SemanticInfo_t* semanticInfos, int paramCount); 116 | 117 | /** 118 | * Try to get the memberInfo from the given semanticInfo 119 | * @param semanticInfo the semanticInfo to get from 120 | * @param memberName the member name 121 | * @return the memberInfo, NULL if failed 122 | */ 123 | SymbolInfo_Member_t SemanticInfo_getMemberInfo(SemanticInfo_t semanticInfo, const char* memberName); 124 | 125 | /** 126 | * Helper Function to check if the two types are matched 127 | * @param aType type of a 128 | * @param aMeta type meta of a 129 | * @param bType type of b 130 | * @param bMeta type meta of b 131 | * @return 1 if matched, 0 otherwise 132 | */ 133 | int SymbolInfo_Helper_isTypeMatched(Symbol_Value_Type aType, SymbolInfo_t aMeta, Symbol_Value_Type bType, SymbolInfo_t bMeta); 134 | 135 | #endif //LAB1_SEMANTICINFO_H 136 | -------------------------------------------------------------------------------- /include/Structure/SimpleArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/17. 3 | // 4 | 5 | #ifndef LAB1_SIMPLEARRAY_H 6 | #define LAB1_SIMPLEARRAY_H 7 | 8 | #define DEFAULT_CAPACITY 100 9 | 10 | typedef void (*Destructor)(void*); 11 | 12 | struct SimpleArray_s{ 13 | char* data; 14 | int num; 15 | int capacity; 16 | int typeSize; 17 | }; 18 | typedef struct SimpleArray_s* SimpleArray_t; 19 | typedef struct SimpleArray_s SimpleArray; 20 | 21 | /** 22 | * Create a new simple array, the typeSize is the size of the type of the element 23 | * @param typeSize size of the type of the element 24 | * @return created simple array 25 | */ 26 | SimpleArray_t SimpleArray_create(int typeSize); 27 | 28 | /** 29 | * Create a new simple array with capacity, the typeSize is the size of the type of the element 30 | * @param typeSize size of the type of the element 31 | * @param capacity capacity of the array 32 | * @return created simple array 33 | */ 34 | SimpleArray_t SimpleArray_newArrayWithCapacity(int typeSize, int capacity); 35 | 36 | /** 37 | * Add an element to the simple array's tail, will copy the content of the element to the array 38 | * @param array the simple array 39 | * @param element the element to add 40 | * @return the index of the added element 41 | */ 42 | int SimpleArray_addElement(SimpleArray_t array, const void* element); 43 | 44 | /** 45 | * Get the element at the index, will check if the index is valid 46 | * do not save the pointer of the element, it may be invalid after the array is modified 47 | * @param array the simple array 48 | * @param index the index of the element 49 | * @return the element at the index 50 | */ 51 | void* SimpleArray_at(SimpleArray_t array, int index); 52 | 53 | /** Free the simple array with destructor, will free the memory of the array and the elements 54 | * Destructor: void(void* pointer_to_the_element) 55 | * @param array the simple array 56 | * @param elementDestructor the destructor of the element, if it's NULL, will not call the destructor 57 | */ 58 | void SimpleArray_destroy(SimpleArray_t array, Destructor elementDestructor); 59 | 60 | /** 61 | * Reserve the capacity of the simple array, will change the capacity of the array 62 | * @param array the simple array 63 | * @param capacity the new capacity of the array 64 | */ 65 | void SimpleArray_reserve(SimpleArray_t array, int capacity); 66 | 67 | /** 68 | * Set the element at the index, will copy the content of the element to the array 69 | * @param array the simple array 70 | * @param index the index of the element 71 | * @param element the element to set 72 | */ 73 | void SimpleArray_setElement(SimpleArray_t array, int index, const void* element); 74 | 75 | /** 76 | * Insert an element to the simple array at the index, will move the elements after the index 77 | * @param array the simple array 78 | * @param index the index to insert 79 | * @param element the element to insert 80 | */ 81 | void SimpleArray_insertElement(SimpleArray_t array, int index, void* element); 82 | 83 | /** Remove the element at the index with destructor if it's not NULL, will move the elements after the index 84 | * Destructor: void(void* pointer_to_the_element) 85 | * @param array the simple array 86 | * @param index the index to remove 87 | * @param elementDestructor the destructor of the element, if it's NULL, will not call the destructor 88 | */ 89 | void SimpleArray_removeElement(SimpleArray_t array, int index, Destructor elementDestructor); 90 | 91 | /** 92 | * Clear the simple array with destructor, will free the memory of the elements 93 | * Destructor: void(void* pointer_to_the_element) 94 | * @param array the simple array 95 | */ 96 | void SimpleArray_clear(SimpleArray_t array); 97 | 98 | /** Resize the simple array, will change the capacity and the size of the array 99 | * be aware that the elements between old size and new size will be random 100 | * @param array the simple array 101 | * @param newSize the new size of the array 102 | */ 103 | void SimpleArray_resize(SimpleArray_t array, int newSize); 104 | 105 | /** 106 | * Zero fill the simple array, will fill the array with 0 107 | * @param array the simple array 108 | */ 109 | void SimpleArray_zeroFilled(SimpleArray_t array); 110 | 111 | /** pop the element at the back of the simple array with destructor if it's not NULL 112 | * Destructor: void(void* pointer_to_the_element) 113 | * @param array the simple array 114 | * @param elementDestructor the destructor of the element, if it's NULL, will not call the destructor 115 | */ 116 | void SimpleArray_popBack(SimpleArray_t array, Destructor elementDestructor); 117 | 118 | /** Push an element to the back of the simple array, will copy the content of the element to the array 119 | * Same as addElement, just an alias of it. 120 | * @param array the simple array 121 | * @param element the element to push 122 | * @return the index of the pushed element 123 | */ 124 | int SimpleArray_pushBack(SimpleArray_t array, void* element); 125 | 126 | /** 127 | * Get the element at the back of the simple array 128 | * @param array the simple array 129 | * @return the element at the back 130 | */ 131 | void* SimpleArray_back(SimpleArray_t array); 132 | 133 | /** Get the size of the simple array 134 | * @param array the simple array 135 | * @return the size of the array 136 | */ 137 | int SimpleArray_size(SimpleArray_t array); 138 | 139 | #endif //LAB1_SIMPLEARRAY_H 140 | -------------------------------------------------------------------------------- /include/Structure/SimpleHashTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by m1504 on 2024/3/20. 3 | // 4 | 5 | #ifndef LAB1_SIMPLEHASHTABLE_H 6 | #define LAB1_SIMPLEHASHTABLE_H 7 | 8 | #include "Structure/SimpleHashTable.h" 9 | #include 10 | #include 11 | #include "SimpleArray.h" 12 | 13 | #define THOUSAND_HASH_TABLE_SIZE 1009 14 | #define DEFAULT_HASH_BUCKET_SIZE 10 15 | struct SimpleHashTable_s; 16 | typedef struct SimpleHashTable_s * SimpleHashTable_t; 17 | 18 | /** 19 | * A hash function that takes a key and returns a hash value. 20 | * @param key the key to be hashed 21 | * @param keySize the size of the key 22 | * @param tableSize the size of the hash table 23 | * @return the hash value of the key 24 | */ 25 | typedef int (*HashFunc)(const void* key, int keySize, int tableSize); 26 | 27 | /** 28 | * A compare function that takes two keys and returns 0 if they are the same. 29 | * @param keyA the first key 30 | * @param keyB the second key 31 | * @param keySize the size of the key 32 | * @return 0 if the two keys are the same, otherwise return a non-zero value 33 | */ 34 | typedef int (*CompareFunc)(const void* keyA, const void* keyB, int keySize); 35 | 36 | /** 37 | * A Traverse function that takes an element and do something with it. 38 | * @param element the element to be traversed 39 | */ 40 | typedef void (*TraverseFunc)(const void* element); 41 | 42 | /** 43 | * An advanced traverse function that takes a key, an element and extra parameters and do something with them. 44 | * @param key the key of the element 45 | * @param keySize the size of the key 46 | * @param element the element to be traversed 47 | * @param extraParamCount the number of extra parameters 48 | * @param ... the extra parameters 49 | */ 50 | typedef void (*AdvancedTraverseFunc)(const void* key, int keySize, const void* element, int extraParamCount, ...); 51 | 52 | typedef struct SimpleHashTablePair_s { 53 | void* key; 54 | int keySize; 55 | void* element; 56 | }SimpleHashTablePair; 57 | typedef SimpleHashTablePair* SimpleHashTablePair_t; 58 | 59 | typedef struct SimpleHashTable_s{ 60 | HashFunc hashFunc; 61 | CompareFunc compareFunc; 62 | SimpleArray_t data; 63 | int elementSize; 64 | int keySize; 65 | int tableSize; 66 | }SimpleHashTable; 67 | typedef SimpleHashTable* SimpleHashTable_t; 68 | 69 | /** 70 | * Create a hash table with the given element size, hash function and compare function, default table size is THOUSAND_HASH_TABLE_SIZE 71 | * @param elementSize the size of the element 72 | * @param hashFunc the hash function, use NULL to use the default hash function(pjw) 73 | * @param compareFunc the compare function, use NULL to use the default compare function(memcmp) 74 | * @return the created hash table 75 | */ 76 | SimpleHashTable_t SimpleHashTable_createHashTable(int elementSize, HashFunc hashFunc, CompareFunc compareFunc); 77 | 78 | /** 79 | * Create a hash table with the given element size, hash function, compare function and table size 80 | * @param elementSize the size of the element 81 | * @param keyHashFunc the hash function for the key, use NULL to use the default hash function(pjw) 82 | * @param keyCompareFunc the compare function for the key, use NULL to use the default compare function(memcmp) 83 | * @param tableSize the size of the hash table 84 | * @return the created hash table 85 | */ 86 | SimpleHashTable_t SimpleHashTable_createWithSize(int elementSize, HashFunc keyHashFunc, CompareFunc keyCompareFunc, int tableSize); 87 | 88 | /** 89 | * Destroy the hash table, and call the destructor on every element if it is not NULL 90 | * @param hashTable the hash table to be destroyed 91 | * @param destructorForKey the destructor for the key, use NULL if no destructor is needed 92 | * @param destructorForElement the destructor for the element, use NULL if no destructor is needed 93 | */ 94 | void SimpleHashTable_destroy(SimpleHashTable_t hashTable, Destructor destructorForKey, Destructor destructorForElement); 95 | 96 | /** 97 | * Force insert the element with the key, and call the destructor if the key already exists and it is not NULL 98 | * @param hashTable table to insert 99 | * @param key key to insert 100 | * @param keySize size of the key 101 | * @param element element to insert 102 | * @param destructorForKey destructor for the key 103 | * @param destructorForElement destructor for the element 104 | */ 105 | void SimpleHashTable_forceInsert(SimpleHashTable_t hashTable, const void* key, int keySize, const void* element, Destructor destructorForKey, Destructor destructorForElement); 106 | 107 | /** 108 | * Insert the element with the key, will not insert if the key already exists 109 | * @param hashTable the hash table to insert 110 | * @param key the key to insert 111 | * @param keySize the size of the key 112 | * @param element the element to insert 113 | * @return 0 if the element is inserted successfully, -1 if the key already exists 114 | */ 115 | int SimpleHashTable_insert(SimpleHashTable_t hashTable, const void* key, int keySize, const void* element); 116 | 117 | /** 118 | * Find the element with the key 119 | * @param hashTable the hash table to find 120 | * @param key the key to find 121 | * @param keySize the size of the key 122 | * @return the element with the key, NULL if the key does not exist 123 | */ 124 | void* SimpleHashTable_find(SimpleHashTable_t hashTable, const void* key, int keySize); 125 | 126 | /** 127 | * Remove the element with the key, and call the destructor if it is not NULL 128 | * @param hashTable the hash table to remove 129 | * @param key the key to remove 130 | * @param keySize the size of the key 131 | * @param destructorForKey the destructor for the key, use NULL if no destructor is needed 132 | * @param destructorForElement the destructor for the element, use NULL if no destructor is needed 133 | */ 134 | void SimpleHashTable_remove(SimpleHashTable_t hashTable, const void* key, int keySize, Destructor destructorForKey, Destructor destructorForElement); 135 | 136 | /** 137 | * Traverse the hash table and call the traverse function on every element 138 | * @param hashTable the hash table to traverse 139 | * @param traverseFunc the traverse function 140 | */ 141 | void SimpleHashTable_traverse(SimpleHashTable_t hashTable, TraverseFunc traverseFunc); 142 | 143 | /** 144 | * Traverse the hash table and call the advanced traverse function on every element 145 | * @param hashTable the hash table to traverse 146 | * @param traverseFunc the advanced traverse function 147 | * @param extraParamCount the number of extra parameters 148 | * @param ... the extra parameters 149 | */ 150 | void SimpleHashTable_advancedTraverse(SimpleHashTable_t hashTable, AdvancedTraverseFunc traverseFunc, int extraParamCount, ...); 151 | 152 | /** 153 | * Default hash function, use PJW hash algorithm 154 | * @param key the key to be hashed 155 | * @param keySize the size of the key 156 | * @param size the size of the hash table 157 | * @return the hash value of the key 158 | */ 159 | int pjwHash(const char* key, int keySize, int size); 160 | 161 | #endif //LAB1_SIMPLEHASHTABLE_H 162 | -------------------------------------------------------------------------------- /include/Structure/SimpleList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/4/3. 3 | // 4 | 5 | #ifndef LAB1_SIMPLELIST_H 6 | #define LAB1_SIMPLELIST_H 7 | 8 | typedef struct SimpleListNode_s { 9 | struct SimpleListNode_s *next; 10 | struct SimpleListNode_s *prev; 11 | void *data; 12 | }SimpleListNode; 13 | typedef struct SimpleListNode_s* SimpleListNode_t; 14 | 15 | typedef struct SimpleList_s{ 16 | SimpleListNode_t head; 17 | SimpleListNode_t tail; 18 | int size; 19 | }SimpleList; 20 | typedef struct SimpleList_s* SimpleList_t; 21 | 22 | /** 23 | * Create an empty list 24 | * @return new list 25 | */ 26 | SimpleList_t SimpleList_create(); 27 | 28 | /** 29 | * Destroy a list 30 | * @param list list to destroy 31 | * @param destroyData function to destroy data 32 | * @return NULL 33 | */ 34 | SimpleList_t SimpleList_destroy(SimpleList_t list, void (*destroyData)(void* data)); 35 | 36 | /** 37 | * Push data to the back of the list, will create a new node 38 | * @param list list to push 39 | * @param data data to push 40 | * @return new node 41 | */ 42 | SimpleListNode_t SimpleList_push_back(SimpleList_t list, void* data); 43 | 44 | /** 45 | * Push data to the front of the list, will create a new node 46 | * @param list list to push 47 | * @param data data to push 48 | * @return new node 49 | */ 50 | SimpleListNode_t SimpleList_push_front(SimpleList_t list, void* data); 51 | 52 | /** 53 | * Pop the last node of the list 54 | * @param list 55 | * @return the data of the last node 56 | */ 57 | void* SimpleList_pop_back(SimpleList_t list); 58 | 59 | /** 60 | * Pop the first node of the list 61 | * @param list 62 | * @return the data of the first node 63 | */ 64 | void* SimpleList_pop_front(SimpleList_t list); 65 | 66 | /** 67 | * Insert data to the list before the given position 68 | * @param list list to insert 69 | * @param pos position to insert 70 | * @param data data to insert 71 | */ 72 | void SimpleList_insertBefore(SimpleList_t list, SimpleListNode_t pos, void* data); 73 | 74 | /** 75 | * Insert data to the list after the given position 76 | * @param list list to insert 77 | * @param pos position to insert 78 | * @param data data to insert 79 | */ 80 | void SimpleList_insertAfter(SimpleList_t list, SimpleListNode_t pos, void* data); 81 | 82 | /** 83 | * Append list2 to list1 84 | * do not use list2 or list1 after this operation, it's not safe 85 | * only returned list is considered valid 86 | * @param list1 87 | * @param list2 88 | * @return appended list1 89 | */ 90 | SimpleList_t SimpleList_append(SimpleList_t list1, SimpleList_t list2); 91 | #endif //LAB1_SIMPLELIST_H 92 | -------------------------------------------------------------------------------- /include/Structure/SymbolTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/19. 3 | // 4 | 5 | /** 碎碎念: 6 | * 我是个傻逼 7 | * 符号创建流程中设计了一套从raw到baked的转换,也就是从拿到struct名称到拿到struct信息的转换 8 | * 我以为这样能方便struct变量、struct数组、嵌套struct的创建 9 | * 然而tmd到了现在我才发现,这个设计是多余的 10 | * 在创建相关符号的时候一定是先查表拿到了struct信息才能创建的 11 | * 根本不需要脱裤子放屁地先创建一个raw再bake 12 | * 就算是前置声明也肯定是先创建一个空的baked丢进符号表,这个流程里完全没有structname的事 13 | * 艹!这个b流程从设计到编写到debug花了我两天 14 | * 我是个傻逼 15 | * 现在还得回头再搭一套基于全程bakedmeta的流程 16 | * 虽说不改也不是不能用,可以直接从struct那里提一个rawmeta出来,但性能浪费我就不说了 17 | * 还是码吧,但我tm现在已经不想玩了 18 | * 艹 19 | * 我是个傻逼 20 | * Crystal 2024/3/27 11:50 21 | */ 22 | 23 | /* 24 | * 为了后续翻找方便,相关弃用方法已移除。 25 | * Crystal 2024/4/6 12:00 26 | */ 27 | 28 | #ifndef LAB1_SYMBOLTABLE_H 29 | #define LAB1_SYMBOLTABLE_H 30 | 31 | #include "SimpleArray.h" 32 | #include "SimpleHashTable.h" 33 | 34 | #define INVALID_VAR_ID (-1) 35 | #define INVALID_LABEL_ID (-1) 36 | 37 | //////////////////////////////////////// 38 | // Enums for SymbolRecord 39 | //////////////////////////////////////// 40 | 41 | /** 42 | * The status of the symbol. 43 | */ 44 | typedef enum SymbolDefineStatus_e { 45 | SDS_Undefined = -1, // A symbol is not declared 46 | SDS_Declared = 0, // A symbol is declared but not defined 47 | SDS_ExternalDeclared = 1, // A symbol is declared and defined in other nextScopeID 48 | SDS_ExternalDefined = 2, // A symbol is defined and usable in current nextScopeID 49 | SDS_Defined = 3, // A symbol is declared in other nextScopeID 50 | } SymbolDefineStatus; 51 | 52 | /** 53 | * The type of the symbol. 54 | */ 55 | typedef enum SymbolType_e { 56 | ST_Variable = 0b00, 57 | ST_Function = 0b01, 58 | ST_Struct = 0b10, 59 | } SymbolType; 60 | 61 | //////////////////////////////////////// 62 | // Types for Symbol's value 63 | //////////////////////////////////////// 64 | 65 | /** 66 | * The type of the symbol value. 67 | */ 68 | typedef enum Symbol_Value_Type_e { 69 | SVT_Int = 0b00, 70 | SVT_Float = 0b01, 71 | SVT_Struct = 0b10, 72 | SVT_Array = 0b11, 73 | SVT_Void = 0b100, 74 | } Symbol_Value_Type; 75 | 76 | /** 77 | * The size of the symbol value. 78 | */ 79 | int SymbolValue_getSize(Symbol_Value_Type type, void *meta); 80 | 81 | //////////////////////////////////////// 82 | ///SymbolRecord 83 | //////////////////////////////////////// 84 | 85 | typedef void* SymbolInfo_t; 86 | 87 | typedef struct { 88 | SymbolType type; 89 | SymbolInfo_t info; 90 | } SymbolRecord; 91 | typedef SymbolRecord* SymbolRecord_t; 92 | 93 | void SymbolRecord_destroy(void* record); 94 | void SymbolRecord_printDebug(SymbolRecord_t record, char* buffer, int bufferSize); 95 | 96 | //////////////////////////////////////// 97 | /// SymbolTable 98 | //////////////////////////////////////// 99 | 100 | #define INVALID_SCOPE (-1) 101 | 102 | typedef struct SymbolTable_s { 103 | SimpleHashTable_t table; // hash table for symbol records, key is full name of symbol, records stored as flat struct SymbolRecord 104 | int nextScopeID; // next scope ID that will be used 105 | SimpleArray_t scopeStack; // stack of scope IDs 106 | int currentScope; // current scopeID that is being used 107 | int nextVarID; // next variable ID that will be used 108 | int nextLabelID; // next label ID that will be used 109 | } SymbolTable; 110 | typedef SymbolTable* SymbolTable_t; 111 | 112 | /** 113 | * Create a symbol table. 114 | * @return The symbol table. 115 | */ 116 | SymbolTable_t SymbolTable_create(); 117 | 118 | /** 119 | * Destroy a symbol table. 120 | * @param table The symbol table. 121 | */ 122 | void SymbolTable_destroy(void* table); 123 | 124 | /** 125 | * Enter a new scope, will get a new scope ID and update prefix. 126 | * prefix is always same as the top of the scope stack. 127 | * @param table The symbol table. 128 | */ 129 | void SymbolTable_enterScope(SymbolTable_t table); 130 | 131 | /** 132 | * Leave current scope, will pop an ID from ID stack and update prefix. 133 | * prefix is always same as the top of the scope stack. 134 | * @param table The symbol table. 135 | */ 136 | void SymbolTable_leaveScope(SymbolTable_t table); 137 | 138 | /** 139 | * Get the current scope. 140 | * @param table The symbol table. 141 | * @return The current scope. 142 | */ 143 | int SymbolTable_getScope(SymbolTable_t table); 144 | 145 | /** 146 | * Generate a new name with the current nextScopeID prefix in input buffer. 147 | * @param table The symbol table. 148 | * @param name The name. 149 | * @return The name without the nextScopeID prefix(a pointer to the middle of buffer). 150 | */ 151 | void SymbolTable_generateName(SymbolTable_t table, char* name, char* buffer, int bufferSize); 152 | 153 | /** 154 | * Lookup a symbol in the symbol table. 155 | * @param table The symbol table. 156 | * @param name The name of the symbol. 157 | * @param outRecord The output record. 158 | * @return The status of the symbol. 159 | */ 160 | SymbolDefineStatus SymbolTable_lookupRecord(SymbolTable_t table, char* name, SymbolRecord_t* outRecord); 161 | 162 | /** 163 | * Lookup a symbol in the symbol table. 164 | * @param table The symbol table. 165 | * @param name The name of the symbol. 166 | * @param outRecord The output record. 167 | * @return index of the nextScopeID where the symbol is found, -1 if not found. 168 | */ 169 | int SymbolTable_internalLookupRecord(SymbolTable_t table, char* name, SymbolRecord_t* outRecord); 170 | 171 | /** 172 | * Lookup a symbol in the symbol table in the specific scope. 173 | * @param table The symbol table. 174 | * @param name The name of the symbol. 175 | * @param scope The scope to search. 176 | * @param outRecord The output record. 177 | * @return The status of the symbol. 178 | */ 179 | SymbolDefineStatus SymbolTable_lookupRecordInScope(SymbolTable_t table, char* name, int scope, SymbolRecord_t* outRecord); 180 | 181 | /** 182 | * Insert a symbol into the symbol table, content will be copied. 183 | * @param table The symbol table. 184 | * @param name The name of the symbol, will be duplicated. 185 | * @param record The record. 186 | * @return 0 if success, -1 if failed. 187 | */ 188 | int SymbolTable_insertRecord(SymbolTable_t table, char* name, SymbolRecord_t record); 189 | 190 | /** 191 | * Creates a blank variable record with valid function info, the meta need to be well-baked. 192 | * will also allocate a new variable ID for the variable. 193 | * ID can be accessed by SymbolRecord->info->varID 194 | * @param table The symbol table 195 | * @param outRecord The output record, should be a pointer to valid memory of SymbolRecord 196 | * @param info The meta data of the variable 197 | * @return SE_Success if success, failed otherwise 198 | */ 199 | void SymbolTable_createVariableByInfo(SymbolTable_t table, SymbolRecord *outRecord, SymbolInfo_t info); 200 | 201 | /** 202 | * Creates a blank function record with valid function info, the meta need to be well-baked. 203 | * @param table The symbol table 204 | * @param outRecord The output record, should be a pointer to valid memory of SymbolRecord 205 | * @param info The meta data of the function 206 | * @return SE_Success if success, failed otherwise 207 | */ 208 | void SymbolTable_createFunctionByInfo(SymbolTable_t table, SymbolRecord *outRecord, SymbolInfo_t info); 209 | 210 | /** 211 | * Creates a blank struct record with valid struct info, the meta need to be well-baked. 212 | * @param table The symbol table 213 | * @param outRecord The output record, should be a pointer to valid memory of SymbolRecord 214 | * @param info The meta data of the struct 215 | * @return SE_Success if success, failed otherwise 216 | */ 217 | void SymbolTable_createStructByInfo(SymbolTable_t table, SymbolRecord *outRecord, SymbolInfo_t info); 218 | 219 | /** 220 | * Generate a new variable ID. 221 | * @param table The symbol table. 222 | * @return The new variable ID. 223 | */ 224 | int SymbolTable_getNextVarID(SymbolTable_t table); 225 | 226 | /** 227 | * Generate a new label name [ label$[ID]] ] 228 | * @param table The symbol table. 229 | * @param buffer The buffer to store the label name. 230 | * @param bufferSize The size of the buffer. 231 | */ 232 | void SymbolTable_generateNextLabelName(SymbolTable_t table, char* buffer, int bufferSize); 233 | 234 | /** 235 | * Generate a new label name with suffix [ label$[ID][suffix] ] 236 | * @param table The symbol table. 237 | * @param buffer The buffer to store the label name. 238 | * @param bufferSize The size of the buffer. 239 | * @param suffix The suffix to append to the label name. 240 | */ 241 | void SymbolTable_generateNextLabelNameWithSuffix(SymbolTable_t table, char* buffer, int bufferSize, char* suffix); 242 | 243 | //////////////////////////////////////// 244 | /// SymbolInfo 245 | //////////////////////////////////////// 246 | 247 | typedef struct { 248 | Symbol_Value_Type type; 249 | SymbolInfo_t meta; 250 | int varID; 251 | } SymbolInfo_Variable; 252 | typedef SymbolInfo_Variable* SymbolInfo_Variable_t; 253 | typedef SymbolInfo_Variable* SymbolInfo_Variable_Raw; 254 | 255 | /** 256 | * Create a new baked SymbolInfo_Variable with baked meta info. 257 | * @param type The type of the variable. 258 | * @param meta The baked meta data of the variable. 259 | * @return The baked SymbolInfo_Variable. 260 | */ 261 | SymbolInfo_Variable_t SymbolInfo_Variable_createBaked(Symbol_Value_Type type, SymbolInfo_t meta); 262 | 263 | /** 264 | * Destroy the baked SymbolInfo_Variable. 265 | * @param info The baked SymbolInfo_Variable. 266 | */ 267 | void SymbolInfo_Variable_destroy(SymbolInfo_Variable_t info); 268 | 269 | typedef struct { 270 | Symbol_Value_Type elementType; 271 | SymbolInfo_t elementMeta; 272 | int dimensionCount; 273 | int dimension; 274 | } SymbolInfo_Array; 275 | typedef SymbolInfo_Array* SymbolInfo_Array_t; 276 | typedef SymbolInfo_Array* SymbolInfo_Array_Raw; 277 | 278 | /** 279 | * Create a new baked SymbolInfo_Array with baked element struct info. 280 | * @param elementType The type of the elements in the array. 281 | * @param elementStructInfo The struct info of the elements in the array. 282 | * @param dimensions The dimensions and its length of the array, -1 if it is not fixed. 283 | * @param dimensionCount The count of the dimensions. 284 | * @return The raw SymbolInfo_Array. 285 | */ 286 | SymbolInfo_Array_t SymbolInfo_Array_createBaked(Symbol_Value_Type elementType, SymbolInfo_t elementStructInfo, int dimensions[], int dimensionCount); 287 | 288 | /** 289 | * Destroy the baked SymbolInfo_Array. 290 | * @param info The baked SymbolInfo_Array. 291 | */ 292 | void SymbolInfo_Array_destroy(SymbolInfo_Array_t info); 293 | 294 | typedef struct { 295 | Symbol_Value_Type returnType; 296 | SymbolInfo_t returnTypeMeta; 297 | char* functionName; 298 | int parameterCount; 299 | SymbolInfo_t* parameters; 300 | int isDefined; 301 | int firstDeclaredLine; 302 | } SymbolInfo_Function; 303 | typedef SymbolInfo_Function* SymbolInfo_Function_t; 304 | typedef SymbolInfo_Function* SymbolInfo_Function_Raw; 305 | 306 | /** 307 | * Create a new baked SymbolInfo_Function with baked meta info. 308 | * @param returnType The return type of the function, SVT_Void for void. 309 | * @param returnTypeMeta The baked meta data of the return type. 310 | * @param parameterTypes An array of parameter types, length must match the parameterCount. 311 | * @param parameterNames An array of parameter names, length must match the parameterCount, all content will be duplicated. 312 | * @param parametersMeta An array of baked parameter metadata, length must match the parameterCount. 313 | * NULL if the parameter is not a struct or an array. 314 | * baked SymbolInfo_Struct_t if the parameter is a struct. 315 | * baked SymbolInfo_Array_t if the parameter is an array. 316 | * @param parameterCount 317 | * @return 318 | */ 319 | SymbolInfo_Function_t 320 | SymbolInfo_Function_createBaked(Symbol_Value_Type returnType, SymbolInfo_t returnTypeMeta, Symbol_Value_Type parameterTypes[], 321 | char *parameterNames[], void *parametersMeta[], int parameterCount); 322 | 323 | /** 324 | * Destroy the baked SymbolInfo_Function. 325 | * @param info The baked SymbolInfo_Function. 326 | */ 327 | void SymbolInfo_Function_destroy(SymbolInfo_Function_t info); 328 | 329 | int SymbolInfo_Function_hasParameterName(SymbolInfo_Function_t functionInfo, char* parameterName); 330 | 331 | void SymbolInfo_Function_addParameter(SymbolInfo_Function_t functionInfo, SymbolInfo_t parameter); 332 | /** 333 | * Get the name of the function. 334 | * @param info The baked SymbolInfo_Function. 335 | * @return The name of the function. 336 | */ 337 | char* SymbolInfo_Function_getName(SymbolInfo_Function_t info); 338 | 339 | /** 340 | * Set the name of the function. 341 | * @param info The baked SymbolInfo_Function. 342 | * @param name The name of the function, will be duplicated. 343 | */ 344 | void SymbolInfo_Function_setName(SymbolInfo_Function_t info, char* name); 345 | 346 | typedef struct { 347 | Symbol_Value_Type parameterType; 348 | char* parameterName; 349 | SymbolInfo_t parameterMeta; 350 | } SymbolInfo_Parameter; 351 | typedef SymbolInfo_Parameter* SymbolInfo_Parameter_t; 352 | typedef SymbolInfo_Parameter* SymbolInfo_Parameter_Raw; 353 | 354 | /** 355 | * Create a new baked SymbolInfo_Parameter with baked meta info. 356 | * @param type The type of the parameter. 357 | * @param parameterName The name of the parameter, will be duplicated if not NULL. 358 | * @param meta The baked meta data of the parameter. 359 | * NULL if the parameter is not a struct or an array. 360 | * baked SymbolInfo_Struct_t if the parameter is a struct. 361 | * baked SymbolInfo_Array_t if the parameter is an array. 362 | * @return The baked SymbolInfo_Parameter. 363 | */ 364 | SymbolInfo_Parameter_t SymbolInfo_Parameter_createBaked(Symbol_Value_Type type, char* parameterName, SymbolInfo_t meta); 365 | 366 | typedef struct { 367 | #ifdef SYMBOL_TABLE_STRUCT_NAME 368 | char* structName; 369 | #endif 370 | int memberCount; 371 | SymbolInfo_t* members; 372 | int size; 373 | } SymbolInfo_Struct; 374 | typedef SymbolInfo_Struct* SymbolInfo_Struct_t; 375 | typedef SymbolInfo_Struct* SymbolInfo_Struct_Raw; 376 | 377 | /** 378 | * Create a new baked SymbolInfo_Struct with baked meta info. 379 | * @param memberTypes An array of member types, length must match the memberCount. 380 | * @param memberNames An array of member names, length must match the memberCount, all content will be duplicated, memberName cannot be NULL. 381 | * @param memberMeta An array of member metadata. 382 | * NULL if the member is not a struct or an array. 383 | * baked SymbolInfo_Struct_t if the member is a struct. 384 | * baked SymbolInfo_Array_t if the member is an array. 385 | * @param memberCount The count of the members. 386 | * @return baked SymbolInfo_Struct_t if success, NULL if failed. 387 | */ 388 | SymbolInfo_Struct_t 389 | SymbolInfo_Struct_createBaked(Symbol_Value_Type *memberTypes, char **memberNames, void **memberMeta, int memberCount); 390 | 391 | /** Destroy the baked SymbolInfo_Struct. 392 | * @param info The baked SymbolInfo_Struct. 393 | */ 394 | void SymbolInfo_Struct_destroy(SymbolInfo_Struct_t info); 395 | 396 | int SymbolInfo_Struct_checkMemberName(SymbolInfo_Struct_t info, char* memberName); 397 | 398 | /** 399 | * Insert a member into the struct. 400 | * @param info The baked SymbolInfo_Struct. 401 | * @param memberInfo The member info. 402 | */ 403 | void SymbolInfo_Struct_insertMember(SymbolInfo_Struct_t info, SymbolInfo_t memberInfo); 404 | 405 | #ifdef SYMBOL_TABLE_STRUCT_NAME 406 | /** 407 | * Get the name of the struct. 408 | * @param info The baked SymbolInfo_Struct. 409 | * @return The name of the struct. 410 | */ 411 | char* SymbolInfo_Struct_getName(SymbolInfo_Struct_t info); 412 | /** 413 | * Set the name of the struct. 414 | * @param info The baked SymbolInfo_Struct. 415 | * @param name The name of the struct, will be duplicated. 416 | */ 417 | void SymbolInfo_Struct_setName(SymbolInfo_Struct_t info, char* name); 418 | #endif 419 | 420 | typedef struct { 421 | Symbol_Value_Type memberType; 422 | SymbolInfo_t memberMeta; 423 | char* memberName; 424 | int offset; 425 | } SymbolInfo_Member; 426 | typedef SymbolInfo_Member* SymbolInfo_Member_t; 427 | typedef SymbolInfo_Member* SymbolInfo_Member_Raw; 428 | /** 429 | * Create a new SymbolInfo_Member. 430 | * @param memberType The type of the member. 431 | * @param memberName The name of the member, will be duplicated. 432 | * @param memberMeta The meta data of the member. 433 | * NULL if the member is not a struct or an array. 434 | * char[] if the member is a struct, represent the name of the struct without the nextScopeID prefix. 435 | * SymbolInfo_Array_t (create by SymbolInfo_Array_create, **need to be raw**) if the member is an array. 436 | * @return The raw SymbolInfo_Member. 437 | * @see SymbolInfo_Array_create 438 | */ 439 | SymbolInfo_Member_Raw SymbolInfo_Member_create(Symbol_Value_Type memberType, char* memberName, void* memberMeta); 440 | 441 | /** 442 | * Create a new baked SymbolInfo_Member with baked meta info. 443 | * @param memberType The type of the member. 444 | * @param memberName The name of the member, will be duplicated. 445 | * @param memberMeta The baked meta data of the member. 446 | * NULL if the member is not a struct or an array. 447 | * baked SymbolInfo_Struct_t if the member is a struct. 448 | * baked SymbolInfo_Array_t if the member is an array. 449 | * @return 450 | */ 451 | SymbolInfo_Member_t SymbolInfo_Member_createBaked(Symbol_Value_Type memberType, char* memberName, SymbolInfo_t memberMeta); 452 | 453 | /** 454 | * Destroy the baked SymbolInfo_Member. 455 | * @param info The baked SymbolInfo_Member. 456 | */ 457 | void SymbolInfo_Member_destroy(SymbolInfo_Member_t info); 458 | 459 | /** 460 | * Check if the symbol is defined. 461 | * @param info The symbol info. 462 | * @return 1 if defined, 0 if not defined. 463 | */ 464 | int SymbolRecord_isSymbolDefined(SymbolRecord_t record); 465 | 466 | 467 | 468 | 469 | #endif //LAB1_SYMBOLTABLE_H 470 | -------------------------------------------------------------------------------- /include/Structure/TokenName.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by m1504 on 2024/3/18. 3 | // 4 | 5 | #ifndef LAB1_TOKENNAME_H 6 | #define LAB1_TOKENNAME_H 7 | 8 | const char* getGrammarSymbolName(int grammarSymbol); 9 | const char* getTokenName(int token); 10 | 11 | #endif //LAB1_TOKENNAME_H 12 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 哈尔滨工业大学-编译原理2024-实验 2 | 3 | ## 版权声明 4 | 5 | 本实验代码由哈尔滨工业大学(本部)相关专业学生编写,仅用于学习交流,未经允许不得用于商业用途。 6 | **由不当使用此项目造成的课业危险由使用者自行承担!!编写者不负任何责任!!** 7 | 8 | ## 模块 9 | 10 | - `src/CmmLexer.l` 词法分析器 11 | - `src/CmmParser.y` 语法分析器 12 | - `src/ErrorReporter.c` 错误报告器,使用散列表实现 13 | - `src/SemanticAnalyzer.c` 语义分析器,在遍历语法树的基础上进行语义检查 14 | - `src/InterCodeGenerator.c` 中间代码生成器,生成三地址码,手动实现了虚表和多态(只是为了好玩) 15 | - `src/Structure/SimpleArray.c` 用于管理树节点,以及为高级数据结构提供基础的的简易动态数组 16 | - `src/Structure/SimpleHashTable.c` 用于管理符号表和错误报告的简易哈希表 17 | - `src/Structure/TokenName.c` 用于从符号枚举值获取符号名 18 | - `src/Structure/SymbolTable.c` 符号表相关实现,支持了一套动态内存管理的符号表 19 | - `src/Structure/ParserNodes.c` 语法树节点,使用动态数组实现 20 | - `src/Structure/SemanticInfo.c` 语义信息,用于在语义节点中提供综合属性 21 | - `Lab1.c` 实验一主程序,包含了词法分析器和语法分析器的调用 22 | - `Lab2.c` 实验二主程序,包含了语义分析器的调用 23 | - `Lab3.c` 实验三主程序,包含了中间代码生成器的调用 24 | 25 | 2024.4.8:项目全部模块编写完成,编写者不再主动更新,如发现问题请及时发issue反馈编写者以修正 26 | *同样也欢迎发issue或邮件探讨项目的设计* 27 | 28 | ## 项目编译 29 | 30 | 首先切换到项目主目录(即CMakeLists.txt所在目录) 31 | 选定一个你喜欢的cmake构建目录名,此处以Cmake为例 32 | 33 | ```bash 34 | mkdir Cmake 35 | cd Cmake 36 | cmake .. 37 | ``` 38 | 39 | cmake将创建所有所需make文件,如果你需要对项目进行debug,在cmake生成make文件时需要指定debug参数: 40 | 41 | ```bash 42 | cmake -DCMAKE_BUILD_TYPE=Debug .. 43 | ``` 44 | 45 | 在执行cmake指令后,你就可以在Cmake文件夹下使用make指令构建项目目标,使用指令 46 | 47 | ```bash 48 | make all 49 | ``` 50 | 51 | 以一次性构建Lab1-3的文件 52 | 你也可以指定性的构建Lab1-3中的任意一个,只需要将`all`替换成`Lab1`, `Lab2`, `Lab3`中的任意一个即可 53 | 54 | 项目的执行文件将生成在 `./crystal` 目录下。 55 | 56 | ## 项目测试 57 | 58 | 项目已在`./crystal`目录下提供测试脚本,可执行`LabXBatchTest.sh`测试实验X,相关样例在`testLabX`目录下 59 | 60 | 当执行脚本时: 61 | 62 | 实验一的树节点输出会被重定向到`testLab1/output/[caseName].pst` 63 | 报错信息将打印到屏幕中。 64 | 65 | 实验三的中间代码生成输出会被重定向到`testLab3/output/[caseName].ir` 66 | 67 | 也可以单独执行`./LabX [filename]`进行测试 68 | 69 | ## 项目测试环境 70 | 71 | IDE: CLion 2023.3.4 72 | 73 | *Thanks to JetBrains for providing the Education License!* 74 | 75 | AI Assistant: GitHub Copilot 76 | 77 | *Thanks to GitHub for providing the Education License!* 78 | 79 | - Ubuntu 22.04.2 LTS 80 | - gcc 11.4.0 81 | - flex 2.6.4 82 | - bison 3.8.2 83 | - cmake 3.26.4 84 | - make 4.3 85 | 86 | *Required_min_version:* 87 | 88 | - cmake 3.22 89 | - flex 2.5.35 90 | - bison 2.5.0 91 | -------------------------------------------------------------------------------- /src/CmmLexer.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #define NOINCLUDE_CMM_SCANNER_TAB_H 3 | #include "CmmParserTypes.h" 4 | #include "Structure/ParserNodes.h" 5 | #include "ErrorReporter.h" 6 | #undef NOINCLUDE_CMM_SCANNER_TAB_H 7 | 8 | %} 9 | 10 | %option yylineno 11 | 12 | COMMENTSINGLE "//" 13 | COMMENTMULTI "/*" 14 | 15 | SEMI ; 16 | COMMA , 17 | ASSIGNOP = 18 | PLUS \+ 19 | MINUS \- 20 | STAR \* 21 | DIV \/ 22 | AND && 23 | OR \|\| 24 | DOT \. 25 | NOT ! 26 | 27 | EQ == 28 | NEQ != 29 | LE <= 30 | LT < 31 | GE >= 32 | GT > 33 | 34 | LP \( 35 | RP \) 36 | LB \[ 37 | RB \] 38 | LC \{ 39 | RC \} 40 | 41 | TYPE int|float 42 | STRUCT struct 43 | RETURN return 44 | IF if 45 | ELSE else 46 | WHILE while 47 | 48 | INTOCT 0[1-7][0-7]* 49 | INTHEX 0[xX][0-9a-fA-F]+ 50 | INTDEC (0|[1-9][0-9]*) 51 | INT {INTDEC}|{INTOCT}|{INTHEX} 52 | FLOAT ({INTDEC}\.[0-9]+)|(([0-9]+\.[0-9]*|[0-9]*\.[0-9]*)[Ee][+-]?[0-9]+) 53 | ID [a-zA-Z_][a-zA-Z0-9_]* 54 | 55 | SPACE [ \t\n\r]+ 56 | 57 | ID_ERROR [0-9][a-zA-Z0-9_]* 58 | INTOCT_ERROR 0[0-7]*[89][0-9]* 59 | INTHEX_ERROR 0[xX][0-9a-fA-F]*[g-zG-Z]*[0-9a-zA-Z]* 60 | INTDEC_ERROR [1-9][0-9]*[a-zA-Z]* 61 | FLOAT_ERROR ({INTDEC}\.[0-9]*[a-zA-Z]+)|(([0-9]*\.[0-9]*|[0-9]*\.[0-9]*)[Ee][+-]?[0-9]*[a-zA-Z]+) 62 | INT_ERROR {INTDEC_ERROR}|{INTOCT_ERROR}|{INTHEX_ERROR} 63 | 64 | ERROR . 65 | 66 | %% 67 | {COMMENTSINGLE} { while (input() != '\n'); } 68 | {COMMENTMULTI} { 69 | int c; 70 | // note that when input meets EOF, it will return 0, not EOF.(issue #2, CmmScanner.c, line 1751) 71 | const int lexerEOF = 0; 72 | int startLine = yylineno; 73 | while ((c = input()) != lexerEOF) { 74 | if (c == '*') { 75 | if ((c = input()) == '/') { 76 | break; 77 | } 78 | else if(c == lexerEOF) 79 | { 80 | goto error_UC; 81 | } 82 | else { 83 | unput(c); 84 | } 85 | } 86 | } 87 | error_UC: 88 | if (c == lexerEOF) { 89 | reportError(startLine, UnterminatedComment, "unterminated comment detected."); 90 | break; 91 | } 92 | } 93 | 94 | {INT} { yylval.nodeIndex = newParserNode(INT, yylineno, 0, NULL, INVALID_NODE_INDEX); return INT; } 95 | {FLOAT} { yylval.nodeIndex = newParserNode(FLOAT, yylineno, 0, NULL, INVALID_NODE_INDEX); return FLOAT; } 96 | 97 | {SEMI} { yylval.nodeIndex = newParserNode(SEMI, yylineno, 0, NULL, INVALID_NODE_INDEX); return SEMI; } 98 | {COMMA} { yylval.nodeIndex = newParserNode(COMMA, yylineno, 0, NULL, INVALID_NODE_INDEX); return COMMA; } 99 | {ASSIGNOP} { yylval.nodeIndex = newParserNode(ASSIGNOP, yylineno, 0, NULL, INVALID_NODE_INDEX); return ASSIGNOP; } 100 | {PLUS} { yylval.nodeIndex = newParserNode(PLUS, yylineno, 0, NULL, INVALID_NODE_INDEX); return PLUS; } 101 | {MINUS} { yylval.nodeIndex = newParserNode(MINUS, yylineno, 0, NULL, INVALID_NODE_INDEX); return MINUS; } 102 | {STAR} { yylval.nodeIndex = newParserNode(STAR, yylineno, 0, NULL, INVALID_NODE_INDEX); return STAR; } 103 | {DIV} { yylval.nodeIndex = newParserNode(DIV, yylineno, 0, NULL, INVALID_NODE_INDEX); return DIV; } 104 | {AND} { yylval.nodeIndex = newParserNode(AND, yylineno, 0, NULL, INVALID_NODE_INDEX); return AND; } 105 | {OR} { yylval.nodeIndex = newParserNode(OR, yylineno, 0, NULL, INVALID_NODE_INDEX); return OR; } 106 | {DOT} { yylval.nodeIndex = newParserNode(DOT, yylineno, 0, NULL, INVALID_NODE_INDEX); return DOT; } 107 | {NOT} { yylval.nodeIndex = newParserNode(NOT, yylineno, 0, NULL, INVALID_NODE_INDEX); return NOT; } 108 | {TYPE} { yylval.nodeIndex = newParserNode(TYPE, yylineno, 0, NULL, INVALID_NODE_INDEX); return TYPE; } 109 | 110 | {EQ} { yylval.nodeIndex = newParserNode(EQ, yylineno, 0, NULL, INVALID_NODE_INDEX); return EQ; } 111 | {NEQ} { yylval.nodeIndex = newParserNode(NEQ, yylineno, 0, NULL, INVALID_NODE_INDEX); return NEQ; } 112 | {LE} { yylval.nodeIndex = newParserNode(LE, yylineno, 0, NULL, INVALID_NODE_INDEX); return LE; } 113 | {LT} { yylval.nodeIndex = newParserNode(LT, yylineno, 0, NULL, INVALID_NODE_INDEX); return LT; } 114 | {GE} { yylval.nodeIndex = newParserNode(GE, yylineno, 0, NULL, INVALID_NODE_INDEX); return GE; } 115 | {GT} { yylval.nodeIndex = newParserNode(GT, yylineno, 0, NULL, INVALID_NODE_INDEX); return GT; } 116 | 117 | {LP} { yylval.nodeIndex = newParserNode(LP, yylineno, 0, NULL, INVALID_NODE_INDEX); return LP; } 118 | {RP} { yylval.nodeIndex = newParserNode(RP, yylineno, 0, NULL, INVALID_NODE_INDEX); return RP; } 119 | {LB} { yylval.nodeIndex = newParserNode(LB, yylineno, 0, NULL, INVALID_NODE_INDEX); return LB; } 120 | {RB} { yylval.nodeIndex = newParserNode(RB, yylineno, 0, NULL, INVALID_NODE_INDEX); return RB; } 121 | {LC} { yylval.nodeIndex = newParserNode(LC, yylineno, 0, NULL, INVALID_NODE_INDEX); return LC; } 122 | {RC} { yylval.nodeIndex = newParserNode(RC, yylineno, 0, NULL, INVALID_NODE_INDEX); return RC; } 123 | 124 | {STRUCT} { yylval.nodeIndex = newParserNode(STRUCT, yylineno, 0, NULL, INVALID_NODE_INDEX); return STRUCT; } 125 | {RETURN} { yylval.nodeIndex = newParserNode(RETURN, yylineno, 0, NULL, INVALID_NODE_INDEX); return RETURN; } 126 | {IF} { yylval.nodeIndex = newParserNode(IF, yylineno, 0, NULL, INVALID_NODE_INDEX); return IF; } 127 | {ELSE} { yylval.nodeIndex = newParserNode(ELSE, yylineno, 0, NULL, INVALID_NODE_INDEX); return ELSE; } 128 | {WHILE} { yylval.nodeIndex = newParserNode(WHILE, yylineno, 0, NULL, INVALID_NODE_INDEX); return WHILE; } 129 | 130 | {ID} { yylval.nodeIndex = newParserNode(ID, yylineno, 0, NULL, INVALID_NODE_INDEX); return ID; } 131 | 132 | {SPACE} ; 133 | 134 | {INT_ERROR} { reportErrorFormat(yylineno, InvalidNumber,"Invalid number \"%s\" ", yytext); return YYerror;} 135 | {FLOAT_ERROR} { reportErrorFormat(yylineno, InvalidFloat, "Invalid float \"%s\" ", yytext); return YYerror;} 136 | {ID_ERROR} { reportErrorFormat(yylineno, InvalidIdentifier, "Invalid identifier \"%s\" ", yytext); return YYerror;} 137 | 138 | 139 | {ERROR} { reportErrorFormat(yylineno, UnrecognizedCharacter, "Unrecognized character \"%s\" ", yytext); return YYerror;} 140 | %% 141 | -------------------------------------------------------------------------------- /src/CmmParser.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #define NOINCLUDE_CMM_SCANNER_TAB_H 3 | #include 4 | #include "CmmParserTypes.h" 5 | #include "Structure/ParserNodes.h" 6 | #include "ErrorReporter.h" 7 | #undef NOINCLUDE_CMM_SCANNER_TAB_H 8 | 9 | extern int yylineno; 10 | extern int yylex(); 11 | %} 12 | 13 | %union { 14 | ParserNode_I nodeIndex; 15 | } 16 | 17 | 18 | %token INT // A sequence of digits without spaces 19 | %token FLOAT // A real number consisting of digits and a decimal point, point must be surrounded by digits 20 | %token ID // A sequence of letters, digits, and underscores, starting with a letter or underscore, at most 52 characters 21 | %token SEMI // ; 22 | %token COMMA // , 23 | %token ASSIGNOP // = 24 | %token EQ NEQ LE LT GE GT // ==, !=, <=, <, >=, > 25 | %token PLUS // + 26 | %token MINUS // - 27 | %token STAR // * 28 | %token DIV // / 29 | %token AND // && 30 | %token OR // || 31 | %token DOT // . 32 | %token NOT // ! 33 | %token TYPE // int, float 34 | %token LP // ( 35 | %token RP // ) 36 | %token LB // [ 37 | %token RB // ] 38 | %token LC // { 39 | %token RC // } 40 | %token STRUCT // struct 41 | %token RETURN // return 42 | %token IF // if 43 | %token ELSE // else 44 | %token WHILE // while 45 | 46 | %type Program ExtDefList ExtDef ExtDecList 47 | %type Specifier StructSpecifier OptTag Tag 48 | %type VarDec FunDec VarList ParamDec 49 | %type CompStm StmtList Stmt 50 | %type DefList Def DecList Dec 51 | %type Exp Args 52 | 53 | // Define the precedence and associativity of the operators 54 | %right ASSIGNOP 55 | %left OR 56 | %left AND 57 | %left EQ NEQ LE LT GE GT 58 | %left PLUS MINUS 59 | %left STAR DIV 60 | %right NOT 61 | %left DOT LP RP LB RB LC RC 62 | 63 | %nonassoc LELSE 64 | %nonassoc ELSE 65 | 66 | %nonassoc pri3 67 | %nonassoc pri2 68 | %nonassoc pri1 69 | %nonassoc pri0 70 | 71 | %% 72 | // HIGH LEVEL GRAMMAR 73 | Program: 74 | ExtDefList {ParserNode_I children[1] = {$1}; $$ = newParserNode(PROGRAM, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX); setParserTreeRoot($$);} 75 | ; 76 | 77 | ExtDefList: 78 | ExtDef ExtDefList {ParserNode_I children[2] = {$1, $2}; $$ = newParserNode(EXT_DEF_LIST, NO_LINE_NUMBER, 2, children, INVALID_NODE_INDEX);} 79 | | /* empty */ {$$ = newParserNode(EXT_DEF_LIST, NO_LINE_NUMBER, 0, NULL, INVALID_NODE_INDEX);} 80 | ; 81 | 82 | ExtDef: 83 | Specifier ExtDecList SEMI %prec pri0 {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXT_DEF, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 84 | |Specifier SEMI %prec pri0 {ParserNode_I children[2] = {$1, $2}; $$ = newParserNode(EXT_DEF, NO_LINE_NUMBER, 2, children, INVALID_NODE_INDEX);} 85 | |Specifier FunDec CompStm {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXT_DEF, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 86 | |Specifier FunDec SEMI %prec pri0 {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXT_DEF, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 87 | 88 | |Specifier ExtDecList %prec pri1 {reportError(getParserNode($1)->lineNum, MissingSemicolon, "Missing \";\"");} 89 | |Specifier %prec pri1 {reportError(getParserNode($1)->lineNum, MissingSemicolon, "Missing \";\"");} 90 | |Specifier FunDec %prec pri1 {reportError(getParserNode($2)->lineNum, MissingSemicolon, "Missing \";\"");} 91 | |error SEMI %prec pri2 {yyerrok; reportError(yylineno, UnexpectedDeclaration, "Unexpected Declaration");} 92 | ; 93 | 94 | ExtDecList: 95 | VarDec {ParserNode_I children[1] = {$1}; $$ = newParserNode(EXT_DEC_LIST, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 96 | |VarDec COMMA ExtDecList {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXT_DEC_LIST, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 97 | 98 | |VarDec ExtDecList {reportError(getParserNode($2)->lineNum, MissingComma, "Missing \",\"");} 99 | ; 100 | 101 | //SPECIFIER 102 | Specifier: 103 | TYPE {ParserNode_I children[1] = {$1}; $$ = newParserNode(SPECIFIER, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 104 | |StructSpecifier {ParserNode_I children[1] = {$1}; $$ = newParserNode(SPECIFIER, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 105 | ; 106 | 107 | StructSpecifier: 108 | STRUCT OptTag LC DefList RC {ParserNode_I children[5] = {$1, $2, $3, $4, $5}; $$ = newParserNode(STRUCT_SPECIFIER, NO_LINE_NUMBER, 5, children, INVALID_NODE_INDEX);} 109 | |STRUCT Tag {ParserNode_I children[2] = {$1, $2}; $$ = newParserNode(STRUCT_SPECIFIER, NO_LINE_NUMBER, 2, children, INVALID_NODE_INDEX);} 110 | ; 111 | 112 | OptTag: 113 | ID {ParserNode_I children[1] = {$1}; $$ = newParserNode(OPT_TAG, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 114 | |/* empty */ {$$ = newParserNode(OPT_TAG, NO_LINE_NUMBER, 0, NULL, INVALID_NODE_INDEX);} 115 | ; 116 | 117 | Tag: 118 | ID {ParserNode_I children[1] = {$1}; $$ = newParserNode(TAG, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 119 | ; 120 | 121 | //DECLARATION 122 | VarDec: 123 | ID {ParserNode_I children[1] = {$1}; $$ = newParserNode(VAR_DEC, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 124 | |VarDec LB INT RB %prec pri0 {ParserNode_I children[4] = {$1, $2, $3, $4}; $$ = newParserNode(VAR_DEC, NO_LINE_NUMBER, 4, children, INVALID_NODE_INDEX);} 125 | 126 | |VarDec LB INT %prec pri1 {reportError(getParserNode($2)->lineNum, MissingRightBracket, "Missing \"]\"");} 127 | ; 128 | 129 | FunDec: 130 | ID LP VarList RP %prec pri0 {ParserNode_I children[4] = {$1, $2, $3, $4}; $$ = newParserNode(FUN_DEC, NO_LINE_NUMBER, 4, children, INVALID_NODE_INDEX);} 131 | |ID LP RP %prec pri0 {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(FUN_DEC, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 132 | 133 | |ID LP VarList %prec pri1 {reportError(getParserNode($2)->lineNum, MissingRightParenthesis, "Missing \")\"");} 134 | ; 135 | 136 | VarList: 137 | ParamDec COMMA VarList %prec pri0 {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(VAR_LIST, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 138 | |ParamDec {ParserNode_I children[1] = {$1}; $$ = newParserNode(VAR_LIST, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 139 | ; 140 | 141 | ParamDec: 142 | Specifier VarDec {ParserNode_I children[2] = {$1, $2}; $$ = newParserNode(PARAM_DEC, NO_LINE_NUMBER, 2, children, INVALID_NODE_INDEX);} 143 | 144 | |VarDec {reportError(getParserNode($1)->lineNum, MissingSpecifier, "Missing Specifier");} 145 | ; 146 | 147 | //STATEMENT 148 | CompStm: 149 | LC DefList StmtList RC {ParserNode_I children[4] = {$1, $2, $3, $4}; $$ = newParserNode(COMP_STM, NO_LINE_NUMBER, 4, children, INVALID_NODE_INDEX);} 150 | ; 151 | 152 | StmtList: 153 | Stmt StmtList {ParserNode_I children[2] = {$1, $2}; $$ = newParserNode(STMT_LIST, NO_LINE_NUMBER, 2, children, INVALID_NODE_INDEX);} 154 | |/* empty */ {$$ = newParserNode(STMT_LIST, NO_LINE_NUMBER, 0, NULL, INVALID_NODE_INDEX);} 155 | ; 156 | 157 | Stmt: 158 | Exp SEMI %prec pri2 {ParserNode_I children[2] = {$1, $2}; $$ = newParserNode(STMT, NO_LINE_NUMBER, 2, children, INVALID_NODE_INDEX);} 159 | |CompStm {ParserNode_I children[1] = {$1}; $$ = newParserNode(STMT, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 160 | |RETURN Exp SEMI %prec pri2 {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(STMT, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 161 | |IF LP Exp RP Stmt %prec LELSE {ParserNode_I children[5] = {$1, $2, $3, $4, $5}; $$ = newParserNode(STMT, NO_LINE_NUMBER, 5, children, INVALID_NODE_INDEX);} 162 | |IF LP Exp RP Stmt ELSE Stmt {ParserNode_I children[7] = {$1, $2, $3, $4, $5, $6, $7}; $$ = newParserNode(STMT, NO_LINE_NUMBER, 7, children, INVALID_NODE_INDEX);} 163 | |WHILE LP Exp RP Stmt {ParserNode_I children[5] = {$1, $2, $3, $4, $5}; $$ = newParserNode(STMT, NO_LINE_NUMBER, 5, children, INVALID_NODE_INDEX);} 164 | 165 | |error SEMI %prec pri3 {yyerrok; reportError(yylineno, UnexpectedStatement, "Unexpected Statement");} 166 | ; 167 | 168 | 169 | //LOCAL DEFINITION 170 | DefList: 171 | Def DefList {ParserNode_I children[2] = {$1, $2}; $$ = newParserNode(DEF_LIST, NO_LINE_NUMBER, 2, children, INVALID_NODE_INDEX);} 172 | |/* empty */ {$$ = newParserNode(DEF_LIST, NO_LINE_NUMBER, 0, NULL, INVALID_NODE_INDEX);} 173 | ; 174 | 175 | Def: 176 | Specifier DecList SEMI {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(DEF, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 177 | ; 178 | 179 | DecList: 180 | Dec {ParserNode_I children[1] = {$1}; $$ = newParserNode(DEC_LIST, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 181 | |Dec COMMA DecList {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(DEC_LIST, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 182 | ; 183 | 184 | Dec: 185 | VarDec {ParserNode_I children[1] = {$1}; $$ = newParserNode(DEC, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 186 | |VarDec ASSIGNOP Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(DEC, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 187 | ; 188 | 189 | //EXPRESSION 190 | 191 | Exp: 192 | Exp ASSIGNOP Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 193 | |Exp AND Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 194 | |Exp OR Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 195 | |Exp EQ Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 196 | |Exp NEQ Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 197 | |Exp LT Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 198 | |Exp LE Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 199 | |Exp GT Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 200 | |Exp GE Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 201 | |Exp PLUS Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 202 | |Exp MINUS Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 203 | |Exp STAR Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 204 | |Exp DIV Exp {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 205 | |LP Exp RP {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 206 | |MINUS Exp {ParserNode_I children[2] = {$1, $2}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 2, children, INVALID_NODE_INDEX);} 207 | |NOT Exp {ParserNode_I children[2] = {$1, $2}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 2, children, INVALID_NODE_INDEX);} 208 | |ID LP Args RP {ParserNode_I children[4] = {$1, $2, $3, $4}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 4, children, INVALID_NODE_INDEX);} 209 | |ID LP RP {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 210 | |Exp LB Exp RB {ParserNode_I children[4] = {$1, $2, $3, $4}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 4, children, INVALID_NODE_INDEX);} 211 | |Exp DOT ID {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 212 | |ID %prec pri0 {ParserNode_I children[1] = {$1}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 213 | |INT %prec pri0 {ParserNode_I children[1] = {$1}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 214 | |FLOAT %prec pri0 {ParserNode_I children[1] = {$1}; $$ = newParserNode(EXP, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 215 | 216 | |error Exp %prec pri1 {yyerrok; reportError(yylineno, UnexpectedExpression, "Unexpected Expression");} 217 | ; 218 | 219 | Args: 220 | Exp COMMA Args {ParserNode_I children[3] = {$1, $2, $3}; $$ = newParserNode(ARGS, NO_LINE_NUMBER, 3, children, INVALID_NODE_INDEX);} 221 | |Exp {ParserNode_I children[1] = {$1}; $$ = newParserNode(ARGS, NO_LINE_NUMBER, 1, children, INVALID_NODE_INDEX);} 222 | ; 223 | 224 | %% -------------------------------------------------------------------------------- /src/ErrorReporter.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by m1504 on 2024/3/20. 3 | // 4 | 5 | #include "Structure/SimpleHashTable.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include "ErrorReporter.h" 11 | 12 | #define IS_LEXICAL_ERROR(errorType) (errorType >= LEXICAL_ERROR_BASE && errorType <= UNDEF_LEXICAL_ERROR) 13 | #define IS_SYNTAX_ERROR(errorType) (errorType >= SYNTAX_ERROR_BASE && errorType <= UNDEF_SYNTAX_ERROR) 14 | #define IS_SEMANTIC_ERROR(errorType) (errorType >= SEMANTIC_ERROR_BASE && errorType <= UNDEF_SEMANTIC_ERROR) 15 | 16 | //#define ERROR_REPORTER_DEBUG 17 | 18 | typedef struct ErrorInfo_s { 19 | int errorType; 20 | int lineNumber; 21 | char* externalMessage; 22 | } ErrorInfo; 23 | typedef ErrorInfo* ErrorInfo_t; 24 | 25 | char semanticErrorTypeNames[][10] = { 26 | "UNDEF", 27 | "1", 28 | "2", 29 | "3", 30 | "4", 31 | "5", 32 | "6", 33 | "7", 34 | "8", 35 | "9", 36 | "10", 37 | "11", 38 | "12", 39 | "13", 40 | "14", 41 | "15", 42 | "16", 43 | "17", 44 | "18", 45 | "19", 46 | "20" 47 | }; 48 | 49 | SimpleHashTable_t errorTable = NULL; 50 | 51 | FILE* errorFile = NULL; 52 | 53 | int cmpErrorPriority(int errorType1, int errorType2); 54 | 55 | ErrorInfo createErrorInfo(int lineNumber, int errorType, char* externalMessage) { 56 | ErrorInfo errorInfo; 57 | errorInfo.lineNumber = lineNumber; 58 | errorInfo.errorType = errorType; 59 | errorInfo.externalMessage = strdup(externalMessage); 60 | return errorInfo; 61 | } 62 | 63 | void freeErrorInfo(void* inErrorInfo) { 64 | ErrorInfo_t errorInfo = (ErrorInfo_t)inErrorInfo; 65 | if (errorInfo->externalMessage != NULL) { 66 | free(errorInfo->externalMessage); 67 | } 68 | } 69 | 70 | const char* getErrorTypeName(int errorType){ 71 | if(IS_LEXICAL_ERROR(errorType)) 72 | { 73 | return "A"; 74 | } 75 | else if(IS_SYNTAX_ERROR(errorType)) 76 | { 77 | return "B"; 78 | } 79 | else if(IS_SEMANTIC_ERROR(errorType)) 80 | { 81 | if(errorType != UNDEF_SEMANTIC_ERROR) { 82 | return semanticErrorTypeNames[errorType - SEMANTIC_ERROR_BASE]; 83 | } 84 | } 85 | return "UNDEF"; 86 | } 87 | 88 | void printErrorInfo(const void* inErrorInfo) { 89 | fprintf(errorFile, "Error type %s at line %d: %s\n" 90 | , getErrorTypeName(((ErrorInfo_t)inErrorInfo)->errorType) 91 | , ((ErrorInfo_t)inErrorInfo)->lineNumber 92 | , ((ErrorInfo_t)inErrorInfo)->externalMessage); 93 | } 94 | 95 | void reportError(int line, int errorType, char* externalMessage) { 96 | if (errorTable == NULL) { 97 | errorTable = SimpleHashTable_createHashTable(sizeof(ErrorInfo), NULL, NULL); 98 | } 99 | 100 | #ifdef ERROR_REPORTER_DEBUG 101 | printf("DEBUG: Error type %s at line %d: %s\n\n" 102 | , getErrorTypeName(errorType) 103 | , line 104 | , externalMessage); 105 | #endif 106 | 107 | ErrorInfo_t existedErrorInfo = (ErrorInfo_t)SimpleHashTable_find(errorTable, &line, sizeof(int)); 108 | if (existedErrorInfo == NULL || cmpErrorPriority(existedErrorInfo->errorType, errorType) < 0) { 109 | ErrorInfo errorInfo = createErrorInfo(line, errorType, externalMessage); 110 | 111 | #ifdef ERROR_REPORTER_DEBUG 112 | printf("DEBUG: Error type %s in *ErrorInfo* at line %d: %s\n\n" 113 | , getErrorTypeName(errorInfo.errorType) 114 | , errorInfo.lineNumber 115 | , errorInfo.externalMessage); 116 | #endif 117 | 118 | SimpleHashTable_forceInsert(errorTable, (char *) &line, sizeof(int), &errorInfo, NULL, freeErrorInfo); 119 | 120 | #ifdef ERROR_REPORTER_DEBUG 121 | printf("DEBUG: Error type %s in *ErrorTable* at line %d: %s\n\n" 122 | , getErrorTypeName(((ErrorInfo_t)SimpleHashTable_find(errorTable, &line, sizeof(int)))->errorType) 123 | , ((ErrorInfo_t)SimpleHashTable_find(errorTable, &line, sizeof(int)))->lineNumber 124 | , ((ErrorInfo_t)SimpleHashTable_find(errorTable, &line, sizeof(int)))->externalMessage); 125 | #endif 126 | 127 | } 128 | } 129 | 130 | void reportErrorFormat(int line, int errorType, const char* format, ...) 131 | { 132 | char buffer[1024]; 133 | va_list args; 134 | va_start(args, format); 135 | vsprintf(buffer, format, args); 136 | va_end(args); 137 | reportError(line, errorType, buffer); 138 | } 139 | 140 | void printError(FILE *file) { 141 | if(errorTable == NULL || file == NULL) 142 | { 143 | return; 144 | } 145 | errorFile = file; 146 | SimpleHashTable_traverse(errorTable, printErrorInfo); 147 | } 148 | 149 | void resetErrorReporter() { 150 | if (errorTable != NULL) { 151 | SimpleHashTable_destroy(errorTable, NULL, freeErrorInfo); 152 | } 153 | errorTable = NULL; 154 | errorFile = NULL; 155 | } 156 | 157 | int hasError() 158 | { 159 | return errorTable == NULL ? 0 : 1; 160 | } 161 | 162 | 163 | int cmpErrorPriority(int errorType1, int errorType2) { 164 | if (errorType1 == errorType2) { 165 | return 0; 166 | } 167 | if(IS_LEXICAL_ERROR(errorType1)) 168 | { 169 | if(IS_LEXICAL_ERROR(errorType2)) 170 | { 171 | return errorType1 - errorType2; 172 | } 173 | } 174 | if(IS_SYNTAX_ERROR(errorType1)) 175 | { 176 | if(IS_SYNTAX_ERROR(errorType2)) 177 | { 178 | return errorType1 - errorType2; 179 | } 180 | else if(IS_LEXICAL_ERROR(errorType2)) 181 | { 182 | return -1; 183 | } 184 | } 185 | if(IS_SEMANTIC_ERROR(errorType1)) 186 | { 187 | if(IS_SEMANTIC_ERROR(errorType2)) 188 | { 189 | return 0; 190 | } 191 | if(IS_LEXICAL_ERROR(errorType2)) 192 | { 193 | return -1; 194 | } 195 | if(IS_SYNTAX_ERROR(errorType2)) 196 | { 197 | return -1; 198 | } 199 | } 200 | return 1; 201 | } 202 | -------------------------------------------------------------------------------- /src/Lab1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Lab1.h" 3 | #include "CmmParserTypes.h" 4 | #include "Structure/ParserNodes.h" 5 | #include "ErrorReporter.h" 6 | 7 | //#define ALWAYS_TRY_PRINT_PARSER_TREE 8 | 9 | extern void yyrestart(FILE* input_file); 10 | 11 | int main(int argc, char** argv){ 12 | if(argc<2) 13 | { 14 | fprintf(stderr, "Usage: %s \n", argv[0]); 15 | return 1; 16 | } 17 | FILE* file = fopen(argv[1], "r"); 18 | if(file == NULL) 19 | { 20 | fprintf(stderr, "Error: Cannot open file %s\n", argv[1]); 21 | return 1; 22 | } 23 | 24 | yyset_debug(0); 25 | yyrestart(file); 26 | yyparse(); 27 | int ret = hasError(); 28 | #ifndef ALWAYS_TRY_PRINT_PARSER_TREE 29 | if(!ret) 30 | #else 31 | if(1) 32 | #endif 33 | { 34 | printParserTree_PreOrder(getParserTreeRoot(), 0); 35 | } 36 | #ifndef ALWAYS_TRY_PRINT_PARSER_TREE 37 | if(ret) 38 | #else 39 | if(1) 40 | #endif 41 | { 42 | printError(stderr); 43 | resetErrorReporter(); 44 | } 45 | 46 | #ifdef DEBUG_PARSER_TREE 47 | printf("DEBUG_PARSER_NODES:\n"); 48 | printAllNodes(); 49 | #endif 50 | 51 | freeParserNodes(); 52 | return ret; 53 | } 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/Lab2.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/19. 3 | // 4 | 5 | #include "Structure/SymbolTable.h" 6 | #include "ErrorReporter.h" 7 | #include "Structure/ParserNodes.h" 8 | #include "SemanticAnalyzer.h" 9 | 10 | #include "Lab2.h" 11 | 12 | int main(int argc, char** argv) { 13 | if(argc<2) 14 | { 15 | fprintf(stderr, "Usage: %s \n", argv[0]); 16 | return 1; 17 | } 18 | FILE* file = fopen(argv[1], "r"); 19 | if(file == NULL) 20 | { 21 | fprintf(stderr, "Error: Cannot open file %s\n", argv[1]); 22 | return 1; 23 | } 24 | 25 | yyset_debug(0); 26 | yyrestart(file); 27 | yyparse(); 28 | int ret = hasError(); 29 | 30 | #ifdef DEBUG_PARSER_TREE 31 | printf("DEBUG_PARSER_NODES:\n"); 32 | printAllNodes(); 33 | #endif 34 | 35 | if(ret) 36 | { 37 | printError(stderr); 38 | fprintf(stderr, "Lexical or syntax error detected, aborted before semantic analyzing.\n"); 39 | freeParserNodes(); 40 | return ret; 41 | } 42 | 43 | SymbolTable_t symbolTable = SymbolTable_create(); 44 | 45 | semanticAnalyze(getParserTreeRoot(), symbolTable); 46 | 47 | ret = hasError(); 48 | if(ret) { 49 | printError(stderr); 50 | resetErrorReporter(); 51 | } 52 | 53 | semanticAnalyze_End(); 54 | SymbolTable_destroy(symbolTable); 55 | freeParserNodes(); 56 | 57 | return ret; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/Lab3.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/31. 3 | // 4 | 5 | #include "CmmParserTypes.h" 6 | #include "Structure/ParserNodes.h" 7 | #include "SemanticAnalyzer.h" 8 | #include "ErrorReporter.h" 9 | #include "InterCodeGenerator.h" 10 | 11 | #include "Lab3.h" 12 | #include "Structure/SymbolTable.h" 13 | 14 | 15 | void registerPredefinedFunctions(SymbolTable_t symbolTable); 16 | 17 | int main(int argc, char** argv){ 18 | if(argc<2) 19 | { 20 | fprintf(stderr, "Usage: %s \n", argv[0]); 21 | return 1; 22 | } 23 | FILE* file = fopen(argv[1], "r"); 24 | if(file == NULL) 25 | { 26 | fprintf(stderr, "Error: Cannot open file %s\n", argv[1]); 27 | return 1; 28 | } 29 | 30 | yyset_debug(0); 31 | yyrestart(file); 32 | yyparse(); 33 | int ret = hasError(); 34 | 35 | #ifdef DEBUG_PARSER_TREE 36 | printf("DEBUG_PARSER_NODES:\n"); 37 | printAllNodes(); 38 | #endif 39 | 40 | if(ret) 41 | { 42 | printError(stderr); 43 | fprintf(stderr, "Lexical or syntax error detected, aborted before semantic analyzing.\n"); 44 | resetErrorReporter(); 45 | freeParserNodes(); 46 | return ret; 47 | } 48 | 49 | SymbolTable_t symbolTable = SymbolTable_create(); 50 | 51 | registerPredefinedFunctions(symbolTable); 52 | 53 | semanticAnalyze(getParserTreeRoot(), symbolTable); 54 | 55 | ret = hasError(); 56 | if(ret) { 57 | printError(stderr); 58 | fprintf(stderr, "Semantic error detected.\n"); 59 | resetErrorReporter(); 60 | semanticAnalyze_End(); 61 | freeParserNodes(); 62 | return ret; 63 | } 64 | 65 | 66 | 67 | InterCodeHandle codeHandle = generateInterCode(getParserTreeRoot(), stdout, symbolTable); 68 | 69 | generateInterCode_End(); 70 | 71 | 72 | semanticAnalyze_End(); 73 | SymbolTable_destroy(symbolTable); 74 | freeParserNodes(); 75 | 76 | return ret; 77 | } 78 | 79 | void registerPredefinedFunctions(SymbolTable_t symbolTable) { 80 | SymbolInfo_Function_t readFunc = SymbolInfo_Function_createBaked(SVT_Int, 81 | NULL, 82 | NULL, 83 | NULL, 84 | NULL, 85 | 0); 86 | Symbol_Value_Type writeFuncParamType[1] = {SVT_Int}; 87 | char* writeFuncParamName[1] = {"value"}; 88 | SymbolInfo_t writeFuncParamInfo[1] = {NULL}; 89 | SymbolInfo_Function_t writeFunc = SymbolInfo_Function_createBaked(SVT_Int, 90 | NULL, 91 | writeFuncParamType, 92 | writeFuncParamName, 93 | writeFuncParamInfo, 94 | 1); 95 | readFunc->isDefined = 1; 96 | writeFunc->isDefined = 1; 97 | SymbolRecord record; 98 | SymbolTable_createFunctionByInfo(symbolTable, &record, readFunc); 99 | SymbolTable_insertRecord(symbolTable, "read", &record); 100 | SymbolTable_createFunctionByInfo(symbolTable, &record, writeFunc); 101 | SymbolTable_insertRecord(symbolTable, "write", &record); 102 | } 103 | -------------------------------------------------------------------------------- /src/Structure/ParserNodes.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by m1504 on 2024/3/19. 3 | // 4 | 5 | #include "Lab1.h" 6 | #include 7 | #include 8 | #include "stdlib.h" 9 | #include "string.h" 10 | #include "Structure/SimpleArray.h" 11 | #include "CmmParserTypes.h" 12 | 13 | #include "Structure/ParserNodes.h" 14 | 15 | SimpleArray_t parserNodes = NULL; 16 | ParserNode_I rootIndex = INVALID_NODE_INDEX; 17 | extern char* yytext; 18 | 19 | void setParserTreeRoot(ParserNode_I InRootIndex){ 20 | rootIndex = InRootIndex; 21 | } 22 | 23 | ParserNode_I newParserNode(int symbol, int lineNum, int childNum, ParserNode_I *children, ParserNode_I fatherNodeIndex) { 24 | if(parserNodes == NULL) 25 | { 26 | parserNodes = SimpleArray_create(sizeof(ParserNode)); 27 | } 28 | ParserNode node; 29 | node.token = symbol; 30 | node.lineNum = lineNum; 31 | node.children = NULL; 32 | node.semanticInfo = NULL; 33 | switch (symbol) { 34 | case ID: 35 | case TYPE: 36 | node.ID = strdup(yytext); 37 | break; 38 | case INT: 39 | node.intVal = stoi(yytext); 40 | break; 41 | case FLOAT: 42 | node.floatVal = strtof(yytext, NULL); 43 | break; 44 | default: 45 | break; 46 | } 47 | int nodeIndex = SimpleArray_addElement(parserNodes, &node); 48 | 49 | addChildrenToNode(nodeIndex, childNum, children); 50 | if(fatherNodeIndex != INVALID_NODE_INDEX) 51 | { 52 | addChildToNode(fatherNodeIndex, nodeIndex); 53 | } 54 | 55 | return nodeIndex; 56 | } 57 | 58 | ParserNode_t getParserNode(ParserNode_I index){ 59 | return (ParserNode_t) SimpleArray_at(parserNodes, index); 60 | } 61 | 62 | void freeParserNode(void *nodeToFree) { 63 | ParserNode_t node = (ParserNode_t)nodeToFree; 64 | if(node->children != NULL) 65 | { 66 | SimpleArray_destroy(node->children, NULL); 67 | } 68 | if(node->token == ID || node->token == TYPE) 69 | { 70 | free(node->ID); 71 | } 72 | } 73 | 74 | void freeParserNodes(){ 75 | SimpleArray_destroy(parserNodes, freeParserNode); 76 | } 77 | 78 | int ParserNodeIndexContainer_addNodeIndex(ParserNodeIndexContainer_t container, ParserNode_I index){ 79 | return SimpleArray_addElement(container, &index); 80 | } 81 | 82 | ParserNodeIndexContainer_t ParserNodeIndexContainer_createContainer(){ 83 | return SimpleArray_newArrayWithCapacity(sizeof(ParserNode_I), 10); 84 | } 85 | 86 | ParserNode_t ParserNodeIndexContainer_getNode(ParserNodeIndexContainer_t container, int index){ 87 | ParserNode_I* indexPtr = (ParserNode_I*) SimpleArray_at(container, index); 88 | return getParserNode(*indexPtr); 89 | } 90 | 91 | void addChildrenToNode(ParserNode_I nodeIndex, int childNum, ParserNode_I* children) { 92 | if(childNum == 0) 93 | { 94 | return; 95 | } 96 | ParserNode_t node = getParserNode(nodeIndex); 97 | if(node->children == NULL) { 98 | node->children = ParserNodeIndexContainer_createContainer(); 99 | node->lineNum = getParserNode(children[0])->lineNum; 100 | } 101 | for(int i = 0; i < childNum; i++) { 102 | ParserNodeIndexContainer_addNodeIndex(node->children, children[i]); 103 | } 104 | } 105 | 106 | void addChildToNode(ParserNode_I nodeIndex, ParserNode_I childIndex){ 107 | ParserNode_t node = getParserNode(nodeIndex); 108 | if(node->children == NULL) 109 | { 110 | node->children = ParserNodeIndexContainer_createContainer(); 111 | node->lineNum = getParserNode(childIndex)->lineNum; 112 | } 113 | ParserNodeIndexContainer_addNodeIndex(node->children, childIndex); 114 | } 115 | 116 | int stoi(const char* str){ 117 | int base = 10; 118 | int result = 0; 119 | int sign = 1; 120 | //处理符号和基数 121 | entry: 122 | switch(str[0]) { 123 | case '-': 124 | sign = -1; 125 | ++str; 126 | goto entry; 127 | case '+': 128 | ++str; 129 | goto entry; 130 | case '0': 131 | switch (str[1]) { 132 | case 'x': 133 | case 'X': 134 | base = 16; 135 | str+=2; 136 | break; 137 | case '\0': 138 | return 0; 139 | default: 140 | base = 8; 141 | ++str; 142 | break; 143 | } 144 | default: 145 | break; 146 | } 147 | //此处已确保str指向真正的数字串 148 | //不关心无符号溢出,不可能炸,这里强转避免编译警告 149 | int len = (int)strlen(str); 150 | for(int i =0;i='0' && str[i]<='9') 154 | { 155 | digit = str[i] - '0'; 156 | } 157 | else if(str[i]>='a' && str[i]<='z') 158 | { 159 | digit = str[i] - 'a' + 10; 160 | } 161 | else if(str[i]>='A' && str[i]<='Z') 162 | { 163 | digit = str[i] - 'A' + 10; 164 | } 165 | result = result * base + digit; 166 | } 167 | return result * sign; 168 | } 169 | 170 | ParserNode_I ParserNodeIndexContainer_getNodeIndex(ParserNodeIndexContainer_t container, int index) { 171 | return *((ParserNode_I *) SimpleArray_at(container, index)); 172 | } 173 | 174 | ParserNode_I getParserTreeRoot() { 175 | return rootIndex; 176 | } 177 | 178 | #pragma clang diagnostic push 179 | #pragma ide diagnostic ignored "misc-no-recursion" 180 | void printParserTree_PreOrder(ParserNode_I nodeIndex, int depth) { 181 | if(nodeIndex == INVALID_NODE_INDEX) 182 | { 183 | return; 184 | } 185 | printParserNode(nodeIndex, depth); 186 | ParserNode_t node = getParserNode(nodeIndex); 187 | if(node->children == NULL) 188 | { 189 | return; 190 | } 191 | for(int i = 0; i < node->children->num; i++) 192 | { 193 | printParserTree_PreOrder(ParserNodeIndexContainer_getNodeIndex(node->children, i), depth + 1); 194 | } 195 | } 196 | #pragma clang diagnostic pop 197 | 198 | void printAllNodes() { 199 | for(int i = 0;inum;i++) 200 | { 201 | printParserNode(i, 0); 202 | } 203 | } 204 | 205 | void printParserNode(ParserNode_I nodeIndex, int depth) { 206 | if(nodeIndex == INVALID_NODE_INDEX) 207 | { 208 | return; 209 | } 210 | #ifdef DEBUG_PRINT_PARSER_NODE_INDEX 211 | printf("%d\t", nodeIndex); 212 | #endif 213 | ParserNode_t node = getParserNode(nodeIndex); 214 | if(IS_SYNTAX_TOKEN(node->token)) 215 | { 216 | if(node->children!=NULL) 217 | { 218 | for(int i = 0; i < depth; i++) 219 | { 220 | printf(" "); 221 | } 222 | printf("%s (%d)\n", getGrammarSymbolName(node->token), node->lineNum); 223 | } 224 | 225 | } 226 | else if(IS_TERMINAL_TOKEN(node->token)) 227 | { 228 | for(int i = 0; i < depth; i++) 229 | { 230 | printf(" "); 231 | } 232 | switch(node->token) 233 | { 234 | case ID: 235 | printf("ID: %s\n", node->ID); 236 | break; 237 | case TYPE: 238 | printf("TYPE: %s\n", node->ID); 239 | break; 240 | case INT: 241 | printf("INT: %d\n", node->intVal); 242 | break; 243 | case FLOAT: 244 | printf("FLOAT: %f\n", node->floatVal); 245 | break; 246 | case EQ: 247 | case NEQ: 248 | case LT: 249 | case GT: 250 | case LE: 251 | case GE: 252 | printf("RELOP\n" ); 253 | break; 254 | default: 255 | printf("%s\n", getTokenName(node->token)); 256 | break; 257 | } 258 | } 259 | } 260 | 261 | void yyerror(const char *msg) { 262 | 263 | } 264 | 265 | ParserNode_t getParserNodeChildNode(ParserNode_I index, int childIndex) { 266 | return getParserNode(getParserNodeChild(index, childIndex)); 267 | } 268 | 269 | ParserNode_I getParserNodeChild(ParserNode_I index, int childIndex) { 270 | ParserNodeIndexContainer_t children = getParserNode(index)->children; 271 | return ParserNodeIndexContainer_getNodeIndex(children, childIndex); 272 | } 273 | 274 | int getParserNodeChildNum(ParserNode_I index) { 275 | ParserNodeIndexContainer_t children = getParserNode(index)->children; 276 | return children->num; 277 | } 278 | 279 | int isChildrenMatchRule(ParserNode_I nodeIndex, int ruleSize, ...) { 280 | if (GET_NODE(nodeIndex)->children == NULL) 281 | { 282 | if(ruleSize == 0) 283 | return 1; 284 | else 285 | return 0; 286 | } 287 | if (GET_CHILD_NUM(nodeIndex) != ruleSize) { 288 | return 0; 289 | } 290 | va_list params; 291 | va_start(params, ruleSize); 292 | for (int i = 0; i < ruleSize; i++) { 293 | if (GET_CHILD_NODE(nodeIndex, i)->token != va_arg(params, int)) { 294 | va_end(params); 295 | return 0; 296 | } 297 | } 298 | va_end(params); 299 | return 1; 300 | } 301 | -------------------------------------------------------------------------------- /src/Structure/SemanticInfo.c: -------------------------------------------------------------------------------- 1 | #pragma clang diagnostic push 2 | #pragma ide diagnostic ignored "misc-no-recursion" 3 | // 4 | // Created by Crystal on 2024/3/19. 5 | // 6 | 7 | #include "Structure/SymbolTable.h" 8 | 9 | #include "Structure/SemanticInfo.h" 10 | 11 | int SymbolInfo_isStructTypeMatched(SymbolInfo_Struct_t a, SymbolInfo_Struct_t b); 12 | int SymbolInfo_isArrayTypeMatched(SymbolInfo_Array_t a, SymbolInfo_Array_t b); 13 | 14 | SemanticInfo_t 15 | SemanticInfo_createLvalue(Symbol_Value_Type valueType, SymbolInfo_t valueInfo, SimpleArray_t semanticInfoList) { 16 | SemanticInfo_t semanticInfo = (SemanticInfo_t)malloc(sizeof(SemanticInfo)); 17 | semanticInfo->isLValue = 1; 18 | semanticInfo->valueType = valueType; 19 | semanticInfo->valueTypeMeta = valueInfo; 20 | SimpleArray_pushBack(semanticInfoList, &semanticInfo); 21 | return semanticInfo; 22 | } 23 | 24 | SemanticInfo_t SemanticInfo_createRvalue(Symbol_Value_Type valueType, SymbolInfo_t valueInfo, SimpleArray_t semanticInfoList) { 25 | SemanticInfo_t semanticInfo = (SemanticInfo_t)malloc(sizeof(SemanticInfo)); 26 | semanticInfo->isLValue = 0; 27 | semanticInfo->valueType = valueType; 28 | semanticInfo->valueTypeMeta = valueInfo; 29 | SimpleArray_pushBack(semanticInfoList, &semanticInfo); 30 | return semanticInfo; 31 | } 32 | 33 | SemanticInfo_t SemanticInfo_makeRvalue(SemanticInfo_t semanticInfo, SimpleArray_t semanticInfoList){ 34 | if(semanticInfo->isLValue) 35 | { 36 | return SemanticInfo_createRvalue(semanticInfo->valueType, semanticInfo->valueTypeMeta, semanticInfoList); 37 | } 38 | return semanticInfo; 39 | } 40 | 41 | void SemanticInfo_destroy(void *semanticInfoToDestroy) { 42 | SemanticInfo_t* semanticInfo = (SemanticInfo_t*)semanticInfoToDestroy; 43 | free(*semanticInfo); 44 | } 45 | 46 | int SemanticInfo_isTypeMatched(SemanticInfo_t a, SemanticInfo_t b) { 47 | if(a==NULL || b==NULL) 48 | { 49 | return 0; 50 | } 51 | return SymbolInfo_Helper_isTypeMatched(a->valueType, a->valueTypeMeta, b->valueType, b->valueTypeMeta); 52 | } 53 | 54 | int SymbolInfo_Function_isReturnTypeMatched(SymbolInfo_Function_t a, SymbolInfo_Function_t b){ 55 | return SymbolInfo_Helper_isTypeMatched(a->returnType, a->returnTypeMeta, b->returnType, b->returnTypeMeta); 56 | } 57 | 58 | int SymbolInfo_Function_isParameterListMatched(SymbolInfo_Function_t a, SymbolInfo_Function_t b){ 59 | if(a->parameterCount != b->parameterCount) 60 | { 61 | return 0; 62 | } 63 | for(int i = 0; i < a->parameterCount; i++) 64 | { 65 | SymbolInfo_Parameter_t aParameter = a->parameters[i]; 66 | SymbolInfo_Parameter_t bParameter = b->parameters[i]; 67 | if(!SymbolInfo_Helper_isTypeMatched(aParameter->parameterType, 68 | aParameter->parameterMeta, 69 | bParameter->parameterType, 70 | bParameter->parameterMeta)) 71 | { 72 | return 0; 73 | } 74 | } 75 | return 1; 76 | } 77 | 78 | 79 | int SemanticInfo_checkValueType(SemanticInfo_t semanticInfo, Symbol_Value_Type type){ 80 | return semanticInfo->valueType == type; 81 | } 82 | 83 | int SemanticInfo_checkReturnType(SymbolInfo_Function_t functionInfo, SemanticInfo_t semanticInfo){ 84 | return SymbolInfo_Helper_isTypeMatched(semanticInfo->valueType, semanticInfo->valueTypeMeta, 85 | functionInfo->returnType, functionInfo->returnTypeMeta); 86 | } 87 | 88 | int SemanticInfo_checkParameterList(SymbolInfo_Function_t functionInfo, SemanticInfo_t* semanticInfos, int paramCount){ 89 | if(functionInfo->parameterCount != paramCount) 90 | { 91 | return 0; 92 | } 93 | for(int i = 0; i < paramCount; i++) 94 | { 95 | SymbolInfo_Parameter_t parameter = functionInfo->parameters[i]; 96 | if(!SymbolInfo_Helper_isTypeMatched(parameter->parameterType, parameter->parameterMeta, 97 | semanticInfos[i]->valueType, semanticInfos[i]->valueTypeMeta)) 98 | { 99 | return 0; 100 | } 101 | } 102 | return 1; 103 | } 104 | 105 | 106 | SymbolInfo_Member_t SemanticInfo_getMemberInfo(SemanticInfo_t semanticInfo, const char *memberName) { 107 | if(!SemanticInfo_checkValueType(semanticInfo, SVT_Struct)) { 108 | return NULL; 109 | } 110 | SymbolInfo_Struct_t structInfo = (SymbolInfo_Struct_t)semanticInfo->valueTypeMeta; 111 | for(int i = 0; i < structInfo->memberCount; i++) { 112 | SymbolInfo_Member_t member = structInfo->members[i]; 113 | if(strcmp(member->memberName, memberName) == 0) { 114 | return member; 115 | } 116 | } 117 | return NULL; 118 | } 119 | 120 | int SymbolInfo_isStructTypeMatched(SymbolInfo_Struct_t a, SymbolInfo_Struct_t b){ 121 | if(a->memberCount == b->memberCount) 122 | { 123 | for(int i = 0; i < a->memberCount; i++) 124 | { 125 | SymbolInfo_Member_t aMember = a->members[i]; 126 | SymbolInfo_Member_t bMember = b->members[i]; 127 | if(!SymbolInfo_Helper_isTypeMatched(aMember->memberType, 128 | aMember->memberMeta, 129 | bMember->memberType, 130 | bMember->memberMeta)) 131 | { 132 | return 0; 133 | } 134 | } 135 | return 1; 136 | } 137 | return 0; 138 | } 139 | 140 | int SymbolInfo_isArrayTypeMatched(SymbolInfo_Array_t a, SymbolInfo_Array_t b) { 141 | return a->dimensionCount == b->dimensionCount 142 | && SymbolInfo_Helper_isTypeMatched(a->elementType, a->elementMeta, 143 | b->elementType, b->elementMeta); 144 | } 145 | 146 | int SymbolInfo_Helper_isTypeMatched(Symbol_Value_Type aType, SymbolInfo_t aMeta, Symbol_Value_Type bType, 147 | SymbolInfo_t bMeta) { 148 | if(aType == bType) 149 | { 150 | switch (aType) { 151 | case SVT_Int: 152 | case SVT_Float: 153 | case SVT_Void: 154 | return 1; 155 | case SVT_Struct: 156 | return SymbolInfo_isStructTypeMatched((SymbolInfo_Struct_t)aMeta, (SymbolInfo_Struct_t)bMeta); 157 | case SVT_Array: 158 | return SymbolInfo_isArrayTypeMatched((SymbolInfo_Array_t)aMeta, (SymbolInfo_Array_t)bMeta); 159 | default: 160 | return 0; 161 | } 162 | } 163 | return 0; 164 | } 165 | 166 | #pragma clang diagnostic pop -------------------------------------------------------------------------------- /src/Structure/SimpleArray.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/17. 3 | // 4 | 5 | #include 6 | #include 7 | #include "Structure/SimpleArray.h" 8 | 9 | // Free the simple array, will free the memory of the array and the elements, used private 10 | void SimpleArray_internalDestroyArray(SimpleArray_t array); 11 | 12 | // Remove the element at the index, will move the elements after the index, used private 13 | void SimpleArray_internalRemoveElement(SimpleArray_t array, int index); 14 | 15 | SimpleArray_t SimpleArray_create(int typeSize){ 16 | SimpleArray_t array = (SimpleArray_t)malloc(sizeof(SimpleArray)); 17 | array->data = (char*)malloc(DEFAULT_CAPACITY * typeSize); 18 | array->num = 0; 19 | array->typeSize = typeSize; 20 | array->capacity = DEFAULT_CAPACITY; 21 | return array; 22 | } 23 | 24 | int SimpleArray_addElement(SimpleArray_t array, const void* element){ 25 | if(array->num >= array->capacity / 2){ 26 | SimpleArray_reserve(array, array->capacity * 2); 27 | } 28 | memcpy(array->data + array->num * array->typeSize, element, array->typeSize); 29 | array->num++; 30 | return array->num - 1; 31 | } 32 | 33 | void* SimpleArray_at(SimpleArray_t array, int index){ 34 | if(index < 0 || index >= array->num){ 35 | return NULL; 36 | } 37 | return array->data + index * array->typeSize; 38 | } 39 | 40 | void SimpleArray_internalDestroyArray(SimpleArray_t array){ 41 | free(array->data); 42 | free(array); 43 | } 44 | 45 | void SimpleArray_reserve(SimpleArray_t array, int capacity){ 46 | char* newData = (char*)malloc(capacity * array->typeSize); 47 | memcpy(newData, array->data, array->num * array->typeSize); 48 | free(array->data); 49 | array->data = newData; 50 | array->capacity = capacity; 51 | } 52 | 53 | void SimpleArray_insertElement(SimpleArray_t array, int index, void *element) { 54 | if(array->num >= array->capacity / 2){ 55 | SimpleArray_reserve(array, array->capacity * 2); 56 | } 57 | memmove(array->data + (index + 1) * array->typeSize, array->data + index * array->typeSize, (array->num - index) * array->typeSize); 58 | memcpy(array->data + index * array->typeSize, element, array->typeSize); 59 | array->num++; 60 | } 61 | 62 | void SimpleArray_internalRemoveElement(SimpleArray_t array, int index) { 63 | memmove(array->data + index * array->typeSize, array->data + (index + 1) * array->typeSize, (array->num - index - 1) * array->typeSize); 64 | array->num--; 65 | } 66 | 67 | void SimpleArray_clear(SimpleArray_t array) { 68 | array->num = 0; 69 | } 70 | 71 | SimpleArray_t SimpleArray_newArrayWithCapacity(int typeSize, int capacity) { 72 | SimpleArray_t array = (SimpleArray_t)malloc(sizeof(SimpleArray)); 73 | array->data = (char*)malloc(capacity * typeSize); 74 | array->num = 0; 75 | array->typeSize = typeSize; 76 | array->capacity = capacity; 77 | return array; 78 | } 79 | 80 | void SimpleArray_resize(SimpleArray_t array, int newSize) { 81 | if(newSize * 2 > array->capacity) { 82 | SimpleArray_reserve(array, newSize * 2); 83 | } 84 | array->num = newSize; 85 | } 86 | 87 | void SimpleArray_zeroFilled(SimpleArray_t array) { 88 | memset(array->data, 0, array->num * array->typeSize); 89 | } 90 | 91 | void SimpleArray_popBack(SimpleArray_t array, Destructor elementDestructor) { 92 | SimpleArray_removeElement(array, array->num - 1, elementDestructor); 93 | } 94 | 95 | int SimpleArray_pushBack(SimpleArray_t array, void *element) { 96 | return SimpleArray_addElement(array, element); 97 | } 98 | 99 | void * SimpleArray_back(SimpleArray_t array) { 100 | return SimpleArray_at(array, array->num - 1); 101 | } 102 | 103 | int SimpleArray_size(SimpleArray_t array) { 104 | return array->num; 105 | } 106 | 107 | void SimpleArray_destroy(SimpleArray_t array, Destructor elementDestructor) { 108 | if(array == NULL) 109 | return; 110 | if(elementDestructor != NULL) 111 | { 112 | for (int i = 0; i < array->num; i++) { 113 | elementDestructor(array->data + i * array->typeSize); 114 | } 115 | } 116 | SimpleArray_internalDestroyArray(array); 117 | } 118 | 119 | void SimpleArray_removeElement(SimpleArray_t array, int index, Destructor elementDestructor) { 120 | if(elementDestructor != NULL) 121 | { 122 | elementDestructor(array->data + index * array->typeSize); 123 | } 124 | SimpleArray_internalRemoveElement(array, index); 125 | } 126 | 127 | void SimpleArray_setElement(SimpleArray_t array, int index, const void *element) { 128 | memcpy(array->data + index * array->typeSize, element, array->typeSize); 129 | } 130 | -------------------------------------------------------------------------------- /src/Structure/SimpleHashTable.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by m1504 on 2024/3/20. 3 | // 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include "Structure/SimpleHashTable.h" 10 | 11 | void SimpleHashTablePair_setPair(SimpleHashTablePair_t pair, const void* key, int keySize, const void* element, int elementSize) 12 | { 13 | pair->keySize = keySize; 14 | pair->key = malloc(keySize); 15 | pair->element = malloc(elementSize); 16 | memcpy(pair->key, key, keySize); 17 | memcpy(pair->element, element, elementSize); 18 | } 19 | 20 | void SimpleHashTablePair_destroy(SimpleHashTablePair_t pair, Destructor destructorForKey, Destructor destructorForElement) 21 | { 22 | if(destructorForKey != NULL) 23 | { 24 | destructorForKey(pair->key); 25 | } 26 | else 27 | { 28 | free(pair->key); 29 | } 30 | if(destructorForElement != NULL) 31 | { 32 | destructorForElement(pair->element); 33 | } 34 | else 35 | { 36 | free(pair->element); 37 | } 38 | 39 | } 40 | 41 | int pjwHash(const char* key, int keySize, int tableSize) { 42 | const int BitsInUnsignedInt = (int)(sizeof(int) * 8); 43 | const int ThreeQuarters = (int)((BitsInUnsignedInt * 3) / 4); 44 | const int OneEighth = (int)(BitsInUnsignedInt / 8); 45 | const int HighBits = (int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth); 46 | int hash = 0; 47 | int test = 0; 48 | 49 | for (int i = 0; i < keySize; i++) { 50 | hash = (hash << OneEighth) + key[i]; 51 | 52 | if ((test = hash & HighBits) != 0) { 53 | hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits)); 54 | } 55 | } 56 | 57 | return hash % tableSize; 58 | } 59 | 60 | int defaultCompare(const void* a, const void* b, int keySize) { 61 | return memcmp(a, b, keySize); 62 | } 63 | 64 | int defaultHash(const void* key, int keySize, int tableSize) { 65 | return pjwHash((const char*)key, keySize, tableSize); 66 | } 67 | 68 | SimpleHashTable_t SimpleHashTable_createHashTable(int elementSize, HashFunc hashFunc, CompareFunc compareFunc) { 69 | return SimpleHashTable_createWithSize(elementSize, hashFunc, compareFunc, THOUSAND_HASH_TABLE_SIZE); 70 | } 71 | 72 | SimpleHashTable_t SimpleHashTable_createWithSize(int elementSize, HashFunc keyHashFunc, CompareFunc keyCompareFunc, int tableSize) { 73 | SimpleHashTable_t hashTable = (SimpleHashTable_t)malloc(sizeof(SimpleHashTable)); 74 | hashTable->hashFunc = keyHashFunc == NULL ? defaultHash : keyHashFunc; 75 | hashTable->compareFunc = keyCompareFunc == NULL ? defaultCompare : keyCompareFunc; 76 | hashTable->elementSize = elementSize; 77 | hashTable->data = SimpleArray_create(sizeof(SimpleArray_t)); 78 | hashTable->tableSize = tableSize; 79 | SimpleArray_resize(hashTable->data, tableSize); 80 | SimpleArray_zeroFilled(hashTable->data); 81 | return hashTable; 82 | } 83 | 84 | void SimpleHashTable_destroy(SimpleHashTable_t hashTable, Destructor destructorForKey, Destructor destructorForElement){ 85 | if(hashTable == NULL) 86 | return; 87 | for (int i = 0; i < THOUSAND_HASH_TABLE_SIZE; i++) { 88 | SimpleArray_t list = *((SimpleArray_t*) SimpleArray_at(hashTable->data, i)); 89 | if (list != NULL) { 90 | for(int j = 0; j < list->num; j++) 91 | { 92 | SimpleHashTablePair_t pair = (SimpleHashTablePair_t) SimpleArray_at(list, j); 93 | SimpleHashTablePair_destroy(pair, destructorForKey, destructorForElement); 94 | } 95 | SimpleArray_destroy(list, NULL); 96 | } 97 | } 98 | SimpleArray_destroy(hashTable->data, NULL); 99 | free(hashTable); 100 | } 101 | 102 | int SimpleHashTable_insert(SimpleHashTable_t hashTable, const void* key, int keySize, const void* element) { 103 | int index = hashTable->hashFunc(key, keySize, hashTable->tableSize); 104 | SimpleArray_t list = *((SimpleArray_t*) SimpleArray_at(hashTable->data, index)); 105 | if (list == NULL) { 106 | list = SimpleArray_newArrayWithCapacity(sizeof(SimpleHashTablePair), DEFAULT_HASH_BUCKET_SIZE); 107 | SimpleArray_setElement(hashTable->data, index, &list); 108 | } 109 | for(int i = 0; i < list->num; i++) 110 | { 111 | SimpleHashTablePair_t pair = (SimpleHashTablePair_t) SimpleArray_at(list, i); 112 | if(pair->keySize == keySize && hashTable->compareFunc(pair->key, key, keySize) == 0) 113 | { 114 | return -1; 115 | } 116 | } 117 | SimpleHashTablePair newPair; 118 | SimpleHashTablePair_setPair(&newPair, key, keySize, element, hashTable->elementSize); 119 | SimpleArray_addElement(list, &newPair); 120 | return 0; 121 | } 122 | 123 | void* SimpleHashTable_find(SimpleHashTable_t hashTable, const void* key, int keySize) { 124 | int index = hashTable->hashFunc(key, keySize, hashTable->tableSize); 125 | SimpleArray_t list = *((SimpleArray_t*) SimpleArray_at(hashTable->data, index)); 126 | if (list == NULL) 127 | { 128 | return NULL; 129 | } 130 | for (int i = 0; i < list->num; i++) { 131 | SimpleHashTablePair_t pair = (SimpleHashTablePair_t) SimpleArray_at(list, i); 132 | if(pair->keySize == keySize && hashTable->compareFunc(pair->key, key, keySize) == 0) 133 | { 134 | return pair->element; 135 | } 136 | } 137 | return NULL; 138 | } 139 | 140 | void SimpleHashTable_remove(SimpleHashTable_t hashTable, const void* key, int keySize, Destructor destructorForKey, Destructor destructorForElement) { 141 | int index = hashTable->hashFunc(key, keySize, hashTable->tableSize); 142 | SimpleArray_t list = *((SimpleArray_t*) SimpleArray_at(hashTable->data, index)); 143 | if (list == NULL) 144 | { 145 | return; 146 | } 147 | for (int i = 0; i < list->num; i++) { 148 | SimpleHashTablePair_t pair = (SimpleHashTablePair_t) SimpleArray_at(list, i); 149 | if(pair->keySize == keySize && hashTable->compareFunc(pair->key, key, keySize) == 0) 150 | { 151 | SimpleHashTablePair_destroy(pair, destructorForKey, destructorForElement); 152 | SimpleArray_removeElement(list, i, NULL); 153 | return; 154 | } 155 | } 156 | } 157 | 158 | void SimpleHashTable_traverse(SimpleHashTable_t hashTable, TraverseFunc traverseFunc) { 159 | if(traverseFunc == NULL) 160 | return; 161 | for (int i = 0; i < hashTable->tableSize; i++) { 162 | SimpleArray_t list = *((SimpleArray_t*) SimpleArray_at(hashTable->data, i)); 163 | if (list != NULL) { 164 | for (int j = 0; j < list->num; j++) { 165 | SimpleHashTablePair_t pair = (SimpleHashTablePair_t) SimpleArray_at(list, j); 166 | traverseFunc(pair->element); 167 | } 168 | } 169 | } 170 | } 171 | 172 | void SimpleHashTable_forceInsert(SimpleHashTable_t hashTable, const void *key, int keySize, const void *element, 173 | Destructor destructorForKey, Destructor destructorForElement) { 174 | int index = hashTable->hashFunc(key, keySize, hashTable->tableSize); 175 | SimpleArray_t list = *((SimpleArray_t*) SimpleArray_at(hashTable->data, index)); 176 | if (list == NULL) { 177 | list = SimpleArray_newArrayWithCapacity(sizeof(SimpleHashTablePair), DEFAULT_HASH_BUCKET_SIZE); 178 | SimpleArray_setElement(hashTable->data, index, &list); 179 | } 180 | for(int i = 0; i < list->num; i++) 181 | { 182 | SimpleHashTablePair_t pair = (SimpleHashTablePair_t) SimpleArray_at(list, i); 183 | if(pair->keySize == keySize && hashTable->compareFunc(pair->key, key, keySize) == 0) 184 | { 185 | SimpleHashTablePair_destroy(pair, destructorForKey, destructorForElement); 186 | SimpleHashTablePair_setPair(pair, key, keySize, element, hashTable->elementSize); 187 | return; 188 | } 189 | } 190 | SimpleHashTablePair newPair; 191 | SimpleHashTablePair_setPair(&newPair, key, keySize, element, hashTable->elementSize); 192 | SimpleArray_addElement(list, &newPair); 193 | } 194 | 195 | void 196 | SimpleHashTable_advancedTraverse(SimpleHashTable_t hashTable, AdvancedTraverseFunc traverseFunc, int extraParamCount, 197 | ...) { 198 | if(traverseFunc == NULL) 199 | return; 200 | va_list args; 201 | va_start(args, extraParamCount); 202 | for (int i = 0; i < hashTable->tableSize; i++) { 203 | SimpleArray_t list = *((SimpleArray_t*) SimpleArray_at(hashTable->data, i)); 204 | if (list != NULL) { 205 | for (int j = 0; j < list->num; j++) { 206 | SimpleHashTablePair_t pair = (SimpleHashTablePair_t) SimpleArray_at(list, j); 207 | traverseFunc(pair->key, pair->keySize, pair->element, extraParamCount, args); 208 | } 209 | } 210 | } 211 | va_end(args); 212 | } 213 | 214 | -------------------------------------------------------------------------------- /src/Structure/SimpleList.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/4/3. 3 | // 4 | 5 | #include 6 | 7 | #include "Structure/SimpleList.h" 8 | 9 | SimpleList_t SimpleList_create() { 10 | SimpleList_t newList = malloc(sizeof(SimpleList)); 11 | newList->head = NULL; 12 | newList->tail = NULL; 13 | newList->size = 0; 14 | return newList; 15 | } 16 | 17 | SimpleListNode_t SimpleList_push_back(SimpleList_t list, void *data) { 18 | SimpleListNode_t newNode = malloc(sizeof(SimpleListNode)); 19 | newNode->data = data; 20 | newNode->next = NULL; 21 | newNode->prev = list->tail; 22 | if (list->tail != NULL) { 23 | list->tail->next = newNode; 24 | } 25 | list->tail = newNode; 26 | if (list->head == NULL) { 27 | list->head = newNode; 28 | } 29 | list->size++; 30 | return newNode; 31 | } 32 | 33 | SimpleListNode_t SimpleList_push_front(SimpleList_t list, void *data) { 34 | SimpleListNode_t newNode = malloc(sizeof(SimpleListNode)); 35 | newNode->data = data; 36 | newNode->next = list->head; 37 | newNode->prev = NULL; 38 | if (list->head != NULL) { 39 | list->head->prev = newNode; 40 | } 41 | list->head = newNode; 42 | if (list->tail == NULL) { 43 | list->tail = newNode; 44 | } 45 | list->size++; 46 | return newNode; 47 | } 48 | 49 | void *SimpleList_pop_back(SimpleList_t list) { 50 | SimpleListNode_t lastNode = list->tail; 51 | if (lastNode == NULL) { 52 | return NULL; 53 | } 54 | void *data = lastNode->data; 55 | list->tail = lastNode->prev; 56 | if (list->tail != NULL) { 57 | list->tail->next = NULL; 58 | } else { 59 | list->head = NULL; 60 | } 61 | free(lastNode); 62 | list->size--; 63 | return data; 64 | } 65 | 66 | void *SimpleList_pop_front(SimpleList_t list) { 67 | SimpleListNode_t firstNode = list->head; 68 | if (firstNode == NULL) { 69 | return NULL; 70 | } 71 | void *data = firstNode->data; 72 | list->head = firstNode->next; 73 | if (list->head != NULL) { 74 | list->head->prev = NULL; 75 | } else { 76 | list->tail = NULL; 77 | } 78 | free(firstNode); 79 | list->size--; 80 | return data; 81 | } 82 | 83 | void SimpleList_insertBefore(SimpleList_t list, SimpleListNode_t pos, void *data) { 84 | if (pos == NULL) { 85 | SimpleList_push_back(list, data); 86 | return; 87 | } 88 | SimpleListNode_t newNode = malloc(sizeof(SimpleListNode)); 89 | newNode->data = data; 90 | newNode->next = pos; 91 | newNode->prev = pos->prev; 92 | if (pos->prev != NULL) { 93 | pos->prev->next = newNode; 94 | } else { 95 | list->head = newNode; 96 | } 97 | pos->prev = newNode; 98 | list->size++; 99 | } 100 | 101 | void SimpleList_insertAfter(SimpleList_t list, SimpleListNode_t pos, void *data) { 102 | if (pos == NULL) { 103 | SimpleList_push_front(list, data); 104 | return; 105 | } 106 | SimpleListNode_t newNode = malloc(sizeof(SimpleListNode)); 107 | newNode->data = data; 108 | newNode->next = pos->next; 109 | newNode->prev = pos; 110 | if (pos->next != NULL) { 111 | pos->next->prev = newNode; 112 | } else { 113 | list->tail = newNode; 114 | } 115 | pos->next = newNode; 116 | list->size++; 117 | } 118 | 119 | SimpleList_t SimpleList_append(SimpleList_t list1, SimpleList_t list2) { 120 | if (list1 == NULL) { 121 | return list2; 122 | } 123 | if (list2 == NULL) { 124 | return list1; 125 | } 126 | if(list1->size == 0) 127 | { 128 | free(list1); 129 | return list2; 130 | } 131 | if(list2->size == 0) 132 | { 133 | free(list2); 134 | return list1; 135 | } 136 | list1->tail->next = list2->head; 137 | list2->head->prev = list1->tail; 138 | list1->tail = list2->tail; 139 | list1->size += list2->size; 140 | free(list2); 141 | return list1; 142 | } 143 | 144 | SimpleList_t SimpleList_destroy(SimpleList_t list, void (*destroyData)(void *)) { 145 | SimpleListNode_t node = list->head; 146 | while (node != NULL) { 147 | SimpleListNode_t next = node->next; 148 | if (destroyData != NULL) { 149 | destroyData(node->data); 150 | } 151 | free(node); 152 | node = next; 153 | } 154 | free(list); 155 | return NULL; 156 | } 157 | -------------------------------------------------------------------------------- /src/Structure/SymbolTable.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/19. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | #include "Structure/SymbolTable.h" 9 | 10 | #define SYMBOL_TABLE_HASH_TABLE_SIZE 10007 11 | 12 | //////////////////////////////////////// 13 | /// debug 14 | //////////////////////////////////////// 15 | 16 | void SymbolInfo_Struct_printDebug(SymbolInfo_t structInfo, char *buffer, int size); 17 | 18 | void SymbolInfo_Function_printDebug(SymbolInfo_t functionInfo, char *buffer, int size); 19 | 20 | void SymbolInfo_Variable_printDebug(SymbolInfo_t variableInfo, char *buffer, int size); 21 | 22 | void SymbolInfo_DebugHelper_getTypeString(Symbol_Value_Type e, void* meta, char buffer[], int bufferSize); 23 | 24 | //////////////////////////////////////// 25 | /// SymbolValue 26 | //////////////////////////////////////// 27 | 28 | int SymbolValue_getSize(Symbol_Value_Type type, SymbolInfo_t meta) { 29 | switch (type) { 30 | case SVT_Int: 31 | case SVT_Float: 32 | return 4; 33 | case SVT_Struct: 34 | return ((SymbolInfo_Struct_t)meta)->size; 35 | case SVT_Array: 36 | return ((SymbolInfo_Array_t)meta)->dimension * SymbolValue_getSize(((SymbolInfo_Array_t)meta)->elementType, 37 | ((SymbolInfo_Array_t)meta)->elementMeta); 38 | default: 39 | return 0; 40 | } 41 | return 0; 42 | } 43 | 44 | //////////////////////////////////////// 45 | /// SymbolTable 46 | //////////////////////////////////////// 47 | 48 | SymbolTable_t SymbolTable_create() { 49 | SymbolTable_t table = (SymbolTable_t)malloc(sizeof(SymbolTable)); 50 | table->table = SimpleHashTable_createWithSize(sizeof(SymbolRecord), NULL, NULL, SYMBOL_TABLE_HASH_TABLE_SIZE); 51 | table->nextScopeID = 0; 52 | table->scopeStack = SimpleArray_create(sizeof(int)); 53 | table->currentScope = 0; 54 | table->nextVarID = 0; 55 | table->nextLabelID = 0; 56 | SymbolTable_enterScope(table); 57 | return table; 58 | } 59 | 60 | void SymbolTable_destroy(void* tableToDestroy){ 61 | SymbolTable_t table = (SymbolTable_t)tableToDestroy; 62 | SimpleHashTable_destroy(table->table, NULL, SymbolRecord_destroy); 63 | SimpleArray_destroy(table->scopeStack, NULL); 64 | free(table); 65 | } 66 | 67 | void SymbolTable_enterScope(SymbolTable_t table) { 68 | table->currentScope = table->nextScopeID; 69 | SimpleArray_pushBack(table->scopeStack, &table->nextScopeID); 70 | table->nextScopeID++; 71 | } 72 | 73 | void SymbolTable_leaveScope(SymbolTable_t table) { 74 | assert(table->scopeStack->num > 0); 75 | SimpleArray_popBack(table->scopeStack, NULL); 76 | table->currentScope = *(int *) SimpleArray_back(table->scopeStack); 77 | } 78 | 79 | int SymbolTable_getScope(SymbolTable_t table) { 80 | return *(int *) SimpleArray_back(table->scopeStack); 81 | } 82 | 83 | void SymbolTable_generateName(SymbolTable_t table, char *name, char *buffer, int bufferSize) { 84 | snprintf(buffer, bufferSize, "+%d_%s", table->currentScope, name); 85 | } 86 | 87 | SymbolDefineStatus SymbolTable_lookupRecord(SymbolTable_t table, char *name, SymbolRecord_t *outRecord) { 88 | int scopeIndex = SymbolTable_internalLookupRecord(table, name, outRecord); 89 | if(scopeIndex == -1) 90 | { 91 | return SDS_Undefined; 92 | } 93 | if(scopeIndex==table->scopeStack->num-1) 94 | { 95 | if(SymbolRecord_isSymbolDefined(*outRecord)) 96 | return SDS_Defined; 97 | else 98 | return SDS_Declared; 99 | } 100 | else 101 | { 102 | if(SymbolRecord_isSymbolDefined(*outRecord)) 103 | return SDS_ExternalDefined; 104 | else 105 | return SDS_ExternalDeclared; 106 | } 107 | } 108 | 109 | int SymbolTable_internalLookupRecord(SymbolTable_t table, char *name, SymbolRecord_t *outRecord) { 110 | for(int i = table->scopeStack->num - 1; i >= 0; i--){ 111 | int scope = *(int*) SimpleArray_at(table->scopeStack, i); 112 | char buffer[256]; 113 | snprintf(buffer, sizeof(buffer), "+%d_%s", scope, name); 114 | #ifdef SYMBOL_TABLE_DEBUG 115 | printf("Looking up \"%s\"\n", buffer); 116 | #endif 117 | SymbolRecord_t record = SimpleHashTable_find(table->table, buffer, (int)strlen(buffer)+1); 118 | if(record != NULL){ 119 | *outRecord = record; 120 | return i; 121 | } 122 | } 123 | #ifdef SYMBOL_TABLE_DEBUG 124 | printf("Failed to find \"%s\"\n", name); 125 | #endif 126 | *outRecord = NULL; 127 | return -1; 128 | } 129 | 130 | 131 | SymbolDefineStatus 132 | SymbolTable_lookupRecordInScope(SymbolTable_t table, char *name, int scope, SymbolRecord_t *outRecord) { 133 | char buffer[256]; 134 | snprintf(buffer, sizeof(buffer), "+%d_%s", scope, name); 135 | SymbolRecord_t record = SimpleHashTable_find(table->table, buffer, (int)strlen(buffer)+1); 136 | if(record == NULL) { 137 | *outRecord = NULL; 138 | return SDS_Undefined; 139 | } 140 | *outRecord = record; 141 | if(SymbolRecord_isSymbolDefined(record)) 142 | return SDS_Defined; 143 | else 144 | return SDS_Declared; 145 | } 146 | 147 | int SymbolTable_insertRecord(SymbolTable_t table, char *name, SymbolRecord_t record) { 148 | char fullNameBuffer[256]; 149 | SymbolTable_generateName(table, name, fullNameBuffer, sizeof(fullNameBuffer)); 150 | #ifdef SYMBOL_TABLE_STRUCT_NAME 151 | if(record->type == ST_Struct){ 152 | SymbolInfo_Struct_setName(record->info, name); 153 | } 154 | #endif 155 | if(record->type == ST_Function){ 156 | SymbolInfo_Function_setName(record->info, name); 157 | } 158 | #ifndef SYMBOL_TABLE_DEBUG 159 | return SimpleHashTable_insert(table->table, fullNameBuffer, (int)strlen(fullNameBuffer)+1, record); 160 | #else 161 | char debugBuffer[1024]; 162 | int result = SimpleHashTable_insert(table->table, fullNameBuffer, (int)strlen(fullNameBuffer) + 1, record); 163 | if(result == 0){ 164 | SymbolRecord_printDebug(record, debugBuffer, 1024); 165 | printf("Inserted record \"%s\": %s\n", fullNameBuffer, debugBuffer); 166 | } 167 | else 168 | { 169 | printf("Failed to insert record \"%s\": %s\n", fullNameBuffer, debugBuffer); 170 | } 171 | return result; 172 | #endif 173 | } 174 | 175 | void SymbolTable_createVariableByInfo(SymbolTable_t table, SymbolRecord *outRecord, SymbolInfo_t info) 176 | { 177 | outRecord->type = ST_Variable; 178 | outRecord->info = info; 179 | } 180 | 181 | void SymbolTable_createFunctionByInfo(SymbolTable_t table, SymbolRecord *outRecord, SymbolInfo_t info) { 182 | outRecord->type = ST_Function; 183 | outRecord->info = info; 184 | } 185 | 186 | void SymbolTable_createStructByInfo(SymbolTable_t table, SymbolRecord *outRecord, SymbolInfo_t info) { 187 | outRecord->type = ST_Struct; 188 | outRecord->info = info; 189 | } 190 | 191 | //////////////////////////////////////// 192 | /// SymbolRecord 193 | //////////////////////////////////////// 194 | 195 | void SymbolRecord_destroy(void* recordToDestroy){ 196 | SymbolRecord_t record = (SymbolRecord_t)recordToDestroy; 197 | switch(record->type) 198 | { 199 | case ST_Variable: 200 | SymbolInfo_Variable_destroy(record->info); 201 | break; 202 | case ST_Function: 203 | SymbolInfo_Function_destroy(record->info); 204 | break; 205 | case ST_Struct: 206 | SymbolInfo_Struct_destroy(record->info); 207 | break; 208 | default: 209 | break; 210 | } 211 | free(record); 212 | } 213 | 214 | //////////////////////////////////////// 215 | /// SymbolInfo 216 | //////////////////////////////////////// 217 | 218 | 219 | SymbolInfo_Variable_t SymbolInfo_Variable_createBaked(Symbol_Value_Type type, SymbolInfo_t meta){ 220 | SymbolInfo_Variable_Raw info = NULL; 221 | switch(type){ 222 | case SVT_Int: 223 | info = (SymbolInfo_Variable_Raw)malloc(sizeof(SymbolInfo_Variable)); 224 | ((SymbolInfo_Variable_Raw)info)->type = SVT_Int; 225 | ((SymbolInfo_Variable_Raw)info)->meta = NULL; 226 | ((SymbolInfo_Variable_Raw)info)->varID = 0; 227 | return info; 228 | case SVT_Float: 229 | info = (SymbolInfo_Variable_Raw)malloc(sizeof(SymbolInfo_Variable)); 230 | ((SymbolInfo_Variable_Raw)info)->type = SVT_Float; 231 | ((SymbolInfo_Variable_Raw)info)->meta = NULL; 232 | ((SymbolInfo_Variable_Raw)info)->varID = 0; 233 | return info; 234 | case SVT_Struct: 235 | info = (SymbolInfo_Variable_Raw)malloc(sizeof(SymbolInfo_Variable)); 236 | ((SymbolInfo_Variable_Raw)info)->type = SVT_Struct; 237 | ((SymbolInfo_Variable_Raw)info)->meta = meta; 238 | ((SymbolInfo_Variable_Raw)info)->varID = 0; 239 | return info; 240 | case SVT_Array: 241 | info = (SymbolInfo_Variable_Raw)malloc(sizeof(SymbolInfo_Variable)); 242 | ((SymbolInfo_Variable_Raw)info)->type = SVT_Array; 243 | ((SymbolInfo_Variable_Raw)info)->meta = meta; 244 | ((SymbolInfo_Variable_Raw)info)->varID = 0; 245 | return info; 246 | default: 247 | return NULL; 248 | } 249 | } 250 | 251 | void SymbolInfo_Variable_destroy(SymbolInfo_Variable_t info) { 252 | if(info == NULL) 253 | return; 254 | else if(info->type == SVT_Array){ 255 | SymbolInfo_Array_destroy(info->meta); 256 | } 257 | free(info); 258 | } 259 | 260 | SymbolInfo_Array_t SymbolInfo_Array_createBaked(Symbol_Value_Type elementType, SymbolInfo_t elementStructInfo, int dimensions[], int dimensionCount){ 261 | SymbolInfo_Array_Raw info = (SymbolInfo_Array_Raw)malloc(sizeof(SymbolInfo_Array)); 262 | info->dimensionCount = dimensionCount; 263 | info->dimension = dimensions[0]; 264 | if(dimensionCount > 1){ 265 | info->elementType = SVT_Array; 266 | info->elementMeta = SymbolInfo_Array_createBaked(elementType, elementStructInfo, dimensions+1, dimensionCount-1); 267 | }else{ 268 | info->elementType = elementType; 269 | info->elementMeta = elementStructInfo; 270 | } 271 | return info; 272 | } 273 | 274 | void SymbolInfo_Array_destroy(SymbolInfo_Array_t info) { 275 | if(info == NULL) 276 | return; 277 | if(info->elementType == SVT_Array){ 278 | SymbolInfo_Array_destroy(info->elementMeta); 279 | } 280 | free(info); 281 | } 282 | 283 | SymbolInfo_Function_t 284 | SymbolInfo_Function_createBaked(Symbol_Value_Type returnType, SymbolInfo_t returnTypeMeta, Symbol_Value_Type parameterTypes[], 285 | char *parameterNames[], void *parametersMeta[], int parameterCount){ 286 | SymbolInfo_Function_Raw rawInfo = (SymbolInfo_Function_Raw)malloc(sizeof(SymbolInfo_Function)); 287 | rawInfo->returnType = returnType; 288 | rawInfo->returnTypeMeta = returnTypeMeta; 289 | rawInfo->parameterCount = parameterCount; 290 | // cast to void* to make clang-tidy happy 291 | rawInfo->parameters = (void*)(SymbolInfo_Parameter_Raw*)malloc(sizeof(SymbolInfo_Parameter_Raw) * parameterCount); 292 | for(int i = 0; i < parameterCount; i++){ 293 | rawInfo->parameters[i] = SymbolInfo_Parameter_createBaked(parameterTypes[i], parameterNames[i], parametersMeta[i]); 294 | } 295 | rawInfo->isDefined = 0; 296 | return rawInfo; 297 | } 298 | 299 | void SymbolInfo_Function_destroy(SymbolInfo_Function_t info) { 300 | if(info == NULL) 301 | return; 302 | if(info->functionName != NULL) 303 | free(info->functionName); 304 | if(info->returnType == SVT_Array){ 305 | SymbolInfo_Array_destroy(info->returnTypeMeta); 306 | } 307 | for(int i = 0; i < info->parameterCount; i++){ 308 | SymbolInfo_Parameter_t parameter = info->parameters[i]; 309 | if(parameter->parameterName != NULL) 310 | free(parameter->parameterName); 311 | if(parameter->parameterType == SVT_Array){ 312 | SymbolInfo_Array_destroy(parameter->parameterMeta); 313 | } 314 | free(parameter); 315 | } 316 | free(info->parameters); 317 | free(info); 318 | } 319 | 320 | int SymbolInfo_Function_hasParameterName(SymbolInfo_Function_t functionInfo, char* parameterName){ 321 | if(parameterName == NULL) 322 | { 323 | return 0; 324 | } 325 | for(int i = 0; i < functionInfo->parameterCount; i++) 326 | { 327 | SymbolInfo_Parameter_t parameter = functionInfo->parameters[i]; 328 | if(parameter->parameterName != NULL && strcmp(parameter->parameterName, parameterName) == 0) 329 | { 330 | return 1; 331 | } 332 | } 333 | return 0; 334 | } 335 | 336 | void SymbolInfo_Function_addParameter(SymbolInfo_Function_t functionInfo, SymbolInfo_t parameter){ 337 | functionInfo->parameters[functionInfo->parameterCount] = parameter; 338 | functionInfo->parameterCount++; 339 | } 340 | 341 | /** 342 | * Get the name of the function. 343 | * @param info The baked SymbolInfo_Function. 344 | * @return The name of the function. 345 | */ 346 | char* SymbolInfo_Function_getName(SymbolInfo_Function_t info){ 347 | return info->functionName; 348 | } 349 | 350 | /** 351 | * Set the name of the function. 352 | * @param info The baked SymbolInfo_Function. 353 | * @param name The name of the function, will be duplicated. 354 | */ 355 | void SymbolInfo_Function_setName(SymbolInfo_Function_t info, char* name){ 356 | info->functionName = name == NULL ? NULL : strdup(name); 357 | } 358 | 359 | SymbolInfo_Parameter_t SymbolInfo_Parameter_createBaked(Symbol_Value_Type type, char* parameterName, SymbolInfo_t meta){ 360 | SymbolInfo_Parameter_Raw info = (SymbolInfo_Parameter_Raw)malloc(sizeof(SymbolInfo_Parameter)); 361 | info->parameterType = type; 362 | info->parameterName = parameterName == NULL ? NULL : strdup(parameterName); 363 | info->parameterMeta = meta; 364 | return info; 365 | } 366 | 367 | SymbolInfo_Struct_t 368 | SymbolInfo_Struct_createBaked(Symbol_Value_Type *memberTypes, char **memberNames, void **memberMeta, int memberCount) { 369 | SymbolInfo_Struct_Raw info = (SymbolInfo_Struct_Raw)malloc(sizeof(SymbolInfo_Struct)); 370 | info->memberCount = memberCount; 371 | // cast to void* to make clang-tidy happy 372 | info->members = (void*)(SymbolInfo_Member_Raw*)malloc(sizeof(SymbolInfo_Member_Raw) * memberCount); 373 | for(int i = 0; i < memberCount; i++){ 374 | info->members[i] = SymbolInfo_Member_create(memberTypes[i], memberNames[i], memberMeta[i]); 375 | } 376 | return info; 377 | } 378 | 379 | 380 | void SymbolInfo_Struct_destroy(SymbolInfo_Struct_t info) { 381 | if(info == NULL) 382 | return; 383 | #ifdef SYMBOL_TABLE_STRUCT_NAME 384 | if(info->structName != NULL) 385 | free(info->structName); 386 | #endif 387 | if(info->memberCount == 0) 388 | return; 389 | for(int i = 0; i < info->memberCount; i++){ 390 | SymbolInfo_Member_t member = info->members[i]; 391 | SymbolInfo_Member_destroy(member); 392 | } 393 | free(info->members); 394 | free(info); 395 | } 396 | 397 | int SymbolInfo_Struct_checkMemberName(SymbolInfo_Struct_t info, char* memberName){ 398 | for(int i = 0; i < info->memberCount; i++){ 399 | SymbolInfo_Member_t member = info->members[i]; 400 | if(strcmp(member->memberName, memberName) == 0){ 401 | return 1; 402 | } 403 | } 404 | return 0; 405 | } 406 | 407 | 408 | void SymbolInfo_Struct_insertMember(SymbolInfo_Struct_t info, SymbolInfo_t memberInfo){ 409 | info->members[info->memberCount] = memberInfo; 410 | info->memberCount++; 411 | ((SymbolInfo_Member_t) memberInfo)->offset = info->size; 412 | info->size += SymbolValue_getSize(((SymbolInfo_Member_t) memberInfo)->memberType, ((SymbolInfo_Member_t) memberInfo)->memberMeta); 413 | } 414 | 415 | 416 | #ifdef SYMBOL_TABLE_STRUCT_NAME 417 | char* SymbolInfo_Struct_getName(SymbolInfo_Struct_t info) 418 | { 419 | if(info == NULL) 420 | return NULL; 421 | return info->structName; 422 | } 423 | 424 | void SymbolInfo_Struct_setName(SymbolInfo_Struct_t info, char* name) 425 | { 426 | info->structName = name == NULL ? NULL : strdup(name); 427 | } 428 | #endif 429 | 430 | SymbolInfo_Member_Raw SymbolInfo_Member_create(Symbol_Value_Type memberType, char* memberName, void *memberMeta) { 431 | SymbolInfo_Member_Raw rawInfo = (SymbolInfo_Member_Raw)malloc(sizeof(SymbolInfo_Member)); 432 | rawInfo->memberType = memberType; 433 | rawInfo->memberName = memberName == NULL ? NULL : strdup(memberName); 434 | rawInfo->memberMeta = memberMeta; 435 | return rawInfo; 436 | } 437 | 438 | SymbolInfo_Member_t SymbolInfo_Member_createBaked(Symbol_Value_Type memberType, char* memberName, SymbolInfo_t memberMeta){ 439 | SymbolInfo_Member_Raw info = (SymbolInfo_Member_Raw)malloc(sizeof(SymbolInfo_Member)); 440 | info->memberType = memberType; 441 | info->memberName = memberName == NULL ? NULL : strdup(memberName); 442 | info->memberMeta = memberMeta; 443 | return info; 444 | } 445 | 446 | void SymbolInfo_Member_destroy(SymbolInfo_Member_t info) { 447 | if(info == NULL) 448 | return; 449 | SymbolInfo_Member_t member = info; 450 | if(member->memberName != NULL) 451 | free(member->memberName); 452 | if(member->memberType == SVT_Array){ 453 | SymbolInfo_Array_destroy(member->memberMeta); 454 | } 455 | free(member); 456 | } 457 | 458 | void SymbolRecord_printDebug(SymbolRecord_t record, char *buffer, int bufferSize) { 459 | if(record == NULL){ 460 | snprintf(buffer, bufferSize, "NULL SymbolRecord"); 461 | return; 462 | } 463 | switch (record->type) { 464 | case ST_Variable: 465 | SymbolInfo_Variable_printDebug(record->info, buffer, bufferSize); 466 | break; 467 | case ST_Function: 468 | SymbolInfo_Function_printDebug(record->info, buffer, bufferSize); 469 | break; 470 | case ST_Struct: 471 | SymbolInfo_Struct_printDebug(record->info, buffer, bufferSize); 472 | break; 473 | default: 474 | snprintf(buffer, bufferSize, "Unknown SymbolRecord type"); 475 | break; 476 | 477 | } 478 | } 479 | 480 | 481 | int SymbolRecord_isSymbolDefined(SymbolRecord_t record) { 482 | switch(record->type){ 483 | case ST_Variable: 484 | return 1; 485 | case ST_Function: { 486 | SymbolInfo_Function_t functionInfo = (SymbolInfo_Function_t) record->info; 487 | return functionInfo->isDefined; 488 | } 489 | case ST_Struct: 490 | return 1; 491 | default: 492 | return 0; 493 | } 494 | } 495 | 496 | int SymbolTable_getNextVarID(SymbolTable_t table) { 497 | return table->nextVarID++; 498 | } 499 | 500 | void SymbolTable_generateNextLabelName(SymbolTable_t table, char* buffer, int bufferSize){ 501 | SymbolTable_generateNextLabelNameWithSuffix(table, buffer, bufferSize, ""); 502 | } 503 | 504 | void SymbolTable_generateNextLabelNameWithSuffix(SymbolTable_t table, char* buffer, int bufferSize, char* suffix){ 505 | snprintf(buffer, bufferSize, "label$%d%s", table->nextLabelID++, suffix); 506 | } 507 | 508 | void SymbolInfo_Variable_printDebug(SymbolInfo_t variableInfo, char *buffer, int size) { 509 | SymbolInfo_Variable_t info = (SymbolInfo_Variable_t)variableInfo; 510 | SymbolInfo_DebugHelper_getTypeString(info->type, info->meta, buffer, size); 511 | if(info->type == SVT_Struct){ 512 | char structDefBuffer[256]; 513 | SymbolInfo_Struct_printDebug(info->meta, structDefBuffer, sizeof(structDefBuffer)); 514 | snprintf(buffer+strlen(buffer), size-strlen(buffer), "\n\tVariable %s", structDefBuffer); 515 | } 516 | if(info->type == SVT_Array) 517 | { 518 | SymbolInfo_Array_t arrayInfo = info->meta; 519 | if(arrayInfo->elementType == SVT_Struct){ 520 | char structDefBuffer[256]; 521 | SymbolInfo_Struct_printDebug(arrayInfo->elementMeta, structDefBuffer, sizeof(structDefBuffer)); 522 | snprintf(buffer+strlen(buffer), size-strlen(buffer), "\n\tArray %s", structDefBuffer); 523 | } 524 | } 525 | } 526 | 527 | void SymbolInfo_Function_printDebug(SymbolInfo_t functionInfo, char *buffer, int size) { 528 | SymbolInfo_Function_t info = (SymbolInfo_Function_t)functionInfo; 529 | char returnTypeBuffer[256]; 530 | SymbolInfo_DebugHelper_getTypeString(info->returnType, info->returnTypeMeta, returnTypeBuffer, sizeof(returnTypeBuffer)); 531 | #ifndef SYMBOL_TABLE_FUNCTION_NAME 532 | snprintf(buffer, size, "Function: %s(", returnTypeBuffer); 533 | #else 534 | snprintf(buffer, size, "Function: %s %s(", returnTypeBuffer, info->functionName == NULL ? "NULL" : info->functionName); 535 | #endif 536 | int offset = (int)strlen(buffer); 537 | for(int i = 0; i < info->parameterCount; i++){ 538 | char parameterTypeBuffer[256]; 539 | SymbolInfo_Parameter_t paraInfo = info->parameters[i]; 540 | SymbolInfo_DebugHelper_getTypeString(paraInfo->parameterType, paraInfo->parameterMeta, parameterTypeBuffer, sizeof(parameterTypeBuffer)); 541 | offset += snprintf(buffer+offset, size-offset, "%s %s", parameterTypeBuffer, paraInfo->parameterName == NULL ? "NULL" : paraInfo->parameterName); 542 | if(i != info->parameterCount - 1){ 543 | offset += snprintf(buffer+offset, size-offset, ", "); 544 | } 545 | } 546 | snprintf(buffer+offset, size-offset, ")"); 547 | if(info->returnType== SVT_Struct){ 548 | char structDefBuffer[256]; 549 | SymbolInfo_Struct_printDebug(info->returnTypeMeta, structDefBuffer, sizeof(structDefBuffer)); 550 | snprintf(buffer+strlen(buffer), size-strlen(buffer), "\n\tReturn %s", structDefBuffer); 551 | } 552 | for(int i = 0; i < info->parameterCount; i++) { 553 | SymbolInfo_Parameter_t param = info->parameters[i]; 554 | if(param->parameterType == SVT_Struct){ 555 | char structDefBuffer[256]; 556 | SymbolInfo_Struct_printDebug(param->parameterMeta, structDefBuffer, sizeof(structDefBuffer)); 557 | snprintf(buffer+strlen(buffer), size-strlen(buffer), "\n\tParam [%d] %s", i, structDefBuffer); 558 | } 559 | } 560 | } 561 | 562 | void SymbolInfo_Struct_printDebug(SymbolInfo_t structInfo, char *buffer, int size) { 563 | SymbolInfo_Struct_t info = (SymbolInfo_Struct_t)structInfo; 564 | #ifndef SYMBOL_TABLE_STRUCT_NAME 565 | snprintf(buffer, size, "Struct: {"); 566 | #else 567 | snprintf(buffer, size, "Struct \"%s\": {", info->structName == NULL ? "NULL" : info->structName); 568 | #endif 569 | int offset = (int)strlen(buffer); 570 | for(int i = 0; i < info->memberCount; i++){ 571 | char memberTypeBuffer[256]; 572 | SymbolInfo_Member_t memberInfo = info->members[i]; 573 | SymbolInfo_DebugHelper_getTypeString(memberInfo->memberType, memberInfo->memberMeta, memberTypeBuffer, sizeof(memberTypeBuffer)); 574 | offset += snprintf(buffer+offset, size-offset, "%s %s", memberTypeBuffer, memberInfo->memberName == NULL ? "NULL" : memberInfo->memberName); 575 | if(i != info->memberCount - 1){ 576 | offset += snprintf(buffer+offset, size-offset, ", "); 577 | } 578 | } 579 | snprintf(buffer+offset, size-offset, "}"); 580 | for(int i = 0; i < info->memberCount; i++) { 581 | SymbolInfo_Member_t member = info->members[i]; 582 | if(member->memberType == SVT_Struct){ 583 | char structDefBuffer[256]; 584 | SymbolInfo_Struct_printDebug(member->memberMeta, structDefBuffer, sizeof(structDefBuffer)); 585 | snprintf(buffer+strlen(buffer), size-strlen(buffer), "\n\tMember [%s] %s", member->memberName, structDefBuffer); 586 | } 587 | } 588 | } 589 | 590 | void SymbolInfo_DebugHelper_getTypeString(Symbol_Value_Type e, void* meta, char *buffer, int bufferSize) { 591 | switch (e) { 592 | case SVT_Int: 593 | snprintf(buffer, bufferSize, "int"); 594 | break; 595 | case SVT_Float: 596 | snprintf(buffer, bufferSize, "float"); 597 | break; 598 | case SVT_Struct: 599 | #ifndef SYMBOL_TABLE_STRUCT_NAME 600 | snprintf(buffer, bufferSize, "struct"); 601 | #else 602 | snprintf(buffer, bufferSize, "struct \"%s\"", SymbolInfo_Struct_getName((SymbolInfo_Struct_t)meta)); 603 | #endif 604 | break; 605 | case SVT_Array: { 606 | SymbolInfo_Array_t arrayInfo = (SymbolInfo_Array_t) meta; 607 | char dimBuffer[256]; 608 | char dimListBuffer[256]; 609 | snprintf(dimBuffer, sizeof(dimBuffer), "[%d]", arrayInfo->dimension); 610 | while(arrayInfo->dimensionCount > 1){ 611 | arrayInfo = arrayInfo->elementMeta; 612 | snprintf(dimBuffer, sizeof(dimBuffer), "[%d]", arrayInfo->dimension); 613 | snprintf(dimListBuffer+strlen(dimListBuffer), sizeof(dimListBuffer)-strlen(dimListBuffer), "%s", dimBuffer); 614 | } 615 | char elementTypeBuffer[256]; 616 | SymbolInfo_DebugHelper_getTypeString(arrayInfo->elementType, arrayInfo->elementMeta, elementTypeBuffer, sizeof(elementTypeBuffer)); 617 | snprintf(buffer, bufferSize, "%s %s", elementTypeBuffer , dimBuffer); 618 | break; 619 | } 620 | case SVT_Void: 621 | snprintf(buffer, bufferSize, "void"); 622 | break; 623 | default: 624 | snprintf(buffer, bufferSize, "Unknown_Type"); 625 | break; 626 | } 627 | } 628 | 629 | 630 | -------------------------------------------------------------------------------- /src/Structure/TokenName.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Crystal on 2024/3/18. 3 | // 4 | #include "CmmParserTypes.h" 5 | #include "Structure/TokenName.h" 6 | 7 | char GrammarSymbolNames[ARGS - PROGRAM + 1][20] = { 8 | "Program", 9 | "ExtDefList", 10 | "ExtDef", 11 | "ExtDecList", 12 | "Specifier", 13 | "StructSpecifier", 14 | "OptTag", 15 | "Tag", 16 | "VarDec", 17 | "FunDec", 18 | "VarList", 19 | "ParamDec", 20 | "CompSt", 21 | "StmtList", 22 | "Stmt", 23 | "DefList", 24 | "Def", 25 | "DecList", 26 | "Dec", 27 | "Exp", 28 | "Args" 29 | }; 30 | 31 | char TokenNames[WHILE - INT + 1][20] = { 32 | "INT", 33 | "FLOAT", 34 | "ID", 35 | "SEMI", 36 | "COMMA", 37 | "ASSIGNOP", 38 | "RELOP", 39 | "RELOP", 40 | "RELOP", 41 | "RELOP", 42 | "RELOP", 43 | "RELOP", 44 | "PLUS", 45 | "MINUS", 46 | "STAR", 47 | "DIV", 48 | "AND", 49 | "OR", 50 | "DOT", 51 | "NOT", 52 | "TYPE", 53 | "LP", 54 | "RP", 55 | "LB", 56 | "RB", 57 | "LC", 58 | "RC", 59 | "STRUCT", 60 | "RETURN", 61 | "IF", 62 | "ELSE", 63 | "WHILE" 64 | }; 65 | 66 | const char *getGrammarSymbolName(int grammarSymbol) { 67 | return GrammarSymbolNames[grammarSymbol - PROGRAM]; 68 | } 69 | 70 | const char* getTokenName(int token) 71 | { 72 | return TokenNames[token - INT]; 73 | } 74 | --------------------------------------------------------------------------------