├── .gitignore ├── CMakeLists.txt ├── README.md ├── ast.h ├── codegen.cc ├── codegen.h ├── demo ├── 2048.c ├── array.c ├── binary_err.c ├── cast.c ├── cast2.c ├── e1.c ├── e10.c ├── e11.c ├── e12.c ├── e13.c ├── e14.c ├── e15.c ├── e16.c ├── e17.c ├── e18.c ├── e19.c ├── e2.c ├── e20.c ├── e21.c ├── e22.c ├── e23.c ├── e3.c ├── e4.c ├── e5.c ├── e6.c ├── e7.c ├── e8.c ├── e9.c ├── eval1.c ├── eval2.c ├── expr.txt ├── lisp.bc ├── lisp.c ├── lisp.lisp ├── lisp2.lisp ├── lispc.bc ├── maze.c ├── nqueen.c ├── test_struct_ret.c └── typedef.c ├── diag.inc ├── diag_engine.cc ├── diag_engine.h ├── doc └── ebnf.txt ├── eval_constant.cc ├── eval_constant.h ├── lexer.cc ├── lexer.h ├── main.cc ├── parser.cc ├── parser.h ├── print_visitor.cc ├── print_visitor.h ├── scope.cc ├── scope.h ├── script ├── apple_m.sh ├── test.sh └── ubuntu20_x86.sh ├── sema.cc ├── sema.h ├── studybackend ├── day01.c └── day01.s ├── test ├── CMakeLists.txt ├── codegen │ ├── CMakeLists.txt │ └── codegen_test.cc ├── lexer │ ├── CMakeLists.txt │ └── lexer_test.cc └── parser │ ├── CMakeLists.txt │ └── parser_test.cc ├── type.cc └── type.h /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | .vscode 4 | *.ll 5 | *.o 6 | *.out 7 | _deps/ 8 | bin/ 9 | build/ 10 | lib/ 11 | cmake-build* 12 | 13 | cmake_install.cmake 14 | CMakeCache.txt 15 | CMakeFiles/ 16 | Makefile 17 | test/*/*.cmake 18 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 4 | project(Subc) 5 | set(SUBC_BUILT_STANDALONE TRUE) 6 | endif() 7 | 8 | if (SUBC_BUILT_STANDALONE) 9 | set(CMAKE_C_STANDARD 99) 10 | set(CMAKE_CXX_STANDARD 17) 11 | 12 | find_package(LLVM REQUIRED CONFIG) 13 | 14 | list(APPEND CMAKE_MODULE_PATH ${LLVM_CMAKE_DIR}) 15 | 16 | include(AddLLVM) 17 | 18 | include_directories( . "${LLVM_BINARY_DIR}/include" "${LLVM_INCLUDE_DIR}") 19 | add_definitions(${LLVM_DEFINITIONS}) 20 | else() 21 | include_directories( . ) 22 | endif() 23 | 24 | if (NOT ${LLVM_ENABLE_RTTI}) 25 | # For non-MSVC compilers 26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") 27 | endif() 28 | 29 | SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) 30 | 31 | set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} Support Core ExecutionEngine CodeGen MC MCJIT OrcJit native TargetParser) 32 | 33 | add_llvm_executable(subc main.cc lexer.cc parser.cc print_visitor.cc type.cc scope.cc sema.cc diag_engine.cc codegen.cc eval_constant.cc) 34 | 35 | add_subdirectory(test) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 基于llvm的subc实现 2 | 3 | ## 零:B站课程链接 4 | [LLVM前端实践之从0到1实现一个C编译器](https://www.bilibili.com/cheese/play/ss31453?csource=private_space_class_null&spm_id_from=333.999.0.0) 5 | 6 | ## 一:开发环境 7 | Ubuntu20.04 + llvm20 8 | 9 | 构建步骤 10 | ``` 11 | git clone git@github.com:iiicp/subc-llvm.git 12 | cd subc-llvm 13 | mkdir build && cd build 14 | cmake .. -GNinja -DLLVM_DIR=`llvm install home`/lib/cmake/llvm 15 | ninja 16 | ``` 17 | 18 | 目前在下列环境下编译通过: 19 | * Ubuntu 20.04 + llvm 20 20 | * Ubuntu 22.04 + llvm 20 21 | * MacOS 14 + llvm 20 22 | 23 | ## 二:实现的完整文法 24 | ``` 25 | prog ::= external-decl+ 26 | external-decl ::= func-def | decl-stmt 27 | func-def ::= decl-spec declarator block-stmt 28 | block-stmt ::= stmt* 29 | stmt ::= decl-stmt | expr-stmt | null-stmt | if-stmt | block-stmt | for-stmt | 30 | break-stmt | continue-stmt | while-stmt | do-while-stm | switch-stmt | 31 | case-stmt | default-stmt 32 | decl-stmt ::= decl-spec init-declarator-list? ";" 33 | init-declarator-list ::= declarator (= initializer)? ("," declarator (= initializer)?)* 34 | decl-spec ::= "int" | struct-or-union-specifier 35 | struct-or-union-specifier ::= struct-or-union identifier "{" (decl-spec declarator(, declarator)* ";")* "}" 36 | struct-or-union identifier 37 | struct-or-union := "struct" | "union" 38 | 39 | declarator ::= "*"* direct-declarator 40 | direct-declarator ::= identifier | direct-declarator "[" assign "]" 41 | | direct-declarator "(" parameter-type-list? ")" 42 | parameter-type-list ::= decl-spec declarator (, decl-spec declarator)* (", " "...")? 43 | 44 | initializer ::= assign | "{" initializer ("," initializer)* "}" 45 | 46 | null-stmt ::= ";" 47 | if-stmt ::= "if" "(" expr ")" stmt ( "else" stmt )? 48 | for-stmt ::= "for" "(" expr? ";" expr? ";" expr? ")" stmt 49 | "for" "(" decl-stmt expr? ";" expr? ")" stmt 50 | while-stmt ::= "while" "(" expr ")" stmt 51 | do-while-stmt ::= "do" stmt "while" "(" expr ")" ";" 52 | switch-stmt ::= "switch" "(" expr ")" stmt 53 | case-stmt ::= "case" expr ":" stmt 54 | default-stmt ::= "default" ":" stmt 55 | block-stmt ::= "{" stmt* "}" 56 | break-stmt ::= "break" ";" 57 | continue-stmt ::= "continue" ";" 58 | expr-stmt ::= expr ";" 59 | 60 | expr ::= assign (, assign )* 61 | assign ::= conditional ("="|"+="|"-="|"*="|"/="|"%="|"<<="|">>="|"&="|"^="|"|=" asign)? 62 | conditional ::= logor ("?" expr ":" conditional)? 63 | logor ::= logand ("||" logand)* 64 | logand ::= bitor ("&&" bitor)* 65 | bitor ::= bitxor ("|" bitxor)* 66 | bitxor ::= bitand ("^" bitand)* 67 | bitand ::= equal ("&" equal)* 68 | equal ::= relational ("==" | "!=" relational)* 69 | relational ::= shift ("<"|">"|"<="|">=" shift)* 70 | shift ::= add ("<<" | ">>" add)* 71 | add ::= mult ("+" | "-" mult)* 72 | mult ::= cast ("*" | "/" | "%" cast)* 73 | cast ::= unary | "(" type-name ")" cast 74 | unary ::= postfix | ("++"|"--"|"&"|"*"|"+"|"-"|"~"|"!"|"sizeof") unary 75 | | "sizeof" "(" type-name ")" 76 | postfix ::= primary | postfix ("++"|"--") | postfix "[" expr "]" 77 | | postfix "." identifier 78 | | postfix "->" identifier 79 | | postfix "(" arg-expr-list? ")" 80 | arg-expr-list := assign ("," assign)* 81 | primary ::= identifier | number | "(" expr ")" 82 | number ::= ([0-9])+ 83 | identifier ::= (a-zA-Z_)(a-zA-Z0-9_)* 84 | type-name ::= decl-spec abstract-declarator? 85 | abstract-declarator ::= "*"* direct-abstract-declarator? 86 | direct-abstract-declarator ::= direct-abstract-declarator? "[" assign "]" 87 | ``` 88 | 89 | ## 三:测试代码 90 | 91 | ### demo1 92 | ``` 93 | struct { 94 | int a, b; 95 | struct {int d; int a;} c; 96 | } a = {1,2, {10}}; 97 | 98 | int sum(int n) { 99 | int ret = 0; 100 | for (int i = 0; i <= n; ++i) { 101 | ret += i; 102 | } 103 | return ret; 104 | } 105 | 106 | int main() { 107 | return a.c.d + sum(100); 108 | } 109 | ``` 110 | 111 | ### demo2 112 | ``` 113 | // How to run: 114 | // 115 | // $ ./9cc examples/nqueen.c > tmp-nqueen.s 116 | // $ gcc -static -o tmp-nqueen tmp-nqueen.s 117 | // $ ./tmp-nqueen 118 | 119 | int printf(const char *fmg, ...); 120 | 121 | void print_board(int board[][10]) { 122 | for (int i = 0; i < 10; i++) { 123 | for (int j = 0; j < 10; j++) 124 | if (board[i][j]) 125 | printf("Q "); 126 | else 127 | printf(". "); 128 | printf("\n"); 129 | } 130 | printf("\n\n"); 131 | } 132 | 133 | int conflict(int board[][10], int row, int col) { 134 | for (int i = 0; i < row; i++) { 135 | if (board[i][col]) 136 | return 1; 137 | int j = row - i; 138 | if (0 < col - j + 1 && board[i][col - j]) 139 | return 1; 140 | if (col + j < 10 && board[i][col + j]) 141 | return 1; 142 | } 143 | return 0; 144 | } 145 | 146 | void solve(int board[][10], int row) { 147 | if (row > 9) { 148 | print_board(board); 149 | } 150 | for (int i = 0; i < 10; i++) { 151 | if (conflict(board, row, i)) { 152 | } else { 153 | board[row][i] = 1; 154 | solve(board, row + 1); 155 | board[row][i] = 0; 156 | } 157 | } 158 | } 159 | 160 | int main() { 161 | int board[100]; 162 | for (int i = 0; i < 100; i++) 163 | board[i] = 0; 164 | solve(board, 0); 165 | return 0; 166 | } 167 | ``` 168 | 169 | ### 详情见测试用例 170 | -------------------------------------------------------------------------------- /ast.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "llvm/IR/Value.h" 5 | #include "type.h" 6 | #include "lexer.h" 7 | 8 | class Program; 9 | class VariableDecl; 10 | class FuncDecl; 11 | class BinaryExpr; 12 | class ThreeExpr; 13 | class CastExpr; 14 | class UnaryExpr; 15 | class SizeOfExpr; 16 | class PostIncExpr; 17 | class PostDecExpr; 18 | class PostSubscript; 19 | class PostMemberDotExpr; 20 | class PostMemberArrowExpr; 21 | class PostFuncCall; 22 | class NumberExpr; 23 | class StringExpr; 24 | class VariableAccessExpr; 25 | class IfStmt; 26 | class DeclStmt; 27 | class BlockStmt; 28 | class ForStmt; 29 | class BreakStmt; 30 | class ContinueStmt; 31 | class ReturnStmt; 32 | class SwitchStmt; 33 | class CaseStmt; 34 | class DefaultStmt; 35 | class DoWhileStmt; 36 | 37 | class Visitor { 38 | public: 39 | virtual ~Visitor() {} 40 | virtual llvm::Value * VisitProgram(Program *p) = 0; 41 | virtual llvm::Value * VisitBlockStmt(BlockStmt *p) = 0; 42 | virtual llvm::Value * VisitDeclStmt(DeclStmt *p) = 0; 43 | virtual llvm::Value * VisitIfStmt(IfStmt *p) = 0; 44 | virtual llvm::Value * VisitForStmt(ForStmt *p) = 0; 45 | virtual llvm::Value * VisitBreakStmt(BreakStmt *p) = 0; 46 | virtual llvm::Value * VisitContinueStmt(ContinueStmt *p) = 0; 47 | virtual llvm::Value * VisitReturnStmt(ReturnStmt *p) = 0; 48 | virtual llvm::Value * VisitSwitchStmt(SwitchStmt *p) = 0; 49 | virtual llvm::Value * VisitCaseStmt(CaseStmt *p) = 0; 50 | virtual llvm::Value * VisitDefaultStmt(DefaultStmt *p) = 0; 51 | virtual llvm::Value * VisitDoWhileStmt(DoWhileStmt *p) = 0; 52 | virtual llvm::Value * VisitVariableDecl(VariableDecl *decl) = 0; 53 | virtual llvm::Value * VisitFuncDecl(FuncDecl *decl) = 0; 54 | virtual llvm::Value * VisitNumberExpr(NumberExpr *expr) = 0; 55 | virtual llvm::Value * VisitStringExpr(StringExpr *expr) = 0; 56 | virtual llvm::Value * VisitBinaryExpr(BinaryExpr *binaryExpr) = 0; 57 | virtual llvm::Value * VisitUnaryExpr(UnaryExpr *expr) = 0; 58 | virtual llvm::Value * VisitCastExpr(CastExpr *expr) = 0; 59 | virtual llvm::Value * VisitSizeOfExpr(SizeOfExpr *expr) = 0; 60 | virtual llvm::Value * VisitPostIncExpr(PostIncExpr *expr) = 0; 61 | virtual llvm::Value * VisitPostDecExpr(PostDecExpr *expr) = 0; 62 | virtual llvm::Value * VisitPostSubscript(PostSubscript *expr) = 0; 63 | virtual llvm::Value * VisitPostMemberDotExpr(PostMemberDotExpr *expr) = 0; 64 | virtual llvm::Value * VisitPostMemberArrowExpr(PostMemberArrowExpr *expr) = 0; 65 | virtual llvm::Value * VisitPostFuncCall(PostFuncCall *expr) = 0; 66 | virtual llvm::Value * VisitThreeExpr(ThreeExpr *expr) = 0; 67 | virtual llvm::Value * VisitVariableAccessExpr(VariableAccessExpr *factorExpr) = 0; 68 | }; 69 | 70 | /// llvm rtti 71 | class AstNode { 72 | public: 73 | enum Kind{ 74 | ND_BlockStmt, 75 | ND_DeclStmt, 76 | ND_ForStmt, 77 | ND_BreakStmt, 78 | ND_ContinueStmt, 79 | ND_IfStmt, 80 | ND_ReturnStmt, 81 | ND_SwitchStmt, 82 | ND_CaseStmt, 83 | ND_DefaultStmt, 84 | ND_DoWhileStmt, 85 | ND_VariableDecl, 86 | ND_FuncDecl, 87 | ND_BinaryExpr, 88 | ND_ThreeExpr, 89 | ND_UnaryExpr, 90 | ND_CastExpr, 91 | ND_SizeOfExpr, 92 | ND_PostIncExpr, 93 | ND_PostDecExpr, 94 | ND_PostSubscript, 95 | ND_PostMemberDotExpr, 96 | ND_PostMemberArrowExpr, 97 | ND_PostFuncCall, 98 | ND_NumberExpr, 99 | ND_VariableAccessExpr, 100 | ND_StringExpr 101 | }; 102 | private: 103 | const Kind kind; 104 | public: 105 | virtual ~AstNode() {} 106 | std::shared_ptr ty; 107 | Token tok; 108 | bool isLValue{false}; 109 | AstNode(Kind kind): kind(kind) {} 110 | Kind GetKind() const {return kind;} 111 | virtual llvm::Value * Accept(Visitor *v) {return nullptr;} 112 | }; 113 | 114 | class BlockStmt : public AstNode { 115 | public: 116 | std::vector> nodeVec; 117 | public: 118 | BlockStmt():AstNode(ND_BlockStmt) {} 119 | 120 | llvm::Value * Accept(Visitor *v) override { 121 | return v->VisitBlockStmt(this); 122 | } 123 | 124 | static bool classof(const AstNode *node) { 125 | return node->GetKind() == ND_BlockStmt; 126 | } 127 | }; 128 | 129 | 130 | class DeclStmt : public AstNode { 131 | public: 132 | std::vector> nodeVec; 133 | public: 134 | DeclStmt():AstNode(ND_DeclStmt) {} 135 | 136 | llvm::Value * Accept(Visitor *v) override { 137 | return v->VisitDeclStmt(this); 138 | } 139 | 140 | static bool classof(const AstNode *node) { 141 | return node->GetKind() == ND_DeclStmt; 142 | } 143 | }; 144 | 145 | class IfStmt : public AstNode { 146 | public: 147 | std::shared_ptr condNode; 148 | std::shared_ptr thenNode; 149 | std::shared_ptr elseNode; 150 | public: 151 | IfStmt():AstNode(ND_IfStmt) {} 152 | 153 | llvm::Value * Accept(Visitor *v) override { 154 | return v->VisitIfStmt(this); 155 | } 156 | 157 | static bool classof(const AstNode *node) { 158 | return node->GetKind() == ND_IfStmt; 159 | } 160 | }; 161 | 162 | /* 163 | for (int i = 0; i < 100; i = i + 1) { 164 | aa = aa + 1; 165 | } 166 | */ 167 | class ForStmt : public AstNode { 168 | public: 169 | std::shared_ptr initNode; 170 | std::shared_ptr condNode; 171 | std::shared_ptr incNode; 172 | std::shared_ptr bodyNode; 173 | public: 174 | ForStmt():AstNode(ND_ForStmt) {} 175 | 176 | llvm::Value * Accept(Visitor *v) override { 177 | return v->VisitForStmt(this); 178 | } 179 | 180 | static bool classof(const AstNode *node) { 181 | return node->GetKind() == ND_ForStmt; 182 | } 183 | }; 184 | 185 | class BreakStmt : public AstNode { 186 | public: 187 | std::shared_ptr target; 188 | public: 189 | BreakStmt():AstNode(ND_BreakStmt) {} 190 | 191 | llvm::Value * Accept(Visitor *v) override { 192 | return v->VisitBreakStmt(this); 193 | } 194 | 195 | static bool classof(const AstNode *node) { 196 | return node->GetKind() == ND_BreakStmt; 197 | } 198 | }; 199 | 200 | class ContinueStmt : public AstNode { 201 | public: 202 | std::shared_ptr target; 203 | public: 204 | ContinueStmt():AstNode(ND_ContinueStmt) {} 205 | 206 | llvm::Value * Accept(Visitor *v) override { 207 | return v->VisitContinueStmt(this); 208 | } 209 | 210 | static bool classof(const AstNode *node) { 211 | return node->GetKind() == ND_ContinueStmt; 212 | } 213 | }; 214 | 215 | class ReturnStmt : public AstNode { 216 | public: 217 | std::shared_ptr expr{nullptr}; 218 | public: 219 | ReturnStmt():AstNode(ND_ReturnStmt) {} 220 | 221 | llvm::Value * Accept(Visitor *v) override { 222 | return v->VisitReturnStmt(this); 223 | } 224 | 225 | static bool classof(const AstNode *node) { 226 | return node->GetKind() == ND_ReturnStmt; 227 | } 228 | }; 229 | 230 | class SwitchStmt : public AstNode { 231 | public: 232 | std::shared_ptr expr; 233 | std::shared_ptr stmt; 234 | std::shared_ptr defaultStmt{nullptr}; 235 | public: 236 | SwitchStmt():AstNode(ND_SwitchStmt) {} 237 | 238 | llvm::Value * Accept(Visitor *v) override { 239 | return v->VisitSwitchStmt(this); 240 | } 241 | 242 | static bool classof(const AstNode *node) { 243 | return node->GetKind() == ND_SwitchStmt; 244 | } 245 | }; 246 | 247 | class CaseStmt : public AstNode { 248 | public: 249 | std::shared_ptr expr; 250 | std::shared_ptr stmt{nullptr}; 251 | public: 252 | CaseStmt():AstNode(ND_CaseStmt) {} 253 | 254 | llvm::Value * Accept(Visitor *v) override { 255 | return v->VisitCaseStmt(this); 256 | } 257 | 258 | static bool classof(const AstNode *node) { 259 | return node->GetKind() == ND_CaseStmt; 260 | } 261 | }; 262 | 263 | class DefaultStmt : public AstNode { 264 | public: 265 | std::shared_ptr stmt; 266 | public: 267 | DefaultStmt():AstNode(ND_DefaultStmt) {} 268 | 269 | llvm::Value * Accept(Visitor *v) override { 270 | return v->VisitDefaultStmt(this); 271 | } 272 | 273 | static bool classof(const AstNode *node) { 274 | return node->GetKind() == ND_DefaultStmt; 275 | } 276 | }; 277 | 278 | class DoWhileStmt : public AstNode { 279 | public: 280 | std::shared_ptr expr; 281 | std::shared_ptr stmt; 282 | public: 283 | DoWhileStmt():AstNode(ND_DoWhileStmt) {} 284 | 285 | llvm::Value * Accept(Visitor *v) override { 286 | return v->VisitDoWhileStmt(this); 287 | } 288 | 289 | static bool classof(const AstNode *node) { 290 | return node->GetKind() == ND_DoWhileStmt; 291 | } 292 | }; 293 | 294 | class VariableDecl : public AstNode { 295 | public: 296 | struct InitValue { 297 | std::shared_ptr declType; 298 | std::shared_ptr value; 299 | std::vector offsetList; 300 | }; 301 | std::vector> initValues; 302 | bool isGlobal{false}; 303 | VariableDecl():AstNode(ND_VariableDecl) {} 304 | 305 | llvm::Value * Accept(Visitor *v) override { 306 | return v->VisitVariableDecl(this); 307 | } 308 | 309 | static bool classof(const AstNode *node) { 310 | return node->GetKind() == ND_VariableDecl; 311 | } 312 | }; 313 | 314 | class FuncDecl : public AstNode { 315 | public: 316 | std::shared_ptr blockStmt{nullptr}; 317 | FuncDecl():AstNode(ND_FuncDecl) {} 318 | 319 | llvm::Value * Accept(Visitor *v) override { 320 | return v->VisitFuncDecl(this); 321 | } 322 | 323 | static bool classof(const AstNode *node) { 324 | return node->GetKind() == ND_FuncDecl; 325 | } 326 | }; 327 | 328 | enum class BinaryOp { 329 | add, 330 | sub, 331 | mul, 332 | div, 333 | mod, 334 | equal, // == 335 | not_equal, 336 | less, 337 | less_equal, 338 | greater, 339 | greater_equal, 340 | logical_or, 341 | logical_and, 342 | bitwise_or, 343 | bitwise_and, 344 | bitwise_xor, 345 | left_shift, 346 | right_shift, 347 | 348 | comma, 349 | 350 | assign, 351 | add_assign, 352 | sub_assign, 353 | mul_assign, 354 | div_assign, 355 | mod_assign, 356 | bitwise_or_assign, 357 | bitwise_xor_assign, 358 | bitwise_and_assign, 359 | left_shift_assign, 360 | right_shift_assign 361 | }; 362 | 363 | class BinaryExpr : public AstNode{ 364 | public: 365 | BinaryOp op; 366 | std::shared_ptr left; 367 | std::shared_ptr right; 368 | BinaryExpr() : AstNode(ND_BinaryExpr) {} 369 | llvm::Value * Accept(Visitor *v) override { 370 | return v->VisitBinaryExpr(this); 371 | } 372 | 373 | static bool classof(const AstNode *node) { 374 | return node->GetKind() == ND_BinaryExpr; 375 | } 376 | }; 377 | 378 | class ThreeExpr : public AstNode { 379 | public: 380 | std::shared_ptr cond; 381 | std::shared_ptr then; 382 | std::shared_ptr els; 383 | 384 | ThreeExpr() : AstNode(ND_ThreeExpr) {} 385 | llvm::Value * Accept(Visitor *v) override { 386 | return v->VisitThreeExpr(this); 387 | } 388 | 389 | static bool classof(const AstNode *node) { 390 | return node->GetKind() == ND_ThreeExpr; 391 | } 392 | }; 393 | 394 | enum class UnaryOp { 395 | positive, 396 | negative, 397 | deref, 398 | addr, 399 | inc, 400 | dec, 401 | logical_not, 402 | bitwise_not 403 | }; 404 | 405 | class UnaryExpr : public AstNode { 406 | public: 407 | UnaryOp op; 408 | std::shared_ptr node; 409 | 410 | UnaryExpr() : AstNode(ND_UnaryExpr) {} 411 | llvm::Value * Accept(Visitor *v) override { 412 | return v->VisitUnaryExpr(this); 413 | } 414 | 415 | static bool classof(const AstNode *node) { 416 | return node->GetKind() == ND_UnaryExpr; 417 | } 418 | }; 419 | 420 | class CastExpr : public AstNode { 421 | public: 422 | std::shared_ptr targetType; 423 | std::shared_ptr node; 424 | 425 | CastExpr() : AstNode(ND_CastExpr) {} 426 | llvm::Value *Accept(Visitor *v) override { 427 | return v->VisitCastExpr(this); 428 | } 429 | 430 | static bool classof(const AstNode * node) { 431 | return node->GetKind() == ND_CastExpr; 432 | } 433 | }; 434 | 435 | class SizeOfExpr : public AstNode { 436 | public: 437 | std::shared_ptr node; 438 | std::shared_ptr type; 439 | 440 | SizeOfExpr() : AstNode(ND_SizeOfExpr) {} 441 | llvm::Value * Accept(Visitor *v) override { 442 | return v->VisitSizeOfExpr(this); 443 | } 444 | 445 | static bool classof(const AstNode *node) { 446 | return node->GetKind() == ND_SizeOfExpr; 447 | } 448 | }; 449 | 450 | class PostIncExpr : public AstNode { 451 | public: 452 | std::shared_ptr left; 453 | PostIncExpr() : AstNode(ND_PostIncExpr) {} 454 | llvm::Value * Accept(Visitor *v) override { 455 | return v->VisitPostIncExpr(this); 456 | } 457 | 458 | static bool classof(const AstNode *node) { 459 | return node->GetKind() == ND_PostIncExpr; 460 | } 461 | }; 462 | 463 | class PostDecExpr : public AstNode { 464 | public: 465 | std::shared_ptr left; 466 | PostDecExpr() : AstNode(ND_PostDecExpr) {} 467 | llvm::Value * Accept(Visitor *v) override { 468 | return v->VisitPostDecExpr(this); 469 | } 470 | 471 | static bool classof(const AstNode *node) { 472 | return node->GetKind() == ND_PostDecExpr; 473 | } 474 | }; 475 | 476 | class PostSubscript : public AstNode { 477 | public: 478 | std::shared_ptr left; 479 | std::shared_ptr node; 480 | PostSubscript() : AstNode(ND_PostSubscript) {} 481 | llvm::Value * Accept(Visitor *v) override { 482 | return v->VisitPostSubscript(this); 483 | } 484 | 485 | static bool classof(const AstNode *node) { 486 | return node->GetKind() == ND_PostSubscript; 487 | } 488 | }; 489 | 490 | class PostMemberDotExpr : public AstNode { 491 | public: 492 | std::shared_ptr left; 493 | Member member; 494 | PostMemberDotExpr() : AstNode(ND_PostMemberDotExpr) {} 495 | llvm::Value * Accept(Visitor *v) override { 496 | return v->VisitPostMemberDotExpr(this); 497 | } 498 | 499 | static bool classof(const AstNode *node) { 500 | return node->GetKind() == ND_PostMemberDotExpr; 501 | } 502 | }; 503 | 504 | class PostMemberArrowExpr : public AstNode { 505 | public: 506 | std::shared_ptr left; 507 | Member member; 508 | PostMemberArrowExpr() : AstNode(ND_PostMemberArrowExpr) {} 509 | llvm::Value * Accept(Visitor *v) override { 510 | return v->VisitPostMemberArrowExpr(this); 511 | } 512 | 513 | static bool classof(const AstNode *node) { 514 | return node->GetKind() == ND_PostMemberArrowExpr; 515 | } 516 | }; 517 | 518 | class PostFuncCall : public AstNode { 519 | public: 520 | std::shared_ptr left; 521 | std::vector> args; 522 | PostFuncCall() : AstNode(ND_PostFuncCall) {} 523 | llvm::Value * Accept(Visitor *v) override { 524 | return v->VisitPostFuncCall(this); 525 | } 526 | 527 | static bool classof(const AstNode *node) { 528 | return node->GetKind() == ND_PostFuncCall; 529 | } 530 | }; 531 | 532 | class NumberExpr : public AstNode{ 533 | public: 534 | union { 535 | int64_t v; 536 | double d; 537 | }value; // for number 538 | 539 | NumberExpr():AstNode(ND_NumberExpr){} 540 | llvm::Value * Accept(Visitor *v) override { 541 | return v->VisitNumberExpr(this); 542 | } 543 | static bool classof(const AstNode *node) { 544 | return node->GetKind() == ND_NumberExpr; 545 | } 546 | }; 547 | 548 | class StringExpr : public AstNode { 549 | public: 550 | std::string value; 551 | StringExpr():AstNode(ND_StringExpr){} 552 | llvm::Value * Accept(Visitor *v) override { 553 | return v->VisitStringExpr(this); 554 | } 555 | static bool classof(const AstNode *node) { 556 | return node->GetKind() == ND_StringExpr; 557 | } 558 | }; 559 | 560 | class VariableAccessExpr : public AstNode { 561 | public: 562 | VariableAccessExpr():AstNode(ND_VariableAccessExpr){} 563 | llvm::Value * Accept(Visitor *v) override { 564 | return v->VisitVariableAccessExpr(this); 565 | } 566 | static bool classof(const AstNode *node) { 567 | return node->GetKind() == ND_VariableAccessExpr; 568 | } 569 | }; 570 | 571 | class Program { 572 | public: 573 | llvm::StringRef fileName; 574 | std::vector> externalDecls; 575 | }; 576 | -------------------------------------------------------------------------------- /codegen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ast.h" 3 | #include "parser.h" 4 | #include "llvm/IR/LLVMContext.h" 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/IR/IRBuilder.h" 7 | #include "llvm/ADT/DenseMap.h" 8 | 9 | class CodeGen : public Visitor, public TypeVisitor { 10 | public: 11 | CodeGen(std::shared_ptr p) { 12 | module = std::make_unique(p->fileName, context); 13 | VisitProgram(p.get()); 14 | } 15 | 16 | std::unique_ptr &GetModule() { 17 | return module; 18 | } 19 | 20 | private: 21 | llvm::Value * VisitProgram(Program *p) override; 22 | llvm::Value * VisitBlockStmt(BlockStmt *p) override; 23 | llvm::Value * VisitDeclStmt(DeclStmt *p) override; 24 | llvm::Value * VisitIfStmt(IfStmt *p) override; 25 | llvm::Value * VisitForStmt(ForStmt *p) override; 26 | llvm::Value * VisitContinueStmt(ContinueStmt *p) override; 27 | llvm::Value * VisitReturnStmt(ReturnStmt *p) override; 28 | llvm::Value * VisitBreakStmt(BreakStmt *p) override; 29 | llvm::Value * VisitSwitchStmt(SwitchStmt *p) override; 30 | llvm::Value * VisitCaseStmt(CaseStmt *p) override; 31 | llvm::Value * VisitDefaultStmt(DefaultStmt *p) override; 32 | llvm::Value * VisitDoWhileStmt(DoWhileStmt *p) override; 33 | llvm::Value * VisitVariableDecl(VariableDecl *decl) override; 34 | llvm::Value * VisitFuncDecl(FuncDecl *decl) override; 35 | llvm::Value * VisitBinaryExpr(BinaryExpr *binaryExpr) override; 36 | llvm::Value * VisitNumberExpr(NumberExpr *factorExpr) override; 37 | llvm::Value * VisitStringExpr(StringExpr *expr) override; 38 | llvm::Value * VisitUnaryExpr(UnaryExpr *expr) override; 39 | llvm::Value * VisitCastExpr(CastExpr *expr) override; 40 | llvm::Value * VisitSizeOfExpr(SizeOfExpr *expr) override; 41 | llvm::Value * VisitPostIncExpr(PostIncExpr *expr) override; 42 | llvm::Value * VisitPostDecExpr(PostDecExpr *expr) override; 43 | llvm::Value * VisitPostSubscript(PostSubscript *expr) override; 44 | llvm::Value * VisitPostMemberDotExpr(PostMemberDotExpr *expr) override; 45 | llvm::Value * VisitPostMemberArrowExpr(PostMemberArrowExpr *expr) override; 46 | llvm::Value * VisitPostFuncCall(PostFuncCall *expr) override; 47 | llvm::Value * VisitThreeExpr(ThreeExpr *expr) override; 48 | llvm::Value * VisitVariableAccessExpr(VariableAccessExpr *factorExpr) override; 49 | 50 | llvm::Type * VisitPrimaryType(CPrimaryType *ty) override; 51 | llvm::Type * VisitPointType(CPointType *ty) override; 52 | llvm::Type * VisitArrayType(CArrayType *ty) override; 53 | llvm::Type * VisitRecordType(CRecordType *ty) override; 54 | llvm::Type * VisitFuncType(CFuncType *ty) override; 55 | private: 56 | void Cast(llvm::Value *&val); 57 | void AssignCast(llvm::Value *&val, llvm::Type *destTy); 58 | void BinaryArithCast(llvm::Value *&left, llvm::Value *&right); 59 | llvm::Value *BoolCast(llvm::Value *val); 60 | private: 61 | void AddLocalVarToMap(llvm::Value *addr, llvm::Type *ty, llvm::StringRef name); 62 | void AddGlobalVarToMap(llvm::Value *addr, llvm::Type *ty, llvm::StringRef name); 63 | std::pair GetVarByName(llvm::StringRef name); 64 | 65 | void PushScope(); 66 | void PopScope(); 67 | void ClearVarScope(); 68 | 69 | private: 70 | llvm::LLVMContext context; 71 | llvm::IRBuilder<> irBuilder{context}; 72 | std::unique_ptr module; 73 | llvm::Function *curFunc{nullptr}; 74 | 75 | llvm::DenseMap breakBBs; 76 | llvm::DenseMap continueBBs; 77 | llvm::SmallVector switchStack; 78 | 79 | llvm::SmallVector>> localVarMap; 80 | llvm::StringMap> globalVarMap; 81 | }; -------------------------------------------------------------------------------- /demo/2048.c: -------------------------------------------------------------------------------- 1 | int printf(const char *fmg, ...); 2 | int scanf(const char *format, ...); 3 | int getchar(); 4 | int putchar(int ch); 5 | 6 | int getint() { 7 | int val; 8 | scanf("%d", &val); 9 | return val; 10 | } 11 | 12 | int getch() { return getchar(); } 13 | 14 | int getarray(int val[]) { 15 | int len; 16 | for (int i = 0; i < len; i++) { 17 | scanf("%d", val[i]); 18 | } 19 | return len; 20 | } 21 | 22 | void putint(int val) { printf("%d", val); } 23 | 24 | void putch(int val) { putchar(val); } 25 | 26 | void putarray(int len, int arr[]) { 27 | printf("%d:", len); 28 | for (int i = 0; i < len; i++) { 29 | printf(" %d", arr[i]); 30 | } 31 | } 32 | 33 | // Constants. 34 | const int UP = 0; 35 | const int DOWN = 1; 36 | const int LEFT = 2; 37 | const int RIGHT = 3; 38 | 39 | const int MAP_LEN = 4; 40 | 41 | const int POW2[20] = {1, 2, 4, 8, 16, 32, 64, 42 | 128, 256, 512, 1024, 2048, 4096, 8192, 43 | 16384, 32768, 65536, 131072, 262144, 524288}; 44 | const int LEN_OF_POW2[20] = {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 45 | 4, 4, 4, 4, 5, 5, 5, 6, 6, 6}; // x * log10(2) 46 | 47 | int STR_INIT[25] = {73, 110, 112, 117, 116, 32, 97, 32, 114, 48 | 97, 110, 100, 111, 109, 32, 110, 117, 109, 49 | 98, 101, 114, 58, 32, 10, 0}; 50 | int STR_HELP[62] = {119, 44, 32, 97, 44, 32, 115, 44, 32, 100, 58, 51 | 32, 109, 111, 118, 101, 10, 104, 58, 32, 112, 114, 52 | 105, 110, 116, 32, 116, 104, 105, 115, 32, 104, 101, 53 | 108, 112, 10, 113, 58, 32, 113, 117, 105, 116, 10, 54 | 112, 58, 32, 112, 114, 105, 110, 116, 32, 116, 104, 55 | 101, 32, 109, 97, 112, 10, 0}; 56 | // "score: " 57 | int STR_SCORE[8] = {115, 99, 111, 114, 101, 58, 32, 0}; 58 | // "step: " 59 | int STR_STEP[7] = {115, 116, 101, 112, 58, 32, 0}; 60 | int STR_GG[12] = {71, 97, 109, 101, 32, 111, 118, 101, 114, 46, 10, 0}; 61 | int STR_INVALID[26] = {73, 110, 118, 97, 108, 105, 100, 32, 105, 62 | 110, 112, 117, 116, 46, 32, 84, 114, 121, 63 | 32, 97, 103, 97, 105, 110, 46, 0}; 64 | const int CHR_SPACE = 32; 65 | const int CHR_ENTER = 10; 66 | 67 | // Map, stores log2(x) if x != 0. 68 | int map[4][4]; 69 | int score; 70 | int step; 71 | int max_num_len; 72 | int alive; 73 | 74 | // Random lib. 75 | int seed; 76 | 77 | int rand() { 78 | seed = (seed * 214013 + 2531011) % 0x40000000; 79 | if (seed < 0) 80 | seed = -seed; 81 | return seed / 65536 % 0x8000; 82 | } 83 | 84 | // 0 to end a string. 85 | void put_string(int str[]) { 86 | int i = 0; 87 | for (;str[i] != 0;) { 88 | putch(str[i]); 89 | i = i + 1; 90 | } 91 | } 92 | 93 | // Clears the map. 94 | void clear_map() { 95 | int x = 0, y; 96 | for (;x < MAP_LEN;) { 97 | y = 0; 98 | for (;y < MAP_LEN;) { 99 | map[x][y] = 0; 100 | y = y + 1; 101 | } 102 | x = x + 1; 103 | } 104 | } 105 | 106 | // Game init. 107 | void init() { 108 | clear_map(); 109 | score = 0; 110 | step = 0; 111 | max_num_len = 1; 112 | alive = 1; 113 | } 114 | 115 | void print_map() { 116 | putch(CHR_ENTER); 117 | put_string(STR_STEP); 118 | putint(step); 119 | putch(CHR_ENTER); 120 | put_string(STR_SCORE); 121 | putint(score); 122 | putch(CHR_ENTER); 123 | int x = 0, y; 124 | for (;x < MAP_LEN;) { 125 | y = 0; 126 | for (;y < MAP_LEN;) { 127 | if (map[x][y] == 0) { 128 | int i = LEN_OF_POW2[map[x][y]] + 1; 129 | for (;i <= max_num_len;) { 130 | putch(95); 131 | i = i + 1; 132 | } 133 | putch(CHR_SPACE); 134 | } else { 135 | putint(POW2[map[x][y]]); 136 | int i = LEN_OF_POW2[map[x][y]]; 137 | for (;i <= max_num_len;) { 138 | putch(CHR_SPACE); 139 | i = i + 1; 140 | } 141 | } 142 | y = y + 1; 143 | } 144 | putch(CHR_ENTER); 145 | x = x + 1; 146 | } 147 | } 148 | 149 | // return bool 150 | // var == dx or var == dy 151 | int move_base(int inc, int var[], int other[], int x[], int y[], 152 | int is_dry_run) { 153 | int start, end; 154 | int moved = 0; 155 | if (inc == -1) { 156 | start = MAP_LEN - 1; 157 | end = -1; 158 | } else { 159 | start = 0; 160 | end = MAP_LEN; 161 | } 162 | other[0] = start; 163 | for(;other[0] != end;) { 164 | int ptr_from = start + inc, ptr_to = start; 165 | for(;ptr_from != end;) { 166 | if (ptr_from == ptr_to) { 167 | ptr_from = ptr_from + inc; 168 | continue; 169 | } 170 | var[0] = ptr_from; 171 | int from_num = map[x[0]][y[0]]; 172 | var[0] = ptr_to; 173 | int to_num = map[x[0]][y[0]]; 174 | if (to_num == 0) { 175 | if (from_num == 0) { 176 | ptr_from = ptr_from + inc; 177 | } else { 178 | if (is_dry_run) { 179 | return 1; 180 | } 181 | map[x[0]][y[0]] = from_num; 182 | var[0] = ptr_from; 183 | map[x[0]][y[0]] = 0; 184 | moved = 1; 185 | ptr_from = ptr_from + inc; 186 | } 187 | } else { 188 | if (from_num == to_num) { 189 | if (is_dry_run) { 190 | return 1; 191 | } 192 | // Merges two numbers. 193 | var[0] = ptr_to; 194 | map[x[0]][y[0]] = to_num + 1; 195 | var[0] = ptr_from; 196 | map[x[0]][y[0]] = 0; 197 | int new_num_len = LEN_OF_POW2[to_num + 1]; 198 | if (new_num_len > max_num_len) { 199 | max_num_len = new_num_len; 200 | } 201 | score = score + POW2[to_num + 1]; 202 | moved = 1; 203 | ptr_to = ptr_to + inc; 204 | } else if (from_num == 0) { 205 | ptr_from = ptr_from + inc; 206 | } else { 207 | ptr_to = ptr_to + inc; 208 | } 209 | } 210 | } 211 | other[0] = other[0] + inc; 212 | } 213 | return moved; 214 | } 215 | 216 | void generate() { 217 | int x = 0, y, chosen_x, chosen_y, empty = 0; 218 | for(;x < MAP_LEN;) { 219 | y = 0; 220 | for(;y < MAP_LEN;) { 221 | if (map[x][y] == 0) { 222 | empty = empty + 1; 223 | if (rand() % empty == 0) { 224 | chosen_x = x; 225 | chosen_y = y; 226 | } 227 | } 228 | y = y + 1; 229 | } 230 | x = x + 1; 231 | } 232 | int num; 233 | if (rand() % 2 < 1) { 234 | num = 1; 235 | } else { 236 | num = 2; 237 | } 238 | map[chosen_x][chosen_y] = num; 239 | } 240 | 241 | void move(int pos) { 242 | int x[1], y[1], inc = 1 - pos % 2 * 2; 243 | int moved; 244 | if (pos / 2 == 0) { 245 | moved = move_base(inc, x, y, x, y, 0); 246 | } else { 247 | moved = move_base(inc, y, x, x, y, 0); 248 | } 249 | if (!moved) { 250 | put_string(STR_INVALID); 251 | putch(CHR_ENTER); 252 | return; 253 | } 254 | step = step + 1; 255 | generate(); 256 | print_map(); 257 | } 258 | 259 | int try_move() { 260 | int x[1], y[1]; 261 | return move_base(1, x, y, x, y, 1) || move_base(1, y, x, x, y, 1) || 262 | move_base(-1, x, y, x, y, 1) || move_base(-1, y, x, x, y, 1); 263 | } 264 | 265 | int main() { 266 | put_string(STR_INIT); 267 | seed = getint(); 268 | init(); 269 | generate(); 270 | print_map(); 271 | for(;alive;) { 272 | int ch = getch(); 273 | if (ch == 119) { 274 | move(UP); 275 | } else if (ch == 97) { 276 | move(LEFT); 277 | } else if (ch == 115) { 278 | move(DOWN); 279 | } else if (ch == 100) { 280 | move(RIGHT); 281 | } else if (ch == 104) { 282 | // help 283 | put_string(STR_HELP); 284 | } else if (ch == 113 || ch == -1) { 285 | // quit 286 | put_string(STR_GG); 287 | return 0; 288 | } else if (ch == 112) { 289 | // print the map 290 | putch(CHR_ENTER); 291 | print_map(); 292 | } else if (ch == 32 || ch == 10 || ch == 13) { 293 | // ' ' or '\n' or '\r' 294 | continue; 295 | } else { 296 | put_string(STR_INVALID); 297 | putch(CHR_ENTER); 298 | seed = (seed + ch) % 0x40000000; 299 | } 300 | 301 | if (!try_move()) { 302 | put_string(STR_GG); 303 | break; 304 | } 305 | } 306 | return 0; 307 | } -------------------------------------------------------------------------------- /demo/array.c: -------------------------------------------------------------------------------- 1 | int main(){int a[3] = {1,101}; return a[1];} -------------------------------------------------------------------------------- /demo/binary_err.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a[4] = {0}; 3 | int *p = a + 3; 4 | return 0; 5 | } -------------------------------------------------------------------------------- /demo/cast.c: -------------------------------------------------------------------------------- 1 | int printf(const char *fmg, ...); 2 | 3 | int main() 4 | { 5 | int i = 17; 6 | char c = 'c'; /* ascii 值是 99 */ 7 | int sum; 8 | 9 | sum = i + c; 10 | printf("Value of sum : %d\n", sum); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /demo/cast2.c: -------------------------------------------------------------------------------- 1 | int printf(const char *fmg, ...); 2 | 3 | int main() 4 | { 5 | int sum = 17, count = 5; 6 | double mean; 7 | 8 | mean = (double) sum / count; 9 | printf("Value of mean : %f\n", mean ); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /demo/e1.c: -------------------------------------------------------------------------------- 1 | int main(){ 2 | int aa = 1, b = 1; 3 | aa = aa || b && aa || b || aa || b && aa ; 4 | aa = aa << 3; 5 | return aa+b; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /demo/e10.c: -------------------------------------------------------------------------------- 1 | int sort_arr[5]; 2 | int combine(int arr1[], int arr1_length, int arr2[], int arr2_length) { 3 | int i = 0; 4 | int j = 0; 5 | int k = 0; 6 | for (;i < arr1_length && j < arr2_length;) { 7 | if (arr1[i] < arr2[j]) { 8 | sort_arr[k] = arr1[i]; 9 | i = i + 1; 10 | } 11 | else { 12 | sort_arr[k] = arr2[j]; 13 | j = j + 1; 14 | } 15 | k = k + 1; 16 | } 17 | if (i == arr1_length) { 18 | for (;j < arr2_length;) { 19 | sort_arr[k] = arr2[j]; 20 | k = k + 1; 21 | j = j + 1; 22 | } 23 | } 24 | else { 25 | for (;i < arr1_length;) { 26 | sort_arr[k] = arr2[i]; 27 | k = k + 1; 28 | i = i + 1; 29 | } 30 | } 31 | return sort_arr[arr1_length + arr2_length - 1]; 32 | } 33 | 34 | int main() { 35 | int a[] = { 1,5 }; 36 | int b[] = { 1,4,14 }; 37 | return combine(a, 2, b, 3); 38 | } 39 | -------------------------------------------------------------------------------- /demo/e11.c: -------------------------------------------------------------------------------- 1 | int a[] = {1,2,3,4,5}; 2 | 3 | int main() { 4 | return sizeof(a); 5 | } -------------------------------------------------------------------------------- /demo/e12.c: -------------------------------------------------------------------------------- 1 | void swap(int *p, int *q) { 2 | int t = *p; 3 | *p = *q; 4 | *q = t; 5 | } 6 | 7 | int main() { 8 | 9 | int a = 3, b = 6; 10 | swap(&a, &b); 11 | 12 | return a; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /demo/e13.c: -------------------------------------------------------------------------------- 1 | int sum(int array[ ][4],int m,int n);//该函数完成对array数组中的前m行和n列元素求和 2 | 3 | int main() 4 | { 5 | //定义二维数组的同时进行初始化 6 | int a[4][4]= {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; 7 | int row = 3, col = 2; 8 | //输出二维数组前row行前col列的元素的和 9 | return sum(a, row, col); 10 | } 11 | 12 | int sum(int array[][4], int m, int n) { 13 | int s = 0; 14 | int i, j; 15 | for (i = 0; i < m; ++i) { 16 | for (j = 0; j < n; ++j) { 17 | s += array[i][j]; 18 | } 19 | } 20 | return s; 21 | } -------------------------------------------------------------------------------- /demo/e14.c: -------------------------------------------------------------------------------- 1 | struct A { 2 | int a; 3 | struct A *p; 4 | }; 5 | 6 | int main() { 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /demo/e15.c: -------------------------------------------------------------------------------- 1 | int printf(const char *fmg, ...); 2 | 3 | const char *hello = "hello,world\n"; 4 | 5 | int main() { 6 | printf("%s\n", hello); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /demo/e16.c: -------------------------------------------------------------------------------- 1 | int printf(const char *fmg, ...); 2 | 3 | int main () 4 | { 5 | /* 局部变量定义 */ 6 | char grade = 'E'; 7 | int ret = grade; 8 | switch(grade) 9 | { 10 | case 'A' : { 11 | printf("很棒!\n" ); 12 | break; 13 | } 14 | case 'B' : 15 | // printf("ddd\n"); 16 | // break; 17 | case 'C' : 18 | ret += 1; 19 | printf("做得好\n" ); 20 | // break; 21 | case 'D' : { 22 | printf("您通过了\n" ); 23 | break; 24 | } 25 | case 'F' : { 26 | printf("最好再试一下\n" ); 27 | break; 28 | } 29 | // default : { 30 | // printf("无效的成绩\n" ); 31 | // break; 32 | // } 33 | // default : { 34 | // printf("无效的成绩\n" ); 35 | // break; 36 | // } 37 | } 38 | printf("您的成绩是 %c\n", grade ); 39 | 40 | return ret; 41 | } 42 | -------------------------------------------------------------------------------- /demo/e17.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iiicp/subc-llvm/905b51f18bfb0f9da0ad3c174a73003a30dadb1c/demo/e17.c -------------------------------------------------------------------------------- /demo/e18.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 10; 3 | while (a < 100) { 4 | break; 5 | if ( a == 35 ) 6 | break; 7 | a += 3; 8 | } 9 | 10 | return 0; 11 | } -------------------------------------------------------------------------------- /demo/e19.c: -------------------------------------------------------------------------------- 1 | int main(){int a=0,b=3;a=2;return a;} -------------------------------------------------------------------------------- /demo/e2.c: -------------------------------------------------------------------------------- 1 | //int printf(const char *fmg, ...); 2 | 3 | struct { 4 | int a, b; 5 | struct {int d; int a;} c; 6 | } a = {1,2,{4,5}}; 7 | 8 | int sum(int n) { 9 | int ret = 0; 10 | for (int i = 0; i <= n; ++i) { 11 | ret += i; 12 | } 13 | return ret; 14 | } 15 | 16 | int main() { 17 | return a.c.d + sum(100); 18 | } 19 | //{struct {int *p; int a,b; union{int a;int b;} c;} a; a.c.b = 1024; a.c.a = 22; a.p = &a.c.b; a.c.b += 111; *a.p;} 20 | //{struct {int *p; int a,b; union{int a;int b;} c;} a; a.c.b = 1024; a.c.a = 22; a.p = &a.c.b; a.c.b += 111; *a.p;} 21 | //{struct {int *p; int a,b; struct{int a;int b;} c;} a; a.c.b = 1024; a.c.b;} -------------------------------------------------------------------------------- /demo/e20.c: -------------------------------------------------------------------------------- 1 | int printf(const char *fmg, ...); 2 | 3 | typedef struct student 4 | { 5 | char name[20]; 6 | int age; 7 | float score; 8 | }student_t, *student_ptr; 9 | 10 | int main (void) 11 | { 12 | student_t stu = {"wit", 20, 99}; 13 | student_t *p1 = &stu; 14 | student_ptr p2 = &stu; 15 | printf ("name: %s\n", p1->name); 16 | printf ("name: %s\n", p2->name); 17 | return 0; 18 | } -------------------------------------------------------------------------------- /demo/e21.c: -------------------------------------------------------------------------------- 1 | int printf(const char *fmg, ...); 2 | 3 | typedef int array_t[10]; 4 | array_t array; 5 | int main (void) 6 | { 7 | array[9] = 100; 8 | printf ("array[9] = %d\n", array[9]); 9 | return 0; 10 | } -------------------------------------------------------------------------------- /demo/e22.c: -------------------------------------------------------------------------------- 1 | int printf(const char *fmg, ...); 2 | typedef char * PCHAR; 3 | int main (void) 4 | { 5 | //char * str = "学嵌入式,到宅学部落"; 6 | PCHAR str = "学嵌入式,到宅学部落"; 7 | printf ("str: %s\n", str); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /demo/e23.c: -------------------------------------------------------------------------------- 1 | 2 | typedef float (*func_t)(double a, int b); 3 | 4 | int printf(const char *fmg, ...); 5 | 6 | float sum (double a, int b) 7 | { 8 | return a + b; 9 | } 10 | int main (void) 11 | { 12 | func_t fp = sum; 13 | printf ("%f\n", fp(1,2)); 14 | return 0; 15 | } -------------------------------------------------------------------------------- /demo/e3.c: -------------------------------------------------------------------------------- 1 | int a = 10; 2 | int main() { 3 | if (a != 10) { 4 | a = 2; 5 | } 6 | else { 7 | a = 20; 8 | } 9 | return a; 10 | } -------------------------------------------------------------------------------- /demo/e4.c: -------------------------------------------------------------------------------- 1 | int main(){ 2 | int a=0; 3 | int count=0; 4 | for(; a<=0; ){ 5 | a=a-1; 6 | count=count+1; 7 | if(a<-20) 8 | break; 9 | } 10 | return count; 11 | } -------------------------------------------------------------------------------- /demo/e5.c: -------------------------------------------------------------------------------- 1 | // #include 2 | int x = 1; 3 | int y = 2; 4 | int z = 3; 5 | int a = 4; 6 | int b = 5; 7 | int c = 6; 8 | int d = 7; 9 | int e = 8; 10 | int f = 9; 11 | int g = 10; 12 | int h = 11; 13 | int i = 12; 14 | int j = 13; 15 | int k = 14; 16 | int l = 15; 17 | int m = 16; 18 | int n = 17; 19 | int o = 18; 20 | int p = 19; 21 | int q = 20; 22 | 23 | int main() { 24 | // Local variables 25 | int x1 = 1; 26 | int x2 = 2; 27 | int x3 = 3; 28 | int x4 = 4; 29 | int x5 = 5; 30 | int x6 = 6; 31 | int x7 = 7; 32 | int x8 = 8; 33 | int x9 = 9; 34 | int x10 = 10; 35 | int x11 = 11; 36 | int x12 = 12; 37 | int x13 = 13; 38 | int x14 = 14; 39 | int x15 = 15; 40 | int x16 = 16; 41 | int x17 = 17; 42 | int x18 = 18; 43 | int x19 = 19; 44 | int x20 = 20; 45 | 46 | // Perform some operations on global variables 47 | x = x + 1; 48 | y = y + 2; 49 | z = z + 3; 50 | a = a + 4; 51 | b = b + 5; 52 | c = c + 6; 53 | d = d + 7; 54 | e = e + 8; 55 | f = f + 9; 56 | g = g + 10; 57 | h = h + 11; 58 | i = i + 12; 59 | j = j + 13; 60 | k = k + 14; 61 | l = l + 15; 62 | m = m + 16; 63 | n = n + 17; 64 | o = o + 18; 65 | p = p + 19; 66 | q = q + 20; 67 | 68 | // Perform some operations on local variables 69 | x1 = x1 * 2; 70 | x2 = x2 * 2; 71 | x3 = x3 * 2; 72 | x4 = x4 * 2; 73 | x5 = x5 * 2; 74 | x6 = x6 * 2; 75 | x7 = x7 * 2; 76 | x8 = x8 * 2; 77 | x9 = x9 * 2; 78 | x10 = x10 * 2; 79 | x11 = x11 * 2; 80 | x12 = x12 * 2; 81 | x13 = x13 * 2; 82 | x14 = x14 * 2; 83 | x15 = x15 * 2; 84 | x16 = x16 * 2; 85 | x17 = x17 * 2; 86 | x18 = x18 * 2; 87 | x19 = x19 * 2; 88 | x20 = x20 * 2; 89 | 90 | int ret = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 91 | + x + y + z + a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q; 92 | // printf("ret = %d\n", ret); 93 | return ret; 94 | } -------------------------------------------------------------------------------- /demo/e6.c: -------------------------------------------------------------------------------- 1 | 2 | struct TreeNode 3 | { 4 | int id; 5 | int height; 6 | struct TreeNode* right; 7 | struct TreeNode* left; 8 | }; 9 | 10 | struct TreeNode* rotateLeft(struct TreeNode* pivot, struct TreeNode* parent); 11 | 12 | struct TreeNode* rotateRight(struct TreeNode* pivot, struct TreeNode* parent); 13 | 14 | int getBalance(struct TreeNode* h); 15 | 16 | int height(struct TreeNode* h); 17 | 18 | void recursiveAdd(struct TreeNode* h, struct TreeNode* p, struct TreeNode* parent, struct TreeNode** root); 19 | 20 | void addNode(struct TreeNode* root, struct TreeNode* p); 21 | 22 | void Rotate(struct TreeNode* h, struct TreeNode** parent, struct TreeNode** root); 23 | 24 | void updateHeight(struct TreeNode* h); 25 | 26 | 27 | int abs(int number) 28 | { 29 | return number < 0 ? -number : number; 30 | } 31 | 32 | struct TreeNode* rotateLeft(struct TreeNode* pivot, struct TreeNode* parent) 33 | { 34 | struct TreeNode* h = pivot->right; 35 | pivot->right = h->left; 36 | h->left = pivot; 37 | updateHeight(pivot); 38 | updateHeight(h); 39 | if (parent) 40 | { 41 | if (parent->left == pivot) 42 | { 43 | parent->left = h; 44 | } 45 | else 46 | { 47 | parent->right = h; 48 | } 49 | updateHeight(parent); 50 | } 51 | 52 | return h; 53 | } 54 | 55 | struct TreeNode* rotateRight(struct TreeNode* pivot, struct TreeNode* parent) 56 | { 57 | struct TreeNode* h = pivot->left; 58 | pivot->left = h->right; 59 | h->right = pivot; 60 | updateHeight(pivot); 61 | updateHeight(h); 62 | if (parent) 63 | { 64 | if (parent->left == pivot) 65 | { 66 | parent->left = h; 67 | } 68 | else 69 | { 70 | parent->right = h; 71 | } 72 | updateHeight(parent); 73 | } 74 | 75 | return h; 76 | } 77 | 78 | void updateHeight(struct TreeNode* h) 79 | { 80 | if (height(h->right) > height(h->left)) 81 | { 82 | h->height = height(h->right); 83 | } 84 | else 85 | { 86 | h->height = height(h->left); 87 | } 88 | } 89 | 90 | void Rotate(struct TreeNode* h, struct TreeNode** parent, struct TreeNode** root) 91 | { 92 | //Neue Höhe bekommen 93 | updateHeight(h); 94 | //balanz checken 95 | int balance = getBalance(h); 96 | if (abs(balance) == 2) 97 | { 98 | //korrigiern 99 | if (balance > 0) 100 | { 101 | if (getBalance(h->left) < 0) 102 | { 103 | rotateLeft(h->left, h); 104 | } 105 | struct TreeNode* newparent = rotateRight(h, *parent); 106 | if (h == *root) 107 | { 108 | *root = newparent; 109 | } 110 | } 111 | else 112 | { 113 | if (getBalance(h->right) > 0) 114 | { 115 | rotateRight(h->right, h); 116 | } 117 | struct TreeNode* newparent = rotateLeft(h, *parent); 118 | if (h == *root) 119 | { 120 | *root = newparent; 121 | } 122 | } 123 | } 124 | } 125 | 126 | int getBalance(struct TreeNode* h) 127 | { 128 | //Balance = höhe des linkensubtree minus höhe des rechten subtree 129 | //0 ist voll balanziert, 1 ist linkslehnend, -1 ist rechtslehnen, -2 und 2 sind unbalanziert 130 | return height(h->left) - height(h->right); 131 | } 132 | 133 | int height(struct TreeNode* h) 134 | { 135 | //height = Maximale Anzahl der Kanten von der Note zur untersten Ebene (Kanten...Verbindung zwischen zwei Noten) 136 | return (h ? h->height + 1 : 0); 137 | } 138 | 139 | void recursiveAdd(struct TreeNode* h, struct TreeNode* p, struct TreeNode* parent, struct TreeNode** root) 140 | { 141 | //suchen nach Platz für neue Note, durch rekursiver Aufruf wird kein Elternpointer gebraucht 142 | if (p->id >= h->id) 143 | { 144 | if (h->right) 145 | { 146 | recursiveAdd(h->right, p, h, root); 147 | } 148 | else 149 | { 150 | h->right = p; 151 | } 152 | } 153 | else 154 | { 155 | if (h->left) 156 | { 157 | recursiveAdd(h->left, p, h, root); 158 | } 159 | else 160 | { 161 | h->left = p; 162 | } 163 | } 164 | //Balancieren 165 | Rotate(h, &parent, root); 166 | } 167 | 168 | void addNode(struct TreeNode* root, struct TreeNode* p) 169 | { 170 | recursiveAdd(root, p, 0, &root); 171 | } 172 | 173 | int main() 174 | { 175 | struct TreeNode root = {1001, 0, 0, 0}; 176 | struct TreeNode newNode1 = {1002, 0, 0, 0}; 177 | struct TreeNode newNode2 = {1003, 0, 0, 0}; 178 | struct TreeNode newNode3 = {888, 0, 0, 0}; 179 | struct TreeNode newNode4 = {10010, 0, 0, 0}; 180 | struct TreeNode newNode5 = {1006, 0, 0, 0}; 181 | struct TreeNode newNode6 = {1006, 0, 0, 0}; 182 | struct TreeNode newNode7 = {1006, 0, 0, 0}; 183 | struct TreeNode newNode8 = {1006, 0, 0, 0}; 184 | struct TreeNode newNode9 = {1006, 0, 0, 0}; 185 | struct TreeNode newNode10 = {1006, 0, 0, 0}; 186 | addNode(&root, &newNode1); 187 | addNode(&root, &newNode2); 188 | addNode(&root, &newNode3); 189 | addNode(&root, &newNode4); 190 | addNode(&root, &newNode5); 191 | addNode(&root, &newNode6); 192 | addNode(&root, &newNode7); 193 | addNode(&root, &newNode8); 194 | addNode(&root, &newNode9); 195 | addNode(&root, &newNode10); 196 | return newNode4.height; 197 | } 198 | -------------------------------------------------------------------------------- /demo/e7.c: -------------------------------------------------------------------------------- 1 | struct Point 2 | { 3 | struct Point* next; 4 | }; 5 | 6 | int getListCount(struct Point* first) 7 | { 8 | struct Point* current = first; 9 | int i = 0; 10 | for(;current;) 11 | { 12 | current = current->next; 13 | i++; 14 | } 15 | return i; 16 | } 17 | 18 | int main() 19 | { 20 | struct Point first = {0}; 21 | struct Point second = {0}; 22 | struct Point third = {0}; 23 | first.next = &second; 24 | second.next = &third; 25 | third.next = 0; 26 | return getListCount(&first); 27 | } 28 | -------------------------------------------------------------------------------- /demo/e8.c: -------------------------------------------------------------------------------- 1 | struct A { 2 | // int a; 3 | struct A *a; 4 | } a = {0}; 5 | 6 | int main() { 7 | return 0; 8 | } -------------------------------------------------------------------------------- /demo/e9.c: -------------------------------------------------------------------------------- 1 | struct A { 2 | int a; 3 | int b; 4 | struct A *c; 5 | }; 6 | 7 | 8 | struct A getNewStruct(struct A a) { 9 | struct A newA; 10 | newA.a = a.a + 102; // 103 11 | newA.b = a.b + 1024; // 1026 12 | newA.c = 0; 13 | return newA; 14 | } 15 | 16 | int main() { 17 | struct A a = {1,2,0}; 18 | struct A newA = getNewStruct(a); 19 | return newA.a + newA.b; 20 | } -------------------------------------------------------------------------------- /demo/eval1.c: -------------------------------------------------------------------------------- 1 | /// a -> number 2 | /// b -> number 3 | 4 | int b = 20; 5 | int main() { 6 | // int a[(int)4.5*(3&4)-5+6+100] = {0}; 7 | int a[12^9] = {0}; 8 | a[2] = 3*4; 9 | return a[2]; 10 | } -------------------------------------------------------------------------------- /demo/eval2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 10; 3 | int b = 1; 4 | switch (a) 5 | { 6 | case sizeof(2*5): 7 | return a + b; 8 | case b: 9 | return a * b; 10 | default: 11 | break; 12 | } 13 | return a; 14 | } -------------------------------------------------------------------------------- /demo/expr.txt: -------------------------------------------------------------------------------- 1 | int main(){int a=0,b=3;a=2;return a;} -------------------------------------------------------------------------------- /demo/lisp.bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iiicp/subc-llvm/905b51f18bfb0f9da0ad3c174a73003a30dadb1c/demo/lisp.bc -------------------------------------------------------------------------------- /demo/lisp.lisp: -------------------------------------------------------------------------------- 1 | 'by-MaxXing 2 | 'Reference:-Roots-of-Lisp 3 | 4 | (define caar (lambda (x) (car (car x)))) 5 | (define cadr (lambda (x) (car (cdr x)))) 6 | (define cadar (lambda (x) (car (cdr (car x))))) 7 | (define caddr (lambda (x) (car (cdr (cdr x))))) 8 | (define caddar (lambda (x) (car (cdr (cdr (car x)))))) 9 | 10 | (define null? (lambda (x) 11 | (eq? x '()))) 12 | 13 | (define and (lambda (x y) 14 | (cond (x (cond (y 't) ('t 'f))) 15 | ('t 'f)))) 16 | 17 | (define not (lambda (x) 18 | (cond (x 'f) ('t 't)))) 19 | 20 | (define append (lambda (x y) 21 | (cond ((null? x) y) 22 | ('t (cons (car x) (append (cdr x) y)))))) 23 | 24 | (define pair (lambda (x y) 25 | (cond ((and (null? x) (null? y)) '()) 26 | ((and (not (atom? x)) (not (atom? y))) 27 | (cons (list (car x) (car y)) 28 | (pair (cdr x) (cdr y))))))) 29 | 30 | (define assoc (lambda (x y) 31 | (cond ((eq? (caar y) x) (cadar y)) 32 | ('t (assoc x (cdr y)))))) 33 | 34 | (define eval (lambda (e a) 35 | (cond 36 | ((number? e) e) 37 | ((atom? e) (assoc e a)) 38 | ((atom? (car e)) 39 | (cond 40 | ((eq? (car e) 'quote) (cadr e)) 41 | ((eq? (car e) 'atom?) (atom? (eval (cadr e) a))) 42 | ((eq? (car e) 'number?) (number? (eval (cadr e) a))) 43 | ((eq? (car e) 'eq?) (eq? (eval (cadr e) a) (eval (caddr e) a))) 44 | ((eq? (car e) 'car) (car (eval (cadr e) a))) 45 | ((eq? (car e) 'cdr) (cdr (eval (cadr e) a))) 46 | ((eq? (car e) 'cons) (cons (eval (cadr e) a) (eval (caddr e) a))) 47 | ((eq? (car e) 'cond) (evcon (cdr e) a)) 48 | ((eq? (car e) 'list) (evlis (cdr e) a)) 49 | ((eq? (car e) '+) (+ (eval (cadr e) a) (eval (caddr e) a))) 50 | ((eq? (car e) '-) (- (eval (cadr e) a) (eval (caddr e) a))) 51 | ((eq? (car e) '*) (* (eval (cadr e) a) (eval (caddr e) a))) 52 | ((eq? (car e) '/) (/ (eval (cadr e) a) (eval (caddr e) a))) 53 | ((eq? (car e) '>) (> (eval (cadr e) a) (eval (caddr e) a))) 54 | ((eq? (car e) '<) (< (eval (cadr e) a) (eval (caddr e) a))) 55 | ((eq? (car e) '>=) (>= (eval (cadr e) a) (eval (caddr e) a))) 56 | ((eq? (car e) '<=) (<= (eval (cadr e) a) (eval (caddr e) a))) 57 | ((eq? (car e) '=) (= (eval (cadr e) a) (eval (caddr e) a))) 58 | ('t (eval (cons (assoc (car e) a) (cdr e)) a)))) 59 | ((eq? (caar e) 'define) (eval (cadr e) 60 | (cons (list (cadar e) (caddar e)) a))) 61 | ((eq? (caar e) 'lambda) (eval (caddar e) 62 | (append (pair (cadar e) (evlis (cdr e) a)) 63 | a)))))) 64 | 65 | (define evcon (lambda (c a) 66 | (cond ((eval (caar c) a) (eval (cadar c) a)) 67 | ('t (evcon (cdr c) a))))) 68 | 69 | (define evlis (lambda (m a) 70 | (cond ((null? m) '()) 71 | ('t (cons (eval (car m) a) 72 | (evlis (cdr m) a)))))) 73 | 74 | (eval '((define map 75 | (lambda (f l) 76 | (cond ((eq? l '()) '()) 77 | ('t (cons (f (car l)) (map f (cdr l))))))) 78 | ((define fib 79 | (lambda (n) 80 | (cond ((< n 2) 1) 81 | ('t (+ (fib (- n 1)) (fib (- n 2))))))) 82 | (map fib '(0 1 2 3 4 5 6 7 8 9)))) 83 | '()) -------------------------------------------------------------------------------- /demo/lisp2.lisp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iiicp/subc-llvm/905b51f18bfb0f9da0ad3c174a73003a30dadb1c/demo/lisp2.lisp -------------------------------------------------------------------------------- /demo/lispc.bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iiicp/subc-llvm/905b51f18bfb0f9da0ad3c174a73003a30dadb1c/demo/lispc.bc -------------------------------------------------------------------------------- /demo/maze.c: -------------------------------------------------------------------------------- 1 | // A maze generator. 2 | // Author: MaxXing. 3 | 4 | // Maze configurations. 5 | const int WIDTH = 100, HEIGHT = 100; 6 | 7 | // Properties of a cell. 8 | const int VISITED = 0; 9 | const int NO_LEFT_WALL = 1; 10 | const int NO_TOP_WALL = 2; 11 | 12 | // Directions. 13 | const int LEFT = 0; 14 | const int RIGHT = 1; 15 | const int TOP = 2; 16 | const int DOWN = 3; 17 | 18 | // Map and image. 19 | int map[100][100][3]; 20 | int image[201][201]; 21 | 22 | // Random seed. 23 | int seed; 24 | 25 | // Random number generator. 26 | int rand() { 27 | seed = (seed * 214013 + 2531011) % 0x40000000; 28 | if (seed < 0) seed = -seed; 29 | return seed / 65536 % 0x8000; 30 | } 31 | 32 | int printf(const char *fmg, ...); 33 | int scanf(const char *format, ...); 34 | int getchar(); 35 | int putchar(int ch); 36 | 37 | int getint() { 38 | int val; 39 | scanf("%d", &val); 40 | return val; 41 | } 42 | 43 | int getch() { return getchar(); } 44 | 45 | int getarray(int val[]) { 46 | int len; 47 | for (int i = 0; i < len; i++) { 48 | scanf("%d", val[i]); 49 | } 50 | return len; 51 | } 52 | 53 | void putint(int val) { printf("%c", val); } 54 | 55 | void putch(int val) { putchar(val); } 56 | 57 | void putarray(int len, int arr[]) { 58 | printf("%d:", len); 59 | for (int i = 0; i < len; i++) { 60 | printf(" %d", arr[i]); 61 | } 62 | } 63 | 64 | // Gets neighbors of the given cell by direction. 65 | // Returns zero if the neighbor is out of the map. 66 | int get_neighbor(int x[], int y[], int dir) { 67 | if (dir == LEFT) { 68 | if (x[0] == 0) return 0; 69 | x[0] = x[0] - 1; 70 | } else if (dir == RIGHT) { 71 | if (x[0] == WIDTH - 1) return 0; 72 | x[0] = x[0] + 1; 73 | } else if (dir == TOP) { 74 | if (y[0] == 0) return 0; 75 | y[0] = y[0] - 1; 76 | } else if (dir == DOWN) { 77 | if (y[0] == HEIGHT - 1) return 0; 78 | y[0] = y[0] + 1; 79 | } 80 | return 1; 81 | } 82 | 83 | // Removes the wall at the given direction of the cell. 84 | void remove_wall(int x, int y, int dir) { 85 | if (dir == LEFT) { 86 | map[y][x][NO_LEFT_WALL] = 1; 87 | } else if (dir == RIGHT) { 88 | map[y][x + 1][NO_LEFT_WALL] = 1; 89 | } else if (dir == TOP) { 90 | map[y][x][NO_TOP_WALL] = 1; 91 | } else if (dir == DOWN) { 92 | map[y + 1][x][NO_TOP_WALL] = 1; 93 | } 94 | } 95 | 96 | // Generates a maze (DFS). 97 | void gen_maze(int x, int y) { 98 | map[y][x][VISITED] = 1; 99 | int dirs[4] = {LEFT, RIGHT, TOP, DOWN}, i; 100 | i = 0; 101 | while (i < 4) { 102 | int r = rand() % 4; 103 | int temp = dirs[i]; 104 | dirs[i] = dirs[r]; 105 | dirs[r] = temp; 106 | i = i + 1; 107 | } 108 | i = 0; 109 | while (i < 4) { 110 | int xx[1] = {x}, yy[1] = {y}; 111 | if (get_neighbor(xx, yy, dirs[i]) && !map[yy[0]][xx[0]][VISITED]) { 112 | remove_wall(x, y, dirs[i]); 113 | gen_maze(xx[0], yy[0]); 114 | } 115 | i = i + 1; 116 | } 117 | } 118 | 119 | // Draws the maze. 120 | void render() { 121 | int x, y; 122 | y = 0; 123 | while (y < HEIGHT) { 124 | x = 0; 125 | while (x < WIDTH) { 126 | if (!map[y][x][NO_LEFT_WALL]) image[y * 2 + 1][x * 2] = 1; 127 | if (!map[y][x][NO_TOP_WALL]) image[y * 2][x * 2 + 1] = 1; 128 | image[y * 2][x * 2] = 1; 129 | x = x + 1; 130 | } 131 | y = y + 1; 132 | } 133 | y = 0; 134 | while (y < HEIGHT * 2 + 1) { 135 | image[y][WIDTH * 2] = 1; 136 | y = y + 1; 137 | } 138 | x = 0; 139 | while (x < WIDTH * 2 + 1) { 140 | image[HEIGHT * 2][x] = 1; 141 | x = x + 1; 142 | } 143 | } 144 | 145 | int main() { 146 | seed = getint(); 147 | int zoom = getint(); 148 | // starttime(); 149 | gen_maze(rand() % WIDTH, rand() % HEIGHT); 150 | render(); 151 | // stoptime(); 152 | // starttime(); 153 | putch(80); putch(51); putch(10); 154 | putint((WIDTH * 2 + 1) * zoom); putch(32); 155 | putint((HEIGHT * 2 + 1) * zoom); putch(10); 156 | putint(255); putch(10); 157 | int y = 0; 158 | while (y < (HEIGHT * 2 + 1) * zoom) { 159 | int x = 0; 160 | while (x < (WIDTH * 2 + 1) * zoom) { 161 | int xx = x / zoom, yy = y / zoom; 162 | int r = image[yy][xx] * 255 * x / ((WIDTH * 2 + 1) * zoom); 163 | int g = image[yy][xx] * 255 * y / ((HEIGHT * 2 + 1) * zoom); 164 | int b = image[yy][xx] * 255; 165 | putint(r); putch(32); putint(g); putch(32); putint(b); putch(32); 166 | x = x + 1; 167 | } 168 | putch(10); 169 | y = y + 1; 170 | } 171 | // stoptime(); 172 | return 0; 173 | } -------------------------------------------------------------------------------- /demo/nqueen.c: -------------------------------------------------------------------------------- 1 | // How to run: 2 | // 3 | // $ ./9cc examples/nqueen.c > tmp-nqueen.s 4 | // $ gcc -static -o tmp-nqueen tmp-nqueen.s 5 | // $ ./tmp-nqueen 6 | 7 | int printf(const char *fmg, ...); 8 | 9 | void print_board(int board[][10]) { 10 | for (int i = 0; i < 10; i++) { 11 | for (int j = 0; j < 10; j++) 12 | if (board[i][j]) 13 | printf("Q "); 14 | else 15 | printf(". "); 16 | printf("\n"); 17 | } 18 | printf("\n\n"); 19 | } 20 | 21 | int conflict(int board[][10], int row, int col) { 22 | for (int i = 0; i < row; i++) { 23 | if (board[i][col]) 24 | return 1; 25 | int j = row - i; 26 | if (0 < col - j + 1 && board[i][col - j]) 27 | return 1; 28 | if (col + j < 10 && board[i][col + j]) 29 | return 1; 30 | } 31 | return 0; 32 | } 33 | 34 | void solve(int board[][10], int row) { 35 | if (row > 9) { 36 | print_board(board); 37 | } 38 | for (int i = 0; i < 10; i++) { 39 | if (conflict(board, row, i)) { 40 | } else { 41 | board[row][i] = 1; 42 | solve(board, row + 1); 43 | board[row][i] = 0; 44 | } 45 | } 46 | } 47 | 48 | int main() { 49 | int board[100]; 50 | for (int i = 0; i < 100; i++) 51 | board[i] = 0; 52 | solve(board, 0); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /demo/test_struct_ret.c: -------------------------------------------------------------------------------- 1 | struct A { 2 | int x, y; 3 | }; 4 | struct A f() { 5 | struct A a; 6 | a.x = 1; 7 | return a; 8 | } 9 | int main() { 10 | int ret = f().x; 11 | return ret; 12 | //struct A a = f(); 13 | //return a.x; 14 | } 15 | -------------------------------------------------------------------------------- /demo/typedef.c: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | int a,b; 3 | }Point; 4 | 5 | int main() { 6 | Point p = {1,2}; 7 | return p.a + p.b; 8 | } -------------------------------------------------------------------------------- /diag.inc: -------------------------------------------------------------------------------- 1 | #ifndef DIAG 2 | #define DIAG(ID, KIND, MSG) 3 | #endif 4 | 5 | /// lexer 6 | DIAG(err_unknown_char, Error, "unknown char '{0}'") 7 | DIAG(err_unclosed_character, Error, "unclosed character literal") 8 | DIAG(err_unclosed_string, Error, "unclosed string literal") 9 | DIAG(err_numeric_constant, Error, "invalid numeric constant") 10 | 11 | /// parser 12 | DIAG(err_expected, Error, "expected '{0}', but found '{1}'") 13 | DIAG(err_break_stmt, Error, "'break' statement not in loop or switch statement") 14 | DIAG(err_continue_stmt, Error, "'continue' statement not in loop or switch statement") 15 | DIAG(err_case_stmt, Error, "'case' statement not in switch statement") 16 | DIAG(err_default_stmt, Error, "'default' statement not in switch statement") 17 | DIAG(err_multi_default_stmt, Error, "only one 'default' statement in switch statement") 18 | 19 | /// sema 20 | DIAG(err_redefined, Error, "redefined symbol '{0}") 21 | DIAG(err_undefined, Error, "undefined symbol '{0}") 22 | DIAG(err_lvalue, Error, "required lvalue on the assign operation left side") 23 | DIAG(err_type, Error, "typename expected") 24 | DIAG(err_same_type, Error, "expected same type") 25 | DIAG(err_expected_ype, Error, "expected {0}") 26 | DIAG(err_expected_lvalue, Error, "expected lvalue") 27 | DIAG(err_expected_ex, Error, "expected '{0}'") 28 | DIAG(err_miss, Error, "miss '{0}'") 29 | DIAG(err_large_length, Error, "large length") 30 | DIAG(err_binary_expr_type, Error, "The types of the left and right sides of the binary expression do not support the operation") 31 | 32 | DIAG(err_constant_expr, Error, "expect constant expr") 33 | DIAG(err_int_constant_expr, Error, "expect int constant expr") 34 | DIAG(err_arr_size, Error, "array size must be greater than 0") 35 | 36 | #undef DIAG -------------------------------------------------------------------------------- /diag_engine.cc: -------------------------------------------------------------------------------- 1 | #include "diag_engine.h" 2 | using namespace llvm; 3 | static const char *diag_msg[] = { 4 | #define DIAG(ID, KIND, MSG) MSG, 5 | #include "diag.inc" 6 | }; 7 | 8 | static llvm::SourceMgr::DiagKind diag_kind[] = { 9 | #define DIAG(ID, KIND, MSG) SourceMgr::DK_##KIND, 10 | #include "diag.inc" 11 | }; 12 | 13 | llvm::SourceMgr::DiagKind DiagEngine::GetDiagKind(unsigned id) { 14 | return diag_kind[id]; 15 | } 16 | 17 | const char *DiagEngine::GetDiagMsg(unsigned id) { 18 | return diag_msg[id]; 19 | } -------------------------------------------------------------------------------- /diag_engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "llvm/Support/SourceMgr.h" 3 | #include "llvm/Support/FormatVariadic.h" 4 | 5 | namespace diag{ 6 | enum { 7 | #define DIAG(ID, KIND, MSG) ID, 8 | #include "diag.inc" 9 | }; 10 | } 11 | 12 | class DiagEngine { 13 | private: 14 | llvm::SourceMgr &mgr; 15 | private: 16 | llvm::SourceMgr::DiagKind GetDiagKind(unsigned id); 17 | const char *GetDiagMsg(unsigned id); 18 | public: 19 | DiagEngine(llvm::SourceMgr &mgr) : mgr(mgr) {} 20 | 21 | template 22 | void Report(llvm::SMLoc loc, unsigned diagId, Args... args) { 23 | auto kind = GetDiagKind(diagId); 24 | const char *fmt = GetDiagMsg(diagId); 25 | auto f = llvm::formatv(fmt, std::forward(args)...).str(); 26 | mgr.PrintMessage(loc, kind, f); 27 | 28 | if (kind == llvm::SourceMgr::DK_Error) { 29 | exit(0); 30 | } 31 | } 32 | }; -------------------------------------------------------------------------------- /doc/ebnf.txt: -------------------------------------------------------------------------------- 1 | prog ::= external-decl+ 2 | external-decl ::= func-def | decl-stmt 3 | func-def ::= decl-spec declarator block-stmt 4 | block-stmt ::= stmt* 5 | stmt ::= decl-stmt | expr-stmt | null-stmt | if-stmt | block-stmt | for-stmt | 6 | break-stmt | continue-stmt | while-stmt | do-while-stm | switch-stmt | 7 | case-stmt | default-stmt 8 | decl-stmt ::= decl-spec init-declarator-list? ";" 9 | init-declarator-list ::= declarator (= initializer)? ("," declarator (= initializer)?)* 10 | decl-spec ::= "int" | struct-or-union-specifier 11 | struct-or-union-specifier ::= struct-or-union identifier "{" (decl-spec declarator(, declarator)* ";")* "}" 12 | struct-or-union identifier 13 | struct-or-union := "struct" | "union" 14 | 15 | declarator ::= "*"* direct-declarator 16 | direct-declarator ::= identifier | direct-declarator "[" assign "]" 17 | | direct-declarator "(" parameter-type-list? ")" 18 | parameter-type-list ::= decl-spec declarator (, decl-spec declarator)* (", " "...")? 19 | 20 | initializer ::= assign | "{" initializer ("," initializer)* "}" 21 | 22 | null-stmt ::= ";" 23 | if-stmt ::= "if" "(" expr ")" stmt ( "else" stmt )? 24 | for-stmt ::= "for" "(" expr? ";" expr? ";" expr? ")" stmt 25 | "for" "(" decl-stmt expr? ";" expr? ")" stmt 26 | while-stmt ::= "while" "(" expr ")" stmt 27 | do-while-stmt ::= "do" stmt "while" "(" expr ")" ";" 28 | switch-stmt ::= "switch" "(" expr ")" stmt 29 | case-stmt ::= "case" expr ":" stmt 30 | default-stmt ::= "default" ":" stmt 31 | block-stmt ::= "{" stmt* "}" 32 | break-stmt ::= "break" ";" 33 | continue-stmt ::= "continue" ";" 34 | expr-stmt ::= expr ";" 35 | 36 | expr ::= assign (, assign )* 37 | assign ::= conditional ("="|"+="|"-="|"*="|"/="|"%="|"<<="|">>="|"&="|"^="|"|=" asign)? 38 | conditional ::= logor ("?" expr ":" conditional)? 39 | logor ::= logand ("||" logand)* 40 | logand ::= bitor ("&&" bitor)* 41 | bitor ::= bitxor ("|" bitxor)* 42 | bitxor ::= bitand ("^" bitand)* 43 | bitand ::= equal ("&" equal)* 44 | equal ::= relational ("==" | "!=" relational)* 45 | relational ::= shift ("<"|">"|"<="|">=" shift)* 46 | shift ::= add ("<<" | ">>" add)* 47 | add ::= mult ("+" | "-" mult)* 48 | mult ::= cast ("*" | "/" | "%" cast)* 49 | cast ::= unary | "(" type-name ")" cast 50 | unary ::= postfix | ("++"|"--"|"&"|"*"|"+"|"-"|"~"|"!"|"sizeof") unary 51 | | "sizeof" "(" type-name ")" 52 | postfix ::= primary | postfix ("++"|"--") | postfix "[" expr "]" 53 | | postfix "." identifier 54 | | postfix "->" identifier 55 | | postfix "(" arg-expr-list? ")" 56 | arg-expr-list := assign ("," assign)* 57 | primary ::= identifier | number | "(" expr ")" 58 | number ::= ([0-9])+ 59 | identifier ::= (a-zA-Z_)(a-zA-Z0-9_)* 60 | type-name ::= decl-spec abstract-declarator? 61 | abstract-declarator ::= "*"* direct-abstract-declarator? 62 | direct-abstract-declarator ::= direct-abstract-declarator? "[" assign "]" -------------------------------------------------------------------------------- /eval_constant.cc: -------------------------------------------------------------------------------- 1 | #include "eval_constant.h" 2 | #include "type.h" 3 | EvalConstant::Constant EvalConstant::Eval(AstNode *node) { 4 | auto kind = node->GetKind(); 5 | switch (kind) 6 | { 7 | case AstNode::ND_BinaryExpr: 8 | return VisitBinaryExpr(llvm::dyn_cast(node)); 9 | case AstNode::ND_ThreeExpr: 10 | return VisitThreeExpr(llvm::dyn_cast(node)); 11 | case AstNode::ND_UnaryExpr: 12 | return VisitUnaryExpr(llvm::dyn_cast(node)); 13 | case AstNode::ND_CastExpr: 14 | return VisitCastExpr(llvm::dyn_cast(node)); 15 | case AstNode::ND_SizeOfExpr: 16 | return VisitSizeOfExpr(llvm::dyn_cast(node)); 17 | case AstNode::ND_NumberExpr: 18 | return VisitNumberExpr(llvm::dyn_cast(node)); 19 | default: 20 | break; 21 | } 22 | diagEngine.Report(llvm::SMLoc::getFromPointer(node->tok.ptr), diag::err_constant_expr); 23 | return 0; 24 | } 25 | 26 | EvalConstant::Constant EvalConstant::VisitNumberExpr(NumberExpr *expr) { 27 | if (expr->ty->IsIntegerType()) { 28 | return expr->value.v; 29 | } 30 | return expr->value.d; 31 | } 32 | 33 | EvalConstant::Constant EvalConstant::VisitBinaryExpr(BinaryExpr *binaryExpr) { 34 | EvalConstant::Constant left = Eval(binaryExpr->left.get()); 35 | EvalConstant::Constant right = Eval(binaryExpr->right.get()); 36 | return std::visit([&](auto &lhs) -> EvalConstant::Constant { 37 | using T1 = std::decay_t; 38 | return std::visit([&](auto &rhs) -> EvalConstant::Constant { 39 | using T2 = std::decay_t; 40 | switch (binaryExpr->op) 41 | { 42 | case BinaryOp::add: { 43 | return lhs + rhs; 44 | } 45 | case BinaryOp::sub: { 46 | return lhs - rhs; 47 | } 48 | case BinaryOp::mul: { 49 | return lhs * rhs; 50 | } 51 | case BinaryOp::div: { 52 | return lhs / rhs; 53 | } 54 | case BinaryOp::mod: { 55 | if constexpr (!std::is_same_v) { 56 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 57 | return 0; 58 | } 59 | else if constexpr (!std::is_same_v) { 60 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 61 | return 0; 62 | } 63 | else { 64 | return lhs % rhs; 65 | } 66 | } 67 | case BinaryOp::equal: { 68 | return lhs == rhs; 69 | } 70 | case BinaryOp::not_equal: { 71 | return lhs != rhs; 72 | } 73 | case BinaryOp::less: { 74 | return lhs < rhs; 75 | } 76 | case BinaryOp::less_equal: { 77 | return lhs <= rhs; 78 | } 79 | case BinaryOp::greater: { 80 | return lhs > rhs; 81 | } 82 | case BinaryOp::greater_equal: { 83 | return lhs >= rhs; 84 | } 85 | case BinaryOp::logical_or: { 86 | return lhs || rhs; 87 | } 88 | case BinaryOp::logical_and: { 89 | return lhs && rhs; 90 | } 91 | case BinaryOp::bitwise_or: { 92 | if constexpr (!std::is_same_v) { 93 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 94 | return 0; 95 | }else if constexpr (!std::is_same_v) { 96 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 97 | return 0; 98 | }else { 99 | return lhs | rhs; 100 | } 101 | } 102 | case BinaryOp::bitwise_xor: { 103 | if constexpr (!std::is_same_v) { 104 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 105 | return 0; 106 | }else if constexpr (!std::is_same_v) { 107 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 108 | return 0; 109 | }else { 110 | return lhs ^ rhs; 111 | } 112 | } 113 | case BinaryOp::bitwise_and: { 114 | if constexpr (!std::is_same_v) { 115 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 116 | return 0; 117 | }else if constexpr (!std::is_same_v) { 118 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 119 | return 0; 120 | }else { 121 | return lhs & rhs; 122 | } 123 | } 124 | case BinaryOp::left_shift: { 125 | if constexpr (!std::is_same_v) { 126 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 127 | return 0; 128 | }else if constexpr (!std::is_same_v) { 129 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 130 | return 0; 131 | }else { 132 | return lhs << rhs; 133 | } 134 | } 135 | case BinaryOp::right_shift: { 136 | if constexpr (!std::is_same_v) { 137 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 138 | return 0; 139 | }else if constexpr (!std::is_same_v) { 140 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 141 | return 0; 142 | }else { 143 | return lhs >> rhs; 144 | } 145 | } 146 | case BinaryOp::comma: { 147 | return rhs; 148 | } 149 | default: 150 | diagEngine.Report(llvm::SMLoc::getFromPointer(binaryExpr->tok.ptr), diag::err_constant_expr); 151 | return 0; 152 | } 153 | }, right); 154 | }, left); 155 | } 156 | 157 | EvalConstant::Constant EvalConstant::VisitUnaryExpr(UnaryExpr *expr) { 158 | EvalConstant::Constant val = Eval(expr->node.get()); 159 | switch (expr->op) 160 | { 161 | case UnaryOp::positive: 162 | return val; 163 | case UnaryOp::negative: 164 | return std::visit([](auto &lhs)->EvalConstant::Constant { 165 | return -lhs; 166 | }, val); 167 | case UnaryOp::logical_not: 168 | return std::visit([](auto &lhs)->EvalConstant::Constant { 169 | return !lhs; 170 | }, val); 171 | case UnaryOp::bitwise_not: 172 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 173 | using T = std::decay_t; 174 | if constexpr (!std::is_same_v) { 175 | diagEngine.Report(llvm::SMLoc::getFromPointer(expr->tok.ptr), diag::err_constant_expr); 176 | return 0; 177 | }else { 178 | return ~lhs; 179 | } 180 | }, val); 181 | default: 182 | diagEngine.Report(llvm::SMLoc::getFromPointer(expr->tok.ptr), diag::err_constant_expr); 183 | return 0; 184 | } 185 | } 186 | 187 | /* 188 | TY_Char, 189 | TY_UChar, 190 | TY_Short, 191 | TY_UShort, 192 | TY_Int, 193 | TY_UInt, 194 | TY_Long, 195 | TY_ULong, 196 | TY_LLong, 197 | TY_ULLong, 198 | TY_Float, 199 | TY_Double, 200 | TY_LDouble,*/ 201 | EvalConstant::Constant EvalConstant::VisitCastExpr(CastExpr *expr) { 202 | EvalConstant::Constant val = Eval(expr->node.get()); 203 | if (expr->targetType) { 204 | if (!expr->targetType->IsArithType()) { 205 | diagEngine.Report(llvm::SMLoc::getFromPointer(expr->tok.ptr), diag::err_constant_expr); 206 | return 0; 207 | } 208 | auto kind = expr->targetType->GetKind(); 209 | switch (kind) 210 | { 211 | case CType::TY_Char: 212 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 213 | return (int8_t)lhs; 214 | }, val); 215 | case CType::TY_UChar: 216 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 217 | return (uint8_t)lhs; 218 | }, val); 219 | case CType::TY_Short: 220 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 221 | return (int16_t)lhs; 222 | }, val); 223 | case CType::TY_UShort: 224 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 225 | return (uint16_t)lhs; 226 | }, val); 227 | case CType::TY_Int: 228 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 229 | return (int32_t)lhs; 230 | }, val); 231 | case CType::TY_UInt: 232 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 233 | return (uint32_t)lhs; 234 | }, val); 235 | case CType::TY_Long: 236 | case CType::TY_ULong: 237 | case CType::TY_LLong: 238 | case CType::TY_ULLong: 239 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 240 | return (int64_t)lhs; 241 | }, val); 242 | case CType::TY_Float: 243 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 244 | return (float)lhs; 245 | }, val); 246 | case CType::TY_Double: 247 | case CType::TY_LDouble: 248 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 249 | return (double)lhs; 250 | }, val); 251 | default: 252 | diagEngine.Report(llvm::SMLoc::getFromPointer(expr->tok.ptr), diag::err_constant_expr); 253 | return 0; 254 | } 255 | } 256 | return val; 257 | } 258 | EvalConstant::Constant EvalConstant::VisitSizeOfExpr(SizeOfExpr *expr) { 259 | if (expr->type) { 260 | return expr->type->GetSize() / 8; 261 | }else { 262 | return expr->node->ty->GetSize() / 8; 263 | } 264 | } 265 | 266 | EvalConstant::Constant EvalConstant::VisitThreeExpr(ThreeExpr *expr) { 267 | EvalConstant::Constant cond = Eval(expr->cond.get()); 268 | EvalConstant::Constant then = Eval(expr->then.get()); 269 | EvalConstant::Constant els = Eval(expr->els.get()); 270 | 271 | return std::visit([&](auto &lhs)->EvalConstant::Constant { 272 | if (lhs) { 273 | return then; 274 | }else { 275 | return els; 276 | } 277 | }, cond); 278 | } -------------------------------------------------------------------------------- /eval_constant.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ast.h" 3 | #include 4 | #include "diag_engine.h" 5 | 6 | class EvalConstant{ 7 | private: 8 | DiagEngine &diagEngine; 9 | public: 10 | using Constant = std::variant; 11 | 12 | EvalConstant(DiagEngine &diagEngine):diagEngine(diagEngine){} 13 | Constant Eval(AstNode *node); 14 | private: 15 | Constant VisitNumberExpr(NumberExpr *expr); 16 | Constant VisitBinaryExpr(BinaryExpr *binaryExpr); 17 | Constant VisitUnaryExpr(UnaryExpr *expr); 18 | Constant VisitCastExpr(CastExpr *expr); 19 | Constant VisitSizeOfExpr(SizeOfExpr *expr); 20 | Constant VisitPostIncExpr(PostIncExpr *expr); 21 | Constant VisitPostDecExpr(PostDecExpr *expr); 22 | Constant VisitPostSubscript(PostSubscript *expr); 23 | Constant VisitPostMemberDotExpr(PostMemberDotExpr *expr); 24 | Constant VisitPostMemberArrowExpr(PostMemberArrowExpr *expr); 25 | Constant VisitThreeExpr(ThreeExpr *expr); 26 | }; -------------------------------------------------------------------------------- /lexer.cc: -------------------------------------------------------------------------------- 1 | #include "lexer.h" 2 | #include 3 | 4 | llvm::StringRef Token::GetSpellingText(TokenType tokenType) { 5 | switch (tokenType) 6 | { 7 | case TokenType::number: 8 | return "number"; 9 | case TokenType::str: 10 | return "string"; 11 | case TokenType::identifier: 12 | return "identifier"; 13 | case TokenType::kw_int: 14 | return "int"; 15 | case TokenType::kw_if: 16 | return "if"; 17 | case TokenType::kw_else: 18 | return "else"; 19 | case TokenType::kw_for: 20 | return "for"; 21 | case TokenType::kw_break: 22 | return "break"; 23 | case TokenType::kw_continue: 24 | return "continue"; 25 | case TokenType::kw_sizeof: 26 | return "sizeof"; 27 | case TokenType::minus: 28 | return "-"; 29 | case TokenType::plus: 30 | return "+"; 31 | case TokenType::star: 32 | return "*"; 33 | case TokenType::slash: 34 | return "/"; 35 | case TokenType::percent: 36 | return "%"; 37 | case TokenType::l_parent: 38 | return "("; 39 | case TokenType::r_parent: 40 | return ")"; 41 | case TokenType::semi: 42 | return ";"; 43 | case TokenType::equal: 44 | return "="; 45 | case TokenType::comma: 46 | return ","; 47 | case TokenType::l_brace: 48 | return "{"; 49 | case TokenType::r_brace: 50 | return "}"; 51 | case TokenType::equal_equal: 52 | return "=="; 53 | case TokenType::not_equal: 54 | return "!="; 55 | case TokenType::less: 56 | return "<"; 57 | case TokenType::less_equal: 58 | return "<="; 59 | case TokenType::greater: 60 | return ">"; 61 | case TokenType::greater_equal: 62 | return ">="; 63 | case TokenType::pipepipe: 64 | return "||"; 65 | case TokenType::pipe: 66 | return "|"; 67 | case TokenType::amp: 68 | return "&"; 69 | case TokenType::ampamp: 70 | return "&&"; 71 | case TokenType::less_less: 72 | return "<<"; 73 | case TokenType::greater_greater: 74 | return ">>"; 75 | case TokenType::caret: 76 | return "^"; 77 | case TokenType::plus_plus: 78 | return "++"; 79 | case TokenType::minus_minus: 80 | return "--"; 81 | case TokenType::tilde: 82 | return "~"; 83 | case TokenType::exclaim: 84 | return "!"; 85 | case TokenType::plus_equal: 86 | return "+="; 87 | case TokenType::minus_equal: 88 | return "-="; 89 | case TokenType::star_equal: 90 | return "*="; 91 | case TokenType::slash_equal: 92 | return "/="; 93 | case TokenType::percent_equal: 94 | return "%="; 95 | case TokenType::less_less_equal: 96 | return "<<="; 97 | case TokenType::greater_greater_equal: 98 | return ">>="; 99 | case TokenType::amp_equal: 100 | return "&="; 101 | case TokenType::caret_equal: 102 | return "^="; 103 | case TokenType::pipe_equal: 104 | return "|="; 105 | case TokenType::question: 106 | return "?"; 107 | case TokenType::colon: 108 | return ":"; 109 | case TokenType::l_bracket: 110 | return "["; 111 | case TokenType::r_bracket: 112 | return "]"; 113 | case TokenType::kw_struct: 114 | return "struct"; 115 | case TokenType::kw_union: 116 | return "union"; 117 | case TokenType::dot: 118 | return "."; 119 | case TokenType::arrow: 120 | return "->"; 121 | case TokenType::kw_return: 122 | return "return"; 123 | case TokenType::kw_void: 124 | return "void"; 125 | case TokenType::kw_const: 126 | return "const"; 127 | case TokenType::kw_volatile: 128 | return "volatile"; 129 | case TokenType::kw_static: 130 | return "static"; 131 | case TokenType::ellipse: 132 | return "..."; 133 | case TokenType::kw_while: 134 | return "while"; 135 | case TokenType::kw_do: 136 | return "do"; 137 | case TokenType::kw_switch: 138 | return "switch"; 139 | case TokenType::kw_case: 140 | return "case"; 141 | case TokenType::kw_default: 142 | return "default"; 143 | case TokenType::kw_short: 144 | return "short"; 145 | case TokenType::kw_long: 146 | return "long"; 147 | case TokenType::kw_float: 148 | return "float"; 149 | case TokenType::kw_double: 150 | return "double"; 151 | case TokenType::kw_signed: 152 | return "signed"; 153 | case TokenType::kw_unsigned: 154 | return "unsigned"; 155 | case TokenType::kw_typedef: 156 | return "typedef"; 157 | case TokenType::kw_extern: 158 | return "extern"; 159 | case TokenType::kw_auto: 160 | return "auto"; 161 | case TokenType::kw_register: 162 | return "register"; 163 | case TokenType::kw_inline: 164 | return "inline"; 165 | default: 166 | llvm::llvm_unreachable_internal(); 167 | } 168 | } 169 | 170 | bool IsWhiteSpace(char ch) { 171 | return ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t'; 172 | } 173 | 174 | bool IsDigit(char ch) { 175 | return (ch >= '0' && ch <= '9'); 176 | } 177 | 178 | bool IsHexDigit(char ch) { 179 | return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); 180 | } 181 | 182 | bool IsLetter(char ch) { 183 | return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_'); 184 | } 185 | 186 | // Read a single character in a char or string literal. 187 | static const char *c_char(int *res, const char *p) { 188 | // Nonescaped 189 | if (*p != '\\') { 190 | *res = *p; 191 | return p + 1; 192 | } 193 | p++; 194 | 195 | int esc = 0; 196 | switch (*p) { 197 | case 'a': { 198 | esc = '\a'; 199 | break; 200 | } 201 | case 'b': { 202 | esc = '\b'; 203 | break; 204 | } 205 | case 'f': { 206 | esc = '\f'; 207 | break; 208 | } 209 | case 'n': { 210 | esc = '\n'; 211 | break; 212 | } 213 | case 'r': { 214 | esc = '\r'; 215 | break; 216 | } 217 | case 't': { 218 | esc = '\t'; 219 | break; 220 | } 221 | case 'v': { 222 | esc = '\v'; 223 | break; 224 | } 225 | default : { 226 | esc = *p; 227 | break; 228 | } 229 | } 230 | *res = esc; 231 | return p + 1; 232 | } 233 | 234 | bool Lexer::StartWith(const char *p) { 235 | return !strncmp(BufPtr, p, strlen(p)); 236 | } 237 | 238 | bool Lexer::StartWith(const char *source, const char *target) { 239 | return !strncmp(source, target, strlen(target)); 240 | } 241 | 242 | void Lexer::NextToken(Token &tok) { 243 | 244 | /// 1. 过滤空格 245 | while (IsWhiteSpace(*BufPtr) || StartWith("//") || StartWith("/*")) { 246 | if (StartWith("//")) { 247 | while (*BufPtr != '\n' && (BufPtr < BufEnd)){ 248 | BufPtr++; 249 | } 250 | } 251 | 252 | if (StartWith("/*")) { 253 | while ((BufPtr[0] != '*' || BufPtr[1] != '/') && (BufPtr < BufEnd)) { 254 | if (*BufPtr == '\n') { 255 | row++; 256 | LineHeadPtr = BufPtr+1; 257 | } 258 | BufPtr++; 259 | } 260 | BufPtr += 2; 261 | } 262 | 263 | if (BufPtr >= BufEnd) { 264 | tok.tokenType = TokenType::eof; 265 | return; 266 | } 267 | 268 | if (*BufPtr == '\n') { 269 | row++; 270 | LineHeadPtr = BufPtr+1; 271 | } 272 | BufPtr++; 273 | } 274 | 275 | /// 2. 判断是否到结尾 276 | if (BufPtr >= BufEnd) { 277 | tok.tokenType = TokenType::eof; 278 | return; 279 | } 280 | 281 | tok.row = row; 282 | tok.col = BufPtr - LineHeadPtr + 1; 283 | 284 | const char *StartPtr = BufPtr; 285 | 286 | if (*BufPtr == '\'') { 287 | tok.tokenType = TokenType::number; 288 | tok.ty = CType::IntType; 289 | tok.ptr = BufPtr++; 290 | BufPtr = c_char((int *)&tok.value.v, BufPtr); 291 | if (*BufPtr != '\'') 292 | diagEngine.Report(llvm::SMLoc::getFromPointer(BufPtr), diag::err_unclosed_character); 293 | BufPtr += 1; 294 | tok.len = BufPtr - StartPtr; 295 | } 296 | else if (*BufPtr == '"') { 297 | BufPtr++; // skip " 298 | tok.tokenType = TokenType::str; 299 | tok.ptr = BufPtr; 300 | std::string value; 301 | while (*BufPtr != '"') { 302 | if (!*BufPtr) { 303 | diagEngine.Report(llvm::SMLoc::getFromPointer(BufPtr), diag::err_unclosed_string); 304 | } 305 | int c; 306 | BufPtr = c_char(&c, BufPtr); 307 | value += c; 308 | } 309 | BufPtr++; // skip " 310 | tok.len = BufPtr - tok.ptr; 311 | tok.strVal = value; 312 | tok.ty = std::make_shared(CType::CharType, tok.len); 313 | } 314 | else if (StartWith("0x") || StartWith("0X") || 315 | StartWith("0b") || StartWith("0B") || 316 | IsDigit(*BufPtr) || (*BufPtr == '.' && IsDigit(BufPtr[1]))) { 317 | const char *p = BufPtr; 318 | for (;;) { 319 | if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1])) 320 | p += 2; 321 | else if (isalnum(*p) || *p == '.') 322 | p++; 323 | else 324 | break; 325 | } 326 | BufPtr = ConvertNumber(tok, StartPtr, p); 327 | } else if (IsLetter(*BufPtr)) { 328 | while (IsLetter(*BufPtr) || IsDigit(*BufPtr)) { 329 | BufPtr++; 330 | } 331 | tok.tokenType = TokenType::identifier; 332 | tok.ptr = StartPtr; 333 | tok.len = BufPtr - StartPtr; 334 | llvm::StringRef text = llvm::StringRef(tok.ptr, tok.len); 335 | if (text == "int") { 336 | tok.tokenType = TokenType::kw_int; 337 | }else if (text == "if") { 338 | tok.tokenType = TokenType::kw_if; 339 | }else if (text == "else") { 340 | tok.tokenType = TokenType::kw_else; 341 | }else if (text == "for") { 342 | tok.tokenType = TokenType::kw_for; 343 | }else if (text == "break") { 344 | tok.tokenType = TokenType::kw_break; 345 | }else if (text == "continue") { 346 | tok.tokenType = TokenType::kw_continue; 347 | }else if (text == "sizeof") { 348 | tok.tokenType = TokenType::kw_sizeof; 349 | }else if (text == "struct") { 350 | tok.tokenType = TokenType::kw_struct; 351 | }else if (text == "union") { 352 | tok.tokenType = TokenType::kw_union; 353 | }else if (text == "return") { 354 | tok.tokenType = TokenType::kw_return; 355 | }else if (text == "void") { 356 | tok.tokenType = TokenType::kw_void; 357 | }else if (text == "char") { 358 | tok.tokenType = TokenType::kw_char; 359 | }else if (text == "const") { 360 | tok.tokenType = TokenType::kw_const; 361 | }else if (text == "volatile") { 362 | tok.tokenType = TokenType::kw_volatile; 363 | }else if (text == "static") { 364 | tok.tokenType = TokenType::kw_static; 365 | }else if (text == "while") { 366 | tok.tokenType = TokenType::kw_while; 367 | }else if (text == "do") { 368 | tok.tokenType = TokenType::kw_do; 369 | }else if (text == "switch") { 370 | tok.tokenType = TokenType::kw_switch; 371 | }else if (text == "case") { 372 | tok.tokenType = TokenType::kw_case; 373 | }else if (text == "default") { 374 | tok.tokenType = TokenType::kw_default; 375 | }else if (text == "short") { 376 | tok.tokenType = TokenType::kw_short; 377 | }else if (text == "long") { 378 | tok.tokenType = TokenType::kw_long; 379 | }else if (text == "float") { 380 | tok.tokenType = TokenType::kw_float; 381 | }else if (text == "double") { 382 | tok.tokenType = TokenType::kw_double; 383 | }else if (text == "signed") { 384 | tok.tokenType = TokenType::kw_signed; 385 | }else if (text == "unsigned") { 386 | tok.tokenType = TokenType::kw_unsigned; 387 | }else if (text == "typedef") { 388 | tok.tokenType = TokenType::kw_typedef; 389 | }else if (text == "auto") { 390 | tok.tokenType = TokenType::kw_auto; 391 | }else if (text == "extern") { 392 | tok.tokenType = TokenType::kw_extern; 393 | }else if (text == "register") { 394 | tok.tokenType = TokenType::kw_register; 395 | }else if (text == "inline") { 396 | tok.tokenType = TokenType::kw_inline; 397 | } 398 | } 399 | else { 400 | switch (*BufPtr) 401 | { 402 | case '+': { 403 | if (BufPtr[1] == '+') { 404 | tok.tokenType = TokenType::plus_plus; 405 | BufPtr+=2; 406 | tok.ptr = StartPtr; 407 | tok.len = 2; 408 | }else if (BufPtr[1] == '=') { 409 | tok.tokenType = TokenType::plus_equal; 410 | BufPtr+=2; 411 | tok.ptr = StartPtr; 412 | tok.len = 2; 413 | } 414 | else { 415 | tok.tokenType = TokenType::plus; 416 | BufPtr++; 417 | tok.ptr = StartPtr; 418 | tok.len = 1; 419 | } 420 | break; 421 | } 422 | case '-': { 423 | if (BufPtr[1] == '-') { 424 | tok.tokenType = TokenType::minus_minus; 425 | BufPtr+=2; 426 | tok.ptr = StartPtr; 427 | tok.len = 2; 428 | }else if (BufPtr[1] == '=') { 429 | tok.tokenType = TokenType::minus_equal; 430 | BufPtr += 2; 431 | tok.ptr = StartPtr; 432 | tok.len = 2; 433 | }else if (BufPtr[1] == '>') { 434 | tok.tokenType = TokenType::arrow; 435 | BufPtr += 2; 436 | tok.ptr = StartPtr; 437 | tok.len = 2; 438 | } 439 | else { 440 | tok.tokenType = TokenType::minus; 441 | BufPtr++; 442 | tok.ptr = StartPtr; 443 | tok.len = 1; 444 | } 445 | break; 446 | } 447 | case '*':{ 448 | if (BufPtr[1] == '=') { 449 | tok.tokenType = TokenType::star_equal; 450 | BufPtr+=2; 451 | tok.ptr = StartPtr; 452 | tok.len = 2; 453 | }else { 454 | tok.tokenType = TokenType::star; 455 | BufPtr++; 456 | tok.ptr = StartPtr; 457 | tok.len = 1; 458 | } 459 | break; 460 | } 461 | case '/':{ 462 | if (BufPtr[1] == '=') { 463 | tok.tokenType = TokenType::slash_equal; 464 | BufPtr+=2; 465 | tok.ptr = StartPtr; 466 | tok.len = 2; 467 | }else { 468 | tok.tokenType = TokenType::slash; 469 | BufPtr++; 470 | tok.ptr = StartPtr; 471 | tok.len = 1; 472 | } 473 | break; 474 | } 475 | case '%':{ 476 | if (BufPtr[1] == '=') { 477 | tok.tokenType = TokenType::percent_equal; 478 | BufPtr+=2; 479 | tok.ptr = StartPtr; 480 | tok.len = 2; 481 | }else { 482 | tok.tokenType = TokenType::percent; 483 | BufPtr++; 484 | tok.ptr = StartPtr; 485 | tok.len = 1; 486 | } 487 | break; 488 | } 489 | case ';':{ 490 | tok.tokenType = TokenType::semi; 491 | BufPtr++; 492 | tok.ptr = StartPtr; 493 | tok.len = 1; 494 | break; 495 | } 496 | case '(':{ 497 | tok.tokenType = TokenType::l_parent; 498 | BufPtr++; 499 | tok.ptr = StartPtr; 500 | tok.len = 1; 501 | break; 502 | } 503 | case ')':{ 504 | tok.tokenType = TokenType::r_parent; 505 | BufPtr++; 506 | tok.ptr = StartPtr; 507 | tok.len = 1; 508 | break; 509 | } 510 | case '=':{ 511 | if (*(BufPtr+1) == '=') { 512 | tok.tokenType = TokenType::equal_equal; 513 | BufPtr+=2; 514 | tok.ptr = StartPtr; 515 | tok.len = 2; 516 | }else { 517 | tok.tokenType = TokenType::equal; 518 | BufPtr++; 519 | tok.ptr = StartPtr; 520 | tok.len = 1; 521 | } 522 | break; 523 | } 524 | case '|':{ 525 | if (*(BufPtr+1) == '|') { 526 | tok.tokenType = TokenType::pipepipe; 527 | BufPtr+=2; 528 | tok.ptr = StartPtr; 529 | tok.len = 2; 530 | } else if (*(BufPtr+1) == '=') { 531 | tok.tokenType = TokenType::pipe_equal; 532 | BufPtr+=2; 533 | tok.ptr = StartPtr; 534 | tok.len = 2; 535 | } 536 | else { 537 | tok.tokenType = TokenType::pipe; 538 | BufPtr++; 539 | tok.ptr = StartPtr; 540 | tok.len = 1; 541 | } 542 | break; 543 | } 544 | case '&':{ 545 | if (*(BufPtr+1) == '&') { 546 | tok.tokenType = TokenType::ampamp; 547 | BufPtr+=2; 548 | tok.ptr = StartPtr; 549 | tok.len = 2; 550 | } else if (*(BufPtr+1) == '=') { 551 | tok.tokenType = TokenType::amp_equal; 552 | BufPtr+=2; 553 | tok.ptr = StartPtr; 554 | tok.len = 2; 555 | } 556 | else { 557 | tok.tokenType = TokenType::amp; 558 | BufPtr++; 559 | tok.ptr = StartPtr; 560 | tok.len = 1; 561 | } 562 | break; 563 | } 564 | case '~': { 565 | tok.tokenType = TokenType::tilde; 566 | BufPtr++; 567 | tok.ptr = StartPtr; 568 | tok.len = 1; 569 | break; 570 | } 571 | case ',':{ 572 | tok.tokenType = TokenType::comma; 573 | BufPtr++; 574 | tok.ptr = StartPtr; 575 | tok.len = 1; 576 | break; 577 | } 578 | case '{': { 579 | tok.tokenType = TokenType::l_brace; 580 | BufPtr++; 581 | tok.ptr = StartPtr; 582 | tok.len = 1; 583 | break; 584 | } 585 | case '}': { 586 | tok.tokenType = TokenType::r_brace; 587 | BufPtr++; 588 | tok.ptr = StartPtr; 589 | tok.len = 1; 590 | break; 591 | } 592 | case '^': { 593 | if (*(BufPtr+1) == '=') { 594 | tok.tokenType = TokenType::caret_equal; 595 | BufPtr+=2; 596 | tok.ptr = StartPtr; 597 | tok.len = 2; 598 | }else { 599 | tok.tokenType = TokenType::caret; 600 | BufPtr++; 601 | tok.ptr = StartPtr; 602 | tok.len = 1; 603 | } 604 | break; 605 | } 606 | case '<': { 607 | if (*(BufPtr+1) == '=') { 608 | tok.tokenType = TokenType::less_equal; 609 | BufPtr+=2; 610 | tok.ptr = StartPtr; 611 | tok.len = 2; 612 | }else if (*(BufPtr+1) == '<') { 613 | if (BufPtr[2] == '=') { 614 | tok.tokenType = TokenType::less_less_equal; 615 | BufPtr+=3; 616 | tok.ptr = StartPtr; 617 | tok.len = 3; 618 | }else { 619 | tok.tokenType = TokenType::less_less; 620 | BufPtr+=2; 621 | tok.ptr = StartPtr; 622 | tok.len = 2; 623 | } 624 | }else { 625 | tok.tokenType = TokenType::less; 626 | BufPtr++; 627 | tok.ptr = StartPtr; 628 | tok.len = 1; 629 | } 630 | break; 631 | } 632 | case '>': { 633 | if (*(BufPtr+1) == '=') { 634 | tok.tokenType = TokenType::greater_equal; 635 | BufPtr+=2; 636 | tok.ptr = StartPtr; 637 | tok.len = 2; 638 | }else if (*(BufPtr+1) == '>') { 639 | if (BufPtr[2] == '=') { 640 | tok.tokenType = TokenType::greater_greater_equal; 641 | BufPtr+=3; 642 | tok.ptr = StartPtr; 643 | tok.len = 3; 644 | }else { 645 | tok.tokenType = TokenType::greater_greater; 646 | BufPtr+=2; 647 | tok.ptr = StartPtr; 648 | tok.len = 2; 649 | } 650 | }else { 651 | tok.tokenType = TokenType::greater; 652 | BufPtr++; 653 | tok.ptr = StartPtr; 654 | tok.len = 1; 655 | } 656 | break; 657 | } 658 | case '!': { 659 | if (*(BufPtr+1) == '=') { 660 | tok.tokenType = TokenType::not_equal; 661 | BufPtr+=2; 662 | tok.ptr = StartPtr; 663 | tok.len = 2; 664 | }else { 665 | tok.tokenType = TokenType::exclaim; 666 | BufPtr++; 667 | tok.ptr = StartPtr; 668 | tok.len = 1; 669 | } 670 | break; 671 | } 672 | case '?': { 673 | tok.tokenType = TokenType::question; 674 | BufPtr++; 675 | tok.ptr = StartPtr; 676 | tok.len = 1; 677 | break; 678 | } 679 | case ':': { 680 | tok.tokenType = TokenType::colon; 681 | BufPtr++; 682 | tok.ptr = StartPtr; 683 | tok.len = 1; 684 | break; 685 | } 686 | case '[': { 687 | tok.tokenType = TokenType::l_bracket; 688 | BufPtr++; 689 | tok.ptr = StartPtr; 690 | tok.len = 1; 691 | break; 692 | } 693 | case ']': { 694 | tok.tokenType = TokenType::r_bracket; 695 | BufPtr++; 696 | tok.ptr = StartPtr; 697 | tok.len = 1; 698 | break; 699 | } 700 | case '.': { 701 | if (BufPtr[1] == '.' && BufPtr[2] == '.') { 702 | tok.tokenType = TokenType::ellipse; 703 | BufPtr+=3; 704 | tok.ptr = StartPtr; 705 | tok.len = 3; 706 | }else { 707 | tok.tokenType = TokenType::dot; 708 | BufPtr++; 709 | tok.ptr = StartPtr; 710 | tok.len = 1; 711 | } 712 | break; 713 | } 714 | default: 715 | diagEngine.Report(llvm::SMLoc::getFromPointer(BufPtr), diag::err_unknown_char, *BufPtr); 716 | break; 717 | } 718 | } 719 | } 720 | 721 | const char * Lexer::ConvertNumber(Token &tok, const char *start, const char *end) { 722 | const auto &[res, endptr] = ConvertIntNumber(tok, start, end); 723 | if (res) { 724 | return endptr; 725 | } 726 | return ConvertFloatNumber(tok, start, end).second; 727 | } 728 | 729 | std::pair Lexer::ConvertIntNumber(Token &tok, const char *start, const char *end) { 730 | // Read a binary, octal, decimal or hexadecimal number. 731 | char *p = const_cast(start); 732 | int base = 10; 733 | if (!strncasecmp(p, "0x", 2) && isxdigit(p[2])) { 734 | p += 2; 735 | base = 16; 736 | } else if (!strncasecmp(p, "0b", 2) && (p[2] == '0' || p[2] == '1')) { 737 | p += 2; 738 | base = 2; 739 | } else if (*p == '0') { 740 | base = 8; 741 | } 742 | 743 | int64_t val = strtoul(p, &p, base); 744 | 745 | // Read U, L or LL suffixes. 746 | bool l = false; 747 | bool u = false; 748 | 749 | if (StartWith(p, "LLU") || StartWith(p, "LLu") || 750 | StartWith(p, "llU") || StartWith(p, "llu") || 751 | StartWith(p, "ULL") || StartWith(p, "Ull") || 752 | StartWith(p, "uLL") || StartWith(p, "ull")) { 753 | p += 3; 754 | l = u = true; 755 | } else if (!strncasecmp(p, "lu", 2) || !strncasecmp(p, "ul", 2)) { 756 | p += 2; 757 | l = u = true; 758 | } else if (StartWith(p, "LL") || StartWith(p, "ll")) { 759 | p += 2; 760 | l = true; 761 | } else if (*p == 'L' || *p == 'l') { 762 | p++; 763 | l = true; 764 | } else if (*p == 'U' || *p == 'u') { 765 | p++; 766 | u = true; 767 | } 768 | 769 | if (p != end) 770 | return {false, p}; 771 | 772 | // Infer a type. 773 | std::shared_ptr ty; 774 | if (base == 10) { 775 | if (l && u) 776 | ty = CType::ULongType;//ty_ulong; 777 | else if (l) 778 | ty = CType::LongType;//ty_long; 779 | else if (u) 780 | ty = (val >> 32) ? CType::ULongType : CType::UIntType; 781 | else 782 | ty = (val >> 31) ? CType::LongType : CType::IntType; 783 | } else { 784 | if (l && u) 785 | ty = CType::ULongType; 786 | else if (l) 787 | ty = (val >> 63) ? CType::ULongType : CType::LongType; 788 | else if (u) 789 | ty = (val >> 32) ? CType::ULongType : CType::UIntType; 790 | else if (val >> 63) 791 | ty = CType::ULongType; 792 | else if (val >> 32) 793 | ty = CType::LongType; 794 | else if (val >> 31) 795 | ty = CType::UIntType; 796 | else 797 | ty = CType::IntType; 798 | } 799 | 800 | tok.tokenType = TokenType::number; 801 | tok.ty = ty; 802 | tok.ptr = start; 803 | tok.len = end - start; 804 | tok.value.v = val; 805 | return {true, end}; 806 | } 807 | 808 | std::pair Lexer::ConvertFloatNumber(Token &tok, const char *pstart, const char *pend) { 809 | // If it's not an integer, it must be a floating point constant. 810 | char *end; 811 | long double val = strtold(pstart, &end); 812 | 813 | std::shared_ptr ty; 814 | if (*end == 'f' || *end == 'F') { 815 | ty = CType::FloatType; 816 | end++; 817 | } else if (*end == 'l' || *end == 'L') { 818 | ty = CType::LDoubleType; 819 | end++; 820 | } else { 821 | ty = CType::DoubleType; 822 | } 823 | 824 | if (pend != end) { 825 | diagEngine.Report(llvm::SMLoc::getFromPointer(end), diag::err_numeric_constant); 826 | return {false, end}; 827 | } 828 | 829 | tok.tokenType = TokenType::number; 830 | tok.value.d = val; 831 | tok.ty = ty; 832 | tok.ptr = pstart; 833 | tok.len = pend - pstart; 834 | return {true, pend}; 835 | } 836 | 837 | void Lexer::SaveState() { 838 | State state; 839 | state.BufPtr = BufPtr; 840 | state.LineHeadPtr = LineHeadPtr; 841 | state.BufEnd = BufEnd; 842 | state.row = row; 843 | stateStack.push(state); 844 | } 845 | 846 | void Lexer::RestoreState() { 847 | State state = stateStack.top(); 848 | stateStack.pop(); 849 | BufPtr = state.BufPtr; 850 | LineHeadPtr = state.LineHeadPtr; 851 | BufEnd = state.BufEnd; 852 | row = state.row; 853 | } -------------------------------------------------------------------------------- /lexer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "llvm/ADT/StringRef.h" 3 | #include "llvm/Support/raw_ostream.h" 4 | #include "type.h" 5 | #include "diag_engine.h" 6 | #include 7 | #include 8 | 9 | /// char stream -> Token 10 | 11 | enum class TokenType : uint8_t{ 12 | number, 13 | str, // string 14 | identifier, 15 | kw_int, // int 16 | kw_if, // if 17 | kw_else, // else 18 | kw_for, // for 19 | kw_break, // break 20 | kw_continue, // continue 21 | kw_sizeof, // sizeof 22 | minus, // - 23 | plus, // + 24 | star, // * 25 | slash, // '/' 26 | percent, // % 27 | l_parent, // ( 28 | r_parent, // ) 29 | semi, // ';' 30 | equal, // = 31 | comma, // , 32 | l_brace, // { 33 | r_brace, // } 34 | equal_equal, // == 35 | not_equal, // != 36 | less, // < 37 | less_equal, // <= 38 | greater, // > 39 | greater_equal, // >= 40 | pipepipe, // || 41 | pipe, // | 42 | amp, // & 43 | ampamp, // && 44 | less_less, // << 45 | greater_greater,// >> 46 | caret, // ^ 47 | plus_plus, // ++ 48 | minus_minus, // -- 49 | tilde, // ~ 50 | exclaim, // ! 51 | plus_equal, // += 52 | minus_equal, // -= 53 | star_equal, // *= 54 | slash_equal, // '/=' 55 | percent_equal, // %= 56 | less_less_equal, // <<= 57 | greater_greater_equal, // >>= 58 | amp_equal, // &= 59 | caret_equal, // ^= 60 | pipe_equal, // |= 61 | question, // ? 62 | colon, // : 63 | l_bracket, // [ 64 | r_bracket, // ] 65 | kw_struct, // struct, 66 | kw_union, // union 67 | dot, // . 68 | arrow, // -> 69 | kw_void, // void 70 | kw_return, // return 71 | kw_char, // char 72 | kw_short, // short 73 | kw_long, // long 74 | kw_float, // float 75 | kw_double, // double 76 | kw_signed, // signed 77 | kw_unsigned, // unsigned 78 | kw_typedef, // typedef 79 | kw_const, // const 80 | kw_volatile, // volatile 81 | kw_static, // static 82 | kw_extern, // extern 83 | kw_auto, // auto 84 | kw_register, // register 85 | kw_inline, // inline 86 | kw_while, // while 87 | kw_do, // do 88 | kw_switch, // switch 89 | kw_case, // case 90 | kw_default, // default 91 | ellipse, // ... 92 | eof // end 93 | }; 94 | 95 | class Token { 96 | public: 97 | TokenType tokenType; 98 | int row, col; 99 | 100 | union { 101 | int64_t v; 102 | double d; 103 | }value; // for number 104 | 105 | std::string strVal; // for "" 106 | 107 | const char *ptr; // for debug && diag 108 | int len; 109 | 110 | std::shared_ptr ty; // for built-in type 111 | 112 | void Dump() { 113 | llvm::outs() << "{ " << llvm::StringRef(ptr, len) << ", row = " << row << ", col = " << col << "}\n"; 114 | } 115 | 116 | static llvm::StringRef GetSpellingText(TokenType tokenType); 117 | }; 118 | 119 | class Lexer { 120 | private: 121 | llvm::SourceMgr &mgr; 122 | DiagEngine &diagEngine; 123 | llvm::StringRef fileName; 124 | public: 125 | Lexer(llvm::SourceMgr &mgr, DiagEngine &diagEngine) : mgr(mgr), diagEngine(diagEngine) { 126 | unsigned id = mgr.getMainFileID(); 127 | llvm::StringRef buf = mgr.getMemoryBuffer(id)->getBuffer(); 128 | BufPtr = buf.begin(); 129 | LineHeadPtr = buf.begin(); 130 | BufEnd = buf.end(); 131 | row = 1; 132 | fileName = mgr.getMemoryBuffer(id)->getBufferIdentifier(); 133 | } 134 | 135 | void NextToken(Token &tok); 136 | 137 | void SaveState(); 138 | void RestoreState(); 139 | 140 | DiagEngine &GetDiagEngine() const { 141 | return diagEngine; 142 | } 143 | 144 | llvm::StringRef GetFileName() { 145 | return fileName; 146 | } 147 | private: 148 | bool StartWith(const char *p); 149 | bool StartWith(const char *source, const char *target); 150 | const char *ConvertNumber(Token &tok, const char *start, const char *end); 151 | std::pair ConvertIntNumber(Token &tok, const char *start, const char *end); 152 | std::pair ConvertFloatNumber(Token &tok, const char *start, const char *end); 153 | private: 154 | const char *BufPtr; 155 | const char *LineHeadPtr; 156 | const char *BufEnd; 157 | int row; 158 | 159 | struct State{ 160 | const char *BufPtr; 161 | const char *LineHeadPtr; 162 | const char *BufEnd; 163 | int row; 164 | }; 165 | 166 | std::stack stateStack; 167 | }; -------------------------------------------------------------------------------- /main.cc: -------------------------------------------------------------------------------- 1 | #include "codegen.h" 2 | #include "diag_engine.h" 3 | #include "lexer.h" 4 | #include "parser.h" 5 | #include "print_visitor.h" 6 | #include "sema.h" 7 | 8 | #include "llvm/CodeGen/CommandFlags.h" 9 | #include "llvm/Support/ErrorOr.h" 10 | #include "llvm/Support/MemoryBuffer.h" 11 | 12 | #include "llvm/ExecutionEngine/ExecutionEngine.h" 13 | #include "llvm/ExecutionEngine/SectionMemoryManager.h" 14 | #include "llvm/IR/LegacyPassManager.h" 15 | #include "llvm/IR/Verifier.h" 16 | #include "llvm/MC/TargetRegistry.h" 17 | #include "llvm/Support/CodeGen.h" 18 | #include "llvm/Support/CommandLine.h" 19 | #include "llvm/Support/FileSystem.h" 20 | #include "llvm/Support/TargetSelect.h" 21 | #include "llvm/Support/ToolOutputFile.h" 22 | #include "llvm/Target/TargetMachine.h" 23 | 24 | #include 25 | 26 | using namespace llvm; 27 | static cl::opt 28 | InputFilename(cl::Positional, cl::desc(""), cl::init("-")); 29 | 30 | static cl::opt 31 | OutputFilename("o", cl::desc("Output Asmber"), cl::value_desc("filename")); 32 | 33 | static cl::opt 34 | TargetTriple("mtriple", cl::desc("Override target triple for module")); 35 | 36 | /// #define JIT_TEST 37 | int main(int argc, char *argv[]) { 38 | cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); 39 | 40 | /// 初始化后端 41 | llvm::InitializeAllTargets(); 42 | llvm::InitializeAllTargetMCs(); 43 | llvm::InitializeAllAsmPrinters(); 44 | llvm::InitializeAllAsmParsers(); 45 | 46 | #ifdef JIT_TEST 47 | LLVMLinkInMCJIT(); 48 | #endif 49 | 50 | static llvm::ErrorOr> Buf = llvm::MemoryBuffer::getFile(InputFilename); 51 | if (!Buf) { 52 | llvm::errs() << "can't open file!!!\n"; 53 | return -1; 54 | } 55 | 56 | llvm::SourceMgr Mgr; 57 | DiagEngine DiagE(Mgr); 58 | 59 | Mgr.AddNewSourceBuffer(std::move(*Buf), llvm::SMLoc()); 60 | 61 | Lexer Lex(Mgr, DiagE); 62 | Sema SM(DiagE); 63 | Parser P(Lex, SM); 64 | auto Prog = P.ParseProgram(); 65 | // PrintVisitor visitor(program); 66 | CodeGen CG(Prog); 67 | 68 | auto &M = CG.GetModule(); 69 | 70 | // llvm::outs() << "1>>> output ir\n"; 71 | // M->print(llvm::outs(), nullptr); 72 | assert(!llvm::verifyModule(*M)); 73 | 74 | #ifdef JIT_TEST 75 | { 76 | llvm::EngineBuilder builder(std::move(M)); 77 | std::string error; 78 | auto ptr = std::make_unique(); 79 | auto ref = ptr.get(); 80 | std::unique_ptr ee( 81 | builder.setErrorStr(&error) 82 | .setEngineKind(llvm::EngineKind::JIT) 83 | .setOptLevel(llvm::CodeGenOptLevel::None) 84 | .setSymbolResolver(std::move(ptr)) 85 | .create()); 86 | ref->finalizeMemory(&error); 87 | 88 | void *addr = (void *)ee->getFunctionAddress("main"); 89 | int res = ((int (*)())addr)(); 90 | llvm::errs() << "result: " << res << "\n"; 91 | } 92 | #else 93 | 94 | std::string CustomTriple; 95 | // If we are supposed to override the target triple, do so now. 96 | if (!TargetTriple.empty()) 97 | CustomTriple = (Triple::normalize(TargetTriple)); 98 | 99 | Triple T(CustomTriple); 100 | if (T.getTriple().empty()) { 101 | T.setTriple(sys::getDefaultTargetTriple()); 102 | } 103 | /// 1. 初始化一个triple 104 | // llvm::Triple T; 105 | // T.setArch(llvm::Triple::ArchType::aarch64); 106 | // T.setOS(llvm::Triple::OSType::Darwin); 107 | // T.setEnvironment(llvm::Triple::GNU); 108 | // llvm::outs() << "\nthe triple: " << T.normalize() << "\n\n"; 109 | /// 2. 查找一个target 110 | std::string Err; 111 | const llvm::Target *TG = llvm::TargetRegistry::lookupTarget(T.normalize(), Err); 112 | if (!TG) { 113 | llvm::WithColor::error() << "target lookup failed with error: " << Err << "\n"; 114 | return 0; 115 | } 116 | 117 | /// 3. 创建target machine 118 | auto Machine = std::unique_ptr( 119 | TG->createTargetMachine(T.normalize(), "generic", "", {}, llvm::Reloc::Model::Static, {}, llvm::CodeGenOptLevel::None)); 120 | 121 | M->setTargetTriple(T.normalize()); 122 | M->setDataLayout(Machine->createDataLayout()); 123 | 124 | /// 4. 对比上面,此时输出会有 data layout信息 125 | llvm::outs() << "2>>> add data layout and triple, output ir\n"; 126 | M->print(llvm::outs(), nullptr); 127 | assert(!llvm::verifyModule(*M)); 128 | 129 | /// 4. 创建输出 130 | std::error_code EC; 131 | llvm::raw_fd_ostream OS(OutputFilename, EC, llvm::sys::fs::OpenFlags::OF_None); 132 | if (EC) 133 | { 134 | llvm::WithColor::error() 135 | << "Can not open file \n"; 136 | return {}; 137 | } 138 | 139 | /// 5. 通过target machine 来串联 输入(module)和输出(汇编文件) 140 | llvm::legacy::PassManager PM; 141 | if (Machine->addPassesToEmitFile(PM, OS, nullptr, 142 | CodeGenFileType::AssemblyFile)) { 143 | llvm::WithColor::error() 144 | << "No support for file type\n"; 145 | return -1; 146 | } 147 | 148 | /// 6. 执行 149 | PM.run(*M); 150 | 151 | #endif 152 | return 0; 153 | } 154 | -------------------------------------------------------------------------------- /parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "lexer.h" 3 | #include "ast.h" 4 | #include "sema.h" 5 | class Parser { 6 | private: 7 | Lexer &lexer; 8 | Sema &sema; 9 | std::vector> breakNodes; 10 | std::vector> continueNodes; 11 | std::vector> switchNodes; 12 | public: 13 | Parser(Lexer &lexer, Sema &sema) : lexer(lexer), sema(sema) { 14 | Advance(); 15 | } 16 | 17 | std::shared_ptr ParseProgram(); 18 | 19 | private: 20 | std::shared_ptr ParseFuncDecl(); 21 | std::shared_ptr ParseStmt(); 22 | std::shared_ptr ParseBlockStmt(); 23 | std::shared_ptr ParseDeclStmt(bool isGlobal = false); 24 | std::shared_ptr ParseDeclSpec(bool &isTypedef); 25 | std::shared_ptr ParseStructOrUnionSpec(); 26 | std::shared_ptr Declarator(std::shared_ptr baseType, bool isGlobal); 27 | std::shared_ptr DirectDeclarator(std::shared_ptr baseType, bool isGlobal); 28 | std::shared_ptr DirectDeclaratorSuffix(Token iden, std::shared_ptr baseType, bool isGlobal); 29 | std::shared_ptr DirectDeclaratorArraySuffix(std::shared_ptr baseType, bool isGlobal); 30 | std::shared_ptr DirectDeclaratorFuncSuffix(Token iden, std::shared_ptr baseType, bool isGlobal); 31 | bool ParseInitializer(std::vector> &arr, std::shared_ptr declType, std::vector &offsetList, bool hasLBrace); 32 | void ParseStringInitializer(std::vector> &arr, std::shared_ptr declType, std::vector &offsetList); 33 | 34 | std::shared_ptr ParseIfStmt(); 35 | std::shared_ptr ParseForStmt(); 36 | std::shared_ptr ParseWhileStmt(); 37 | std::shared_ptr ParseDoWhileStmt(); 38 | std::shared_ptr ParseBreakStmt(); 39 | std::shared_ptr ParseContinueStmt(); 40 | std::shared_ptr ParseReturnStmt(); 41 | std::shared_ptr ParseSwitchStmt(); 42 | std::shared_ptr ParseCaseStmt(); 43 | std::shared_ptr ParseDefaultStmt(); 44 | std::shared_ptr ParseExprStmt(); 45 | std::shared_ptr ParseExpr(); 46 | std::shared_ptr ParseAssignExpr(); 47 | std::shared_ptr ParseConditionalExpr(); 48 | 49 | std::shared_ptr ParseLogOrExpr(); 50 | std::shared_ptr ParseLogAndExpr(); 51 | std::shared_ptr ParseBitOrExpr(); 52 | std::shared_ptr ParseBitXorExpr(); 53 | std::shared_ptr ParseBitAndExpr(); 54 | std::shared_ptr ParseShiftExpr(); 55 | 56 | std::shared_ptr ParseEqualExpr(); 57 | std::shared_ptr ParseRelationalExpr(); 58 | std::shared_ptr ParseAddExpr(); 59 | std::shared_ptr ParseMultiExpr(); 60 | std::shared_ptr ParseCastExpr(); 61 | std::shared_ptr ParseUnaryExpr(); 62 | std::shared_ptr ParsePostFixExpr(); 63 | std::shared_ptr ParsePrimary(); 64 | 65 | std::shared_ptr ParseType(); 66 | 67 | bool IsAssignOperator(); 68 | bool IsUnaryOperator(); 69 | 70 | bool IsTypeName(Token tok); 71 | 72 | bool IsFuncDecl(); 73 | bool IsFuncTypeNode(std::shared_ptr node); 74 | 75 | bool IsStringArrayType(std::shared_ptr ty); 76 | 77 | /// 消费 token 的函数 78 | /// 检测当前 token是否是该类型,不会消费 79 | bool Expect(TokenType tokenType); 80 | /// 检测,并消费 81 | bool Consume(TokenType tokenType); 82 | /// 前进一个 token 83 | void Advance(); 84 | 85 | void ConsumeTypeQualify(); 86 | 87 | DiagEngine &GetDiagEngine() { 88 | return lexer.GetDiagEngine(); 89 | } 90 | 91 | Token tok; 92 | }; -------------------------------------------------------------------------------- /print_visitor.cc: -------------------------------------------------------------------------------- 1 | #include "print_visitor.h" 2 | 3 | PrintVisitor::PrintVisitor(std::shared_ptr program, llvm::raw_ostream *out) { 4 | this->out = out; 5 | VisitProgram(program.get()); 6 | } 7 | 8 | llvm::Value * PrintVisitor::VisitProgram(Program *p) { 9 | for (const auto &decl : p->externalDecls) { 10 | decl->Accept(this); 11 | } 12 | return nullptr; 13 | } 14 | 15 | llvm::Value * PrintVisitor::VisitBlockStmt(BlockStmt *p) { 16 | *out << "{"; 17 | for (const auto &stmt : p->nodeVec) { 18 | stmt->Accept(this); 19 | *out << ";"; 20 | } 21 | *out << "}"; 22 | return nullptr; 23 | } 24 | 25 | llvm::Value * PrintVisitor::VisitDeclStmt(DeclStmt *p) { 26 | int i = 0, size = p->nodeVec.size(); 27 | for (const auto &node : p->nodeVec) { 28 | node->Accept(this); 29 | if (i != size-1) { 30 | *out << ";"; 31 | } 32 | ++i; 33 | } 34 | return nullptr; 35 | } 36 | 37 | llvm::Value * PrintVisitor::VisitIfStmt(IfStmt *p) { 38 | *out << "if("; 39 | p->condNode->Accept(this); 40 | *out << ")"; 41 | p->thenNode->Accept(this); 42 | if (p->elseNode) { 43 | *out << "else"; 44 | p->elseNode->Accept(this); 45 | } 46 | return nullptr; 47 | } 48 | 49 | llvm::Value * PrintVisitor::VisitForStmt(ForStmt *p) { 50 | *out << "for("; 51 | if (p->initNode) { 52 | p->initNode->Accept(this); 53 | } 54 | *out << ";"; 55 | if (p->condNode) { 56 | p->condNode->Accept(this); 57 | } 58 | *out << ";"; 59 | if (p->incNode) { 60 | p->incNode->Accept(this); 61 | } 62 | *out << ")"; 63 | 64 | if (p->bodyNode) { 65 | p->bodyNode->Accept(this); 66 | } 67 | 68 | return nullptr; 69 | } 70 | 71 | llvm::Value * PrintVisitor::VisitContinueStmt(ContinueStmt *p) { 72 | *out << "continue"; 73 | return nullptr; 74 | } 75 | 76 | llvm::Value * PrintVisitor::VisitReturnStmt(ReturnStmt *p) { 77 | *out << "return "; 78 | if (p->expr) { 79 | p->expr->Accept(this); 80 | } 81 | 82 | return nullptr; 83 | } 84 | 85 | llvm::Value * PrintVisitor::VisitBreakStmt(BreakStmt *p) { 86 | *out << "break"; 87 | return nullptr; 88 | } 89 | 90 | llvm::Value * PrintVisitor::VisitSwitchStmt(SwitchStmt *p) { 91 | *out << "switch("; 92 | p->expr->Accept(this); 93 | *out << ")"; 94 | p->stmt->Accept(this); 95 | 96 | return nullptr; 97 | } 98 | 99 | llvm::Value * PrintVisitor::VisitCaseStmt(CaseStmt *p) { 100 | *out << "case "; 101 | p->expr->Accept(this); 102 | *out << ":"; 103 | p->stmt->Accept(this); 104 | 105 | return nullptr; 106 | } 107 | 108 | llvm::Value * PrintVisitor::VisitDefaultStmt(DefaultStmt *p) { 109 | *out << "default:"; 110 | p->stmt->Accept(this); 111 | 112 | return nullptr; 113 | } 114 | 115 | llvm::Value * PrintVisitor::VisitDoWhileStmt(DoWhileStmt *p) { 116 | *out << "do "; 117 | p->stmt->Accept(this); 118 | *out << "while ("; 119 | p->expr->Accept(this); 120 | *out << ");"; 121 | 122 | return nullptr; 123 | } 124 | 125 | llvm::Value * PrintVisitor::VisitVariableDecl(VariableDecl *decl) { 126 | decl->ty->Accept(this); 127 | llvm::StringRef text(decl->tok.ptr, decl->tok.len); 128 | *out << text; 129 | if (decl->initValues.size() > 0) { 130 | *out << "="; 131 | } 132 | int i = 0, size = decl->initValues.size(); 133 | for (const auto &initValue : decl->initValues) { 134 | initValue->value->Accept(this); 135 | if (i < size-1) { 136 | *out << ","; 137 | } 138 | ++i; 139 | } 140 | return nullptr; 141 | } 142 | 143 | llvm::Value * PrintVisitor::VisitFuncDecl(FuncDecl *decl) { 144 | decl->ty->Accept(this); 145 | if (decl->blockStmt) { 146 | decl->blockStmt->Accept(this); 147 | }else { 148 | *out << ";"; 149 | } 150 | return nullptr; 151 | } 152 | 153 | llvm::Value * PrintVisitor::VisitBinaryExpr(BinaryExpr *binaryExpr) { 154 | binaryExpr->left->Accept(this); 155 | 156 | switch (binaryExpr->op) 157 | { 158 | case BinaryOp::add: { 159 | *out << "+"; 160 | break; 161 | } 162 | case BinaryOp::sub:{ 163 | *out << "-"; 164 | break; 165 | } 166 | case BinaryOp::mul:{ 167 | *out << "*"; 168 | break; 169 | } 170 | case BinaryOp::div:{ 171 | *out << "/"; 172 | break; 173 | } 174 | case BinaryOp::equal:{ 175 | *out << "=="; 176 | break; 177 | } 178 | case BinaryOp::not_equal:{ 179 | *out << "!="; 180 | break; 181 | } 182 | case BinaryOp::less:{ 183 | *out << "<"; 184 | break; 185 | } 186 | case BinaryOp::less_equal:{ 187 | *out << "<="; 188 | break; 189 | } 190 | case BinaryOp::greater:{ 191 | *out << ">"; 192 | break; 193 | } 194 | case BinaryOp::greater_equal:{ 195 | *out << ">="; 196 | break; 197 | } 198 | case BinaryOp::mod:{ 199 | *out << "%"; 200 | break; 201 | } 202 | case BinaryOp::logical_or:{ 203 | *out << "||"; 204 | break; 205 | } 206 | case BinaryOp::logical_and:{ 207 | *out << "&&"; 208 | break; 209 | } 210 | case BinaryOp::bitwise_and:{ 211 | *out << "&"; 212 | break; 213 | } 214 | case BinaryOp::bitwise_or:{ 215 | *out << "|"; 216 | break; 217 | } 218 | case BinaryOp::bitwise_xor:{ 219 | *out << "^"; 220 | break; 221 | } 222 | case BinaryOp::left_shift:{ 223 | *out << "<<"; 224 | break; 225 | } 226 | case BinaryOp::right_shift:{ 227 | *out << ">>"; 228 | break; 229 | } 230 | case BinaryOp::comma: { 231 | *out << ","; 232 | break; 233 | } 234 | case BinaryOp::assign: { 235 | *out << "="; 236 | break; 237 | } 238 | case BinaryOp::add_assign: { 239 | *out << "+="; 240 | break; 241 | } 242 | case BinaryOp::sub_assign: { 243 | *out << "-="; 244 | break; 245 | } 246 | case BinaryOp::mul_assign: { 247 | *out << "*="; 248 | break; 249 | } 250 | case BinaryOp::div_assign: { 251 | *out << "/="; 252 | break; 253 | } 254 | case BinaryOp::mod_assign: { 255 | *out << "%="; 256 | break; 257 | } 258 | case BinaryOp::bitwise_and_assign: { 259 | *out << "&="; 260 | break; 261 | } 262 | case BinaryOp::bitwise_or_assign: { 263 | *out << "|="; 264 | break; 265 | } 266 | case BinaryOp::bitwise_xor_assign: { 267 | *out << "^="; 268 | break; 269 | } 270 | case BinaryOp::left_shift_assign: { 271 | *out << "<<="; 272 | break; 273 | } 274 | case BinaryOp::right_shift_assign: { 275 | *out << ">>="; 276 | break; 277 | } 278 | default: 279 | break; 280 | } 281 | 282 | binaryExpr->right->Accept(this); 283 | 284 | return nullptr; 285 | } 286 | 287 | llvm::Value * PrintVisitor::VisitNumberExpr(NumberExpr *expr) { 288 | 289 | if (expr->ty->IsIntegerType()) { 290 | *out << expr->value.v; 291 | }else { 292 | *out << expr->value.d; 293 | } 294 | 295 | return nullptr; 296 | } 297 | 298 | llvm::Value * PrintVisitor::VisitStringExpr(StringExpr *expr) { 299 | *out << llvm::StringRef(expr->tok.ptr, expr->tok.len); 300 | return nullptr; 301 | } 302 | 303 | llvm::Value * PrintVisitor::VisitVariableAccessExpr(VariableAccessExpr *expr) { 304 | *out << llvm::StringRef(expr->tok.ptr, expr->tok.len); 305 | return nullptr; 306 | } 307 | 308 | llvm::Value * PrintVisitor::VisitUnaryExpr(UnaryExpr *expr) { 309 | switch (expr->op) 310 | { 311 | case UnaryOp::positive: 312 | *out << "+"; 313 | break; 314 | case UnaryOp::negative: 315 | *out << "-"; 316 | break; 317 | case UnaryOp::deref: 318 | *out << "*"; 319 | break; 320 | case UnaryOp::addr: 321 | *out << "&"; 322 | break; 323 | case UnaryOp::logical_not: 324 | *out << "!"; 325 | break; 326 | case UnaryOp::bitwise_not: 327 | *out << "~"; 328 | break; 329 | case UnaryOp::inc: 330 | *out << "++"; 331 | break; 332 | case UnaryOp::dec: 333 | *out << "--"; 334 | break; 335 | default: 336 | break; 337 | } 338 | 339 | expr->node->Accept(this); 340 | 341 | return nullptr; 342 | } 343 | llvm::Value * PrintVisitor::VisitSizeOfExpr(SizeOfExpr *expr) { 344 | *out << "sizeof "; 345 | if (expr->type) { 346 | *out << "("; 347 | expr->type->Accept(this); 348 | *out << ")"; 349 | }else { 350 | expr->node->Accept(this); 351 | } 352 | 353 | return nullptr; 354 | } 355 | 356 | llvm::Value * PrintVisitor::VisitCastExpr(CastExpr *expr) { 357 | *out << "("; 358 | expr->targetType->Accept(this); 359 | *out << ")"; 360 | expr->node->Accept(this); 361 | 362 | return nullptr; 363 | } 364 | 365 | llvm::Value * PrintVisitor::VisitPostIncExpr(PostIncExpr *expr) { 366 | expr->left->Accept(this); 367 | *out << "++"; 368 | return nullptr; 369 | } 370 | llvm::Value * PrintVisitor::VisitPostDecExpr(PostDecExpr *expr) { 371 | expr->left->Accept(this); 372 | *out << "--"; 373 | return nullptr; 374 | } 375 | 376 | llvm::Value * PrintVisitor::VisitPostSubscript(PostSubscript *expr) { 377 | expr->left->Accept(this); 378 | *out<<"["; 379 | expr->node->Accept(this); 380 | *out<<"]"; 381 | return nullptr; 382 | } 383 | 384 | llvm::Value * PrintVisitor::VisitPostMemberDotExpr(PostMemberDotExpr *expr) { 385 | expr->left->Accept(this); 386 | *out<<"."; 387 | *out << expr->member.name; 388 | return nullptr; 389 | } 390 | 391 | llvm::Value * PrintVisitor::VisitPostMemberArrowExpr(PostMemberArrowExpr *expr) { 392 | expr->left->Accept(this); 393 | *out<<"->"; 394 | *out << expr->member.name; 395 | return nullptr; 396 | } 397 | 398 | llvm::Value * PrintVisitor::VisitPostFuncCall(PostFuncCall *expr) { 399 | expr->left->Accept(this); 400 | *out << "("; 401 | int i = 0, size = expr->args.size(); 402 | for (const auto &arg : expr->args) { 403 | arg->Accept(this); 404 | if (i < size - 1) { 405 | *out << ","; 406 | } 407 | } 408 | *out << ")"; 409 | return nullptr; 410 | } 411 | 412 | llvm::Value * PrintVisitor::VisitThreeExpr(ThreeExpr *expr) { 413 | expr->cond->Accept(this); 414 | *out<<"?"; 415 | expr->then->Accept(this); 416 | *out<<":"; 417 | expr->els->Accept(this); 418 | 419 | return nullptr; 420 | } 421 | 422 | llvm::Type * PrintVisitor::VisitPrimaryType(CPrimaryType *ty) { 423 | if (ty->GetKind() == CType::TY_Void) { 424 | *out << "void "; 425 | }else if (ty->GetKind() == CType::TY_Char) { 426 | *out << "char "; 427 | }else if (ty->GetKind() == CType::TY_UChar) { 428 | *out << "unsigned char "; 429 | }else if (ty->GetKind() == CType::TY_Short) { 430 | *out << "short "; 431 | }else if (ty->GetKind() == CType::TY_UShort) { 432 | *out << "unsigned short "; 433 | }else if (ty->GetKind() == CType::TY_Int) { 434 | *out << "int "; 435 | }else if (ty->GetKind() == CType::TY_UInt) { 436 | *out << "unsigned int "; 437 | }else if (ty->GetKind() == CType::TY_Long) { 438 | *out << "long "; 439 | }else if (ty->GetKind() == CType::TY_ULong) { 440 | *out << "unsigned long "; 441 | }else if (ty->GetKind() == CType::TY_LLong) { 442 | *out << "long long "; 443 | }else if (ty->GetKind() == CType::TY_ULLong) { 444 | *out << "unsigned long long "; 445 | }else if (ty->GetKind() == CType::TY_Float) { 446 | *out << "float "; 447 | }else if (ty->GetKind() == CType::TY_Double) { 448 | *out << "double "; 449 | }else if (ty->GetKind() == CType::TY_LDouble) { 450 | *out << "long double "; 451 | } 452 | 453 | return nullptr; 454 | } 455 | 456 | llvm::Type * PrintVisitor::VisitPointType(CPointType *ty) { 457 | /// int **p 458 | ty->GetBaseType()->Accept(this); 459 | *out << "*"; 460 | 461 | return nullptr; 462 | } 463 | 464 | /// a[3][4]; 465 | /// [3][4]int 466 | llvm::Type * PrintVisitor::VisitArrayType(CArrayType *ty) { 467 | *out<<"["<GetElementCount()<<"]"; 468 | ty->GetElementType()->Accept(this); 469 | return nullptr; 470 | } 471 | 472 | llvm::Type * PrintVisitor::VisitRecordType(CRecordType *ty) { 473 | TagKind tagKind = ty->GetTagKind(); 474 | if (tagKind == TagKind::kStruct) { 475 | *out << "struct "; 476 | }else { 477 | *out << "union "; 478 | } 479 | *out << ty->GetName() << "{"; 480 | for (const auto &m : ty->GetMembers()) { 481 | m.ty->Accept(this); 482 | *out << m.name << ";"; 483 | } 484 | *out << "} "; 485 | 486 | return nullptr; 487 | } 488 | 489 | llvm::Type * PrintVisitor::VisitFuncType(CFuncType *ty) { 490 | ty->GetRetType()->Accept(this); 491 | *out << ty->GetName() << "("; 492 | int i = 0, size = ty->GetParams().size(); 493 | for (const auto &p : ty->GetParams()) { 494 | p.type->Accept(this); 495 | *out << p.name; 496 | if (i < size - 1) { 497 | *out << ","; 498 | } 499 | } 500 | if (ty->IsVarArg()) { 501 | *out << ",..."; 502 | } 503 | *out << ")"; 504 | return nullptr; 505 | } -------------------------------------------------------------------------------- /print_visitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ast.h" 3 | #include "parser.h" 4 | class PrintVisitor : public Visitor, public TypeVisitor { 5 | private: 6 | llvm::raw_ostream *out; 7 | public: 8 | PrintVisitor(std::shared_ptr program, llvm::raw_ostream *out = &llvm::outs()); 9 | 10 | llvm::Value * VisitProgram(Program *p) override; 11 | llvm::Value * VisitBlockStmt(BlockStmt *p) override; 12 | llvm::Value * VisitDeclStmt(DeclStmt *p) override; 13 | llvm::Value * VisitIfStmt(IfStmt *p) override; 14 | llvm::Value * VisitForStmt(ForStmt *p) override; 15 | llvm::Value * VisitContinueStmt(ContinueStmt *p) override; 16 | llvm::Value * VisitReturnStmt(ReturnStmt *p) override; 17 | llvm::Value * VisitBreakStmt(BreakStmt *p) override; 18 | llvm::Value * VisitSwitchStmt(SwitchStmt *p) override; 19 | llvm::Value * VisitCaseStmt(CaseStmt *p) override; 20 | llvm::Value * VisitDefaultStmt(DefaultStmt *p) override; 21 | llvm::Value * VisitDoWhileStmt(DoWhileStmt *p) override; 22 | llvm::Value * VisitVariableDecl(VariableDecl *decl) override; 23 | llvm::Value * VisitFuncDecl(FuncDecl *decl) override; 24 | llvm::Value * VisitNumberExpr(NumberExpr *expr) override; 25 | llvm::Value * VisitStringExpr(StringExpr *expr) override; 26 | llvm::Value * VisitBinaryExpr(BinaryExpr *binaryExpr) override; 27 | llvm::Value * VisitUnaryExpr(UnaryExpr *expr) override; 28 | llvm::Value * VisitCastExpr(CastExpr *expr) override; 29 | llvm::Value * VisitSizeOfExpr(SizeOfExpr *expr) override; 30 | llvm::Value * VisitPostIncExpr(PostIncExpr *expr) override; 31 | llvm::Value * VisitPostDecExpr(PostDecExpr *expr) override; 32 | llvm::Value * VisitPostSubscript(PostSubscript *expr) override; 33 | llvm::Value * VisitPostMemberDotExpr(PostMemberDotExpr *expr) override; 34 | llvm::Value * VisitPostMemberArrowExpr(PostMemberArrowExpr *expr) override; 35 | llvm::Value * VisitPostFuncCall(PostFuncCall *expr) override; 36 | llvm::Value * VisitThreeExpr(ThreeExpr *expr) override; 37 | llvm::Value * VisitVariableAccessExpr(VariableAccessExpr *factorExpr) override; 38 | 39 | llvm::Type * VisitPrimaryType(CPrimaryType *ty) override; 40 | llvm::Type * VisitPointType(CPointType *ty) override; 41 | llvm::Type * VisitArrayType(CArrayType *ty) override; 42 | llvm::Type * VisitRecordType(CRecordType *ty) override; 43 | llvm::Type * VisitFuncType(CFuncType *ty) override; 44 | }; -------------------------------------------------------------------------------- /scope.cc: -------------------------------------------------------------------------------- 1 | #include "scope.h" 2 | 3 | Scope::Scope() { 4 | envs.push_back(std::make_shared()); 5 | } 6 | void Scope::EnterScope() { 7 | envs.push_back(std::make_shared()); 8 | } 9 | void Scope::ExitScope() { 10 | envs.pop_back(); 11 | } 12 | std::shared_ptr Scope::FindObjSymbol(llvm::StringRef name) { 13 | for (auto it = envs.rbegin(); it != envs.rend(); ++it) { 14 | auto &table = (*it)->objSymbolTable; 15 | if (table.count(name) > 0) { 16 | return table[name]; 17 | } 18 | } 19 | return nullptr; 20 | } 21 | std::shared_ptr Scope::FindObjSymbolInCurEnv(llvm::StringRef name) { 22 | auto &table = envs.back()->objSymbolTable; 23 | if (table.count(name) > 0) { 24 | return table[name]; 25 | } 26 | return nullptr; 27 | } 28 | void Scope::AddObjSymbol(std::shared_ptr ty, llvm::StringRef name) { 29 | auto symbol = std::make_shared(SymbolKind::kobj, ty, name); 30 | envs.back()->objSymbolTable.insert({name, symbol}); 31 | } 32 | 33 | void Scope::AddTypedefSymbol(std::shared_ptr ty, llvm::StringRef name) { 34 | auto symbol = std::make_shared(SymbolKind::ktypedef, ty, name); 35 | envs.back()->objSymbolTable.insert({name, symbol}); 36 | } 37 | 38 | std::shared_ptr Scope::FindTagSymbol(llvm::StringRef name) { 39 | for (auto it = envs.rbegin(); it != envs.rend(); ++it) { 40 | auto &table = (*it)->tagSymbolTable; 41 | if (table.count(name) > 0) { 42 | return table[name]; 43 | } 44 | } 45 | return nullptr; 46 | } 47 | 48 | std::shared_ptr Scope::FindTagSymbolInCurEnv(llvm::StringRef name) { 49 | auto &table = envs.back()->tagSymbolTable; 50 | if (table.count(name) > 0) { 51 | return table[name]; 52 | } 53 | return nullptr; 54 | } 55 | 56 | void Scope::AddTagSymbol(std::shared_ptr ty, llvm::StringRef name) { 57 | auto symbol = std::make_shared(SymbolKind::ktag, ty, name); 58 | envs.back()->tagSymbolTable.insert({name, symbol}); 59 | } -------------------------------------------------------------------------------- /scope.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "llvm/ADT/StringMap.h" 3 | #include "type.h" 4 | #include 5 | 6 | enum class SymbolKind { 7 | kobj, /// var, func 8 | ktypedef, // typedef 9 | ktag /// struct/union 10 | }; 11 | 12 | class Symbol { 13 | private: 14 | SymbolKind kind; 15 | std::shared_ptr ty; 16 | llvm::StringRef name; 17 | public: 18 | Symbol(SymbolKind kind, std::shared_ptr ty, llvm::StringRef name):kind(kind), ty(ty), name(name) {} 19 | std::shared_ptr GetTy() {return ty;} 20 | SymbolKind GetKind() {return kind;} 21 | }; 22 | 23 | 24 | class Env{ 25 | public: 26 | /// 符号信息 27 | llvm::StringMap> objSymbolTable; 28 | llvm::StringMap> tagSymbolTable; 29 | }; 30 | 31 | class Scope { 32 | private: 33 | std::vector> envs; 34 | public: 35 | Scope(); 36 | void EnterScope(); 37 | void ExitScope(); 38 | std::shared_ptr FindObjSymbol(llvm::StringRef name); 39 | std::shared_ptr FindObjSymbolInCurEnv(llvm::StringRef name); 40 | void AddObjSymbol(std::shared_ptr ty, llvm::StringRef name); 41 | void AddTypedefSymbol(std::shared_ptr ty, llvm::StringRef name); 42 | 43 | std::shared_ptr FindTagSymbol(llvm::StringRef name); 44 | std::shared_ptr FindTagSymbolInCurEnv(llvm::StringRef name); 45 | void AddTagSymbol(std::shared_ptr ty, llvm::StringRef name); 46 | }; -------------------------------------------------------------------------------- /script/apple_m.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## input 汇编 3 | input="$1" 4 | ## output 目标文件 5 | output="$2" 6 | ## 汇编 7 | as $input -o tmp.o 8 | ## 链接 9 | ld tmp.o -lSystem -L $(xcrun --show-sdk-path -sdk macosx)/usr/lib -o "$output" 10 | ## 删除临时文件 11 | rm -rf tmp.o -------------------------------------------------------------------------------- /script/test.sh: -------------------------------------------------------------------------------- 1 | #/bin/zsh 2 | 3 | cd build 4 | ninja 5 | cd .. 6 | ./bin/lexer_test 7 | ./bin/parser_test 8 | ./bin/codegen_test -------------------------------------------------------------------------------- /script/ubuntu20_x86.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## 需要先执行这个命令,安装gcc的环境 4 | # sudo apt install gcc-multilib 5 | 6 | ## input 汇编 7 | input="$1" 8 | ## output 目标文件 9 | output="$2" 10 | ## 汇编 11 | as $input -o tmp.o 12 | ## 链接 13 | # export LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:$LIBRARY_PATH 14 | # ld tmp.o /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/crtn.o /usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o /usr/lib/gcc/x86_64-linux-gnu/11/crtend.o -L "/usr/lib/gcc/x86_64-linux-gnu/11" "-L/usr/lib/x86_64-linux-gnu" -lm -lgcc_s -lc -lgcc -o $output 15 | gcc tmp.o -o $output 16 | ## 删除临时文件 17 | rm -rf tmp.o -------------------------------------------------------------------------------- /sema.cc: -------------------------------------------------------------------------------- 1 | #include "sema.h" 2 | #include "llvm/Support/raw_ostream.h" 3 | #include "llvm/Support/Casting.h" 4 | 5 | std::shared_ptr Sema::SemaVariableDeclNode(Token tok, std::shared_ptr ty, bool isGlobal) { 6 | // 1. 检测是否出现重定义 7 | llvm::StringRef text(tok.ptr, tok.len); 8 | std::shared_ptr symbol = scope.FindObjSymbolInCurEnv(text); 9 | if (symbol && (GetMode() == Mode::Normal)) { 10 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_redefined, text); 11 | } 12 | if (GetMode() == Mode::Normal) { 13 | /// 2. 添加到符号表 14 | scope.AddObjSymbol(ty, text); 15 | } 16 | 17 | /// 3. 返回结点 18 | auto decl = std::make_shared(); 19 | decl->tok = tok; 20 | decl->ty = ty; 21 | decl->isLValue = true; 22 | decl->isGlobal = isGlobal; 23 | return decl; 24 | } 25 | 26 | std::shared_ptr Sema::SemaVariableAccessNode(Token tok) { 27 | 28 | llvm::StringRef text(tok.ptr, tok.len); 29 | std::shared_ptr symbol = scope.FindObjSymbol(text); 30 | if (symbol == nullptr && (GetMode() == Mode::Normal)) { 31 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_undefined, text); 32 | } 33 | 34 | auto expr = std::make_shared(); 35 | expr->tok = tok; 36 | expr->ty = symbol->GetTy(); 37 | expr->isLValue = true; 38 | return expr; 39 | } 40 | 41 | std::shared_ptr Sema::SemaBinaryExprNode( std::shared_ptr left,std::shared_ptr right, BinaryOp op, Token tok) { 42 | auto binaryExpr = std::make_shared(); 43 | binaryExpr->tok = tok; 44 | binaryExpr->op = op; 45 | binaryExpr->left = left; 46 | binaryExpr->right = right; 47 | binaryExpr->ty = left->ty; 48 | 49 | CType::Kind leftKind = left->ty->GetKind(); 50 | CType::Kind rightKind = right->ty->GetKind(); 51 | 52 | switch (op) 53 | { 54 | case BinaryOp::add: { 55 | if (!left->ty->IsArithType() && leftKind != CType::TY_Point) { 56 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 57 | }else if (!right->ty->IsArithType() && rightKind != CType::TY_Point) { 58 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 59 | }else if (leftKind == CType::TY_Point && rightKind == CType::TY_Point) { 60 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 61 | }else if (leftKind == CType::TY_Point && !right->ty->IsIntegerType()) { 62 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 63 | }else if (rightKind == CType::TY_Point && !left->ty->IsIntegerType()) { 64 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 65 | }else if (rightKind == CType::TY_Point) { 66 | binaryExpr->ty = right->ty; 67 | auto t = binaryExpr->left; 68 | binaryExpr->left = binaryExpr->right; 69 | binaryExpr->right = t; 70 | } 71 | break; 72 | } 73 | case BinaryOp::sub: { 74 | if (!left->ty->IsArithType() && leftKind != CType::TY_Point) { 75 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 76 | }else if (!right->ty->IsArithType() && rightKind != CType::TY_Point) { 77 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 78 | }else if (leftKind == CType::TY_Point && leftKind == CType::TY_Point) { 79 | binaryExpr->ty = CType::LongType; 80 | }else if (leftKind == CType::TY_Point && !right->ty->IsIntegerType()) { 81 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 82 | }else if (rightKind == CType::TY_Point && !left->ty->IsIntegerType()) { 83 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 84 | }else if (rightKind == CType::TY_Point) { 85 | binaryExpr->ty = right->ty; 86 | auto t = binaryExpr->left; 87 | binaryExpr->left = binaryExpr->right; 88 | binaryExpr->right = t; 89 | } 90 | break; 91 | } 92 | case BinaryOp::add_assign: 93 | case BinaryOp::sub_assign: { 94 | if (!left->ty->IsArithType() && leftKind != CType::TY_Point) { 95 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 96 | }else if (!right->ty->IsArithType()) { 97 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 98 | }else if (leftKind == CType::TY_Point && !right->ty->IsIntegerType()) { 99 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 100 | } 101 | break; 102 | } 103 | case BinaryOp::mul: 104 | case BinaryOp::mul_assign: 105 | case BinaryOp::div: 106 | case BinaryOp::div_assign: { 107 | if (!left->ty->IsArithType() && !right->ty->IsArithType()) { 108 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 109 | } 110 | break; 111 | } 112 | case BinaryOp::mod: 113 | case BinaryOp::mod_assign: 114 | case BinaryOp::bitwise_or: 115 | case BinaryOp::bitwise_or_assign: 116 | case BinaryOp::bitwise_and: 117 | case BinaryOp::bitwise_and_assign: 118 | case BinaryOp::bitwise_xor: 119 | case BinaryOp::bitwise_xor_assign: 120 | case BinaryOp::left_shift: 121 | case BinaryOp::left_shift_assign: 122 | case BinaryOp::right_shift: 123 | case BinaryOp::right_shift_assign:{ 124 | if (!left->ty->IsIntegerType() && !right->ty->IsIntegerType()) { 125 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 126 | } 127 | break; 128 | } 129 | case BinaryOp::equal: 130 | case BinaryOp::not_equal: 131 | case BinaryOp::less: 132 | case BinaryOp::less_equal: 133 | case BinaryOp::greater: 134 | case BinaryOp::greater_equal: 135 | case BinaryOp::logical_or: 136 | case BinaryOp::logical_and:{ 137 | if (!left->ty->IsArithType() && leftKind != CType::TY_Point) { 138 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 139 | }else if (!right->ty->IsArithType() && rightKind != CType::TY_Point) { 140 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_binary_expr_type); 141 | } 142 | break; 143 | } 144 | default: 145 | break; 146 | } 147 | 148 | return binaryExpr; 149 | } 150 | 151 | std::shared_ptr Sema::SemaUnaryExprNode( std::shared_ptr unary, UnaryOp op, Token tok) { 152 | auto node = std::make_shared(); 153 | node->op = op; 154 | node->node = unary; 155 | 156 | switch (op) 157 | { 158 | case UnaryOp::positive: 159 | case UnaryOp::negative: 160 | case UnaryOp::logical_not: 161 | case UnaryOp::bitwise_not: 162 | { 163 | if (unary->ty->GetKind() != CType::TY_Int && (GetMode() == Mode::Normal)) { 164 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_expected_ype, "int type"); 165 | } 166 | node->ty = unary->ty; 167 | break; 168 | } 169 | case UnaryOp::addr: { 170 | /// &a; 171 | // if (!unary->isLValue) { 172 | // diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_expected_lvalue); 173 | // } 174 | node->ty = std::make_shared(unary->ty); 175 | break; 176 | } 177 | case UnaryOp::deref: { 178 | /// *a; 179 | /// 语义判断 must be pointer 180 | if (unary->ty->GetKind() != CType::TY_Point && (GetMode() == Mode::Normal)) { 181 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_expected_ype, "pointer type"); 182 | } 183 | // if (!unary->isLValue) { 184 | // diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_expected_lvalue); 185 | // } 186 | CPointType *pty = llvm::dyn_cast(unary->ty.get()); 187 | node->ty = pty->GetBaseType(); 188 | node->isLValue = true; 189 | break; 190 | } 191 | case UnaryOp::dec: 192 | case UnaryOp::inc: { 193 | if (!unary->isLValue) { 194 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_expected_lvalue); 195 | } 196 | node->ty = unary->ty; 197 | break; 198 | } 199 | default: 200 | break; 201 | } 202 | 203 | return node; 204 | } 205 | 206 | std::shared_ptr Sema::SemaCastExprNode( std::shared_ptr targetType, std::shared_ptr node, Token tok) { 207 | auto ret = std::make_shared(); 208 | ret->ty = targetType; 209 | ret->targetType = targetType; 210 | ret->node = node; 211 | ret->tok = tok; 212 | return ret; 213 | } 214 | 215 | std::shared_ptr Sema::SemaThreeExprNode( std::shared_ptr cond,std::shared_ptr then, std::shared_ptr els, Token tok) { 216 | auto node = std::make_shared(); 217 | node->cond = cond; 218 | node->then = then; 219 | node->els = els; 220 | if (then->ty->GetKind() != els->ty->GetKind() && (GetMode() == Mode::Normal)) { 221 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_same_type); 222 | } 223 | node->ty = then->ty; 224 | return node; 225 | } 226 | 227 | // sizeof a; 228 | std::shared_ptr Sema::SemaSizeofExprNode( std::shared_ptr unary,std::shared_ptr ty) { 229 | auto node = std::make_shared(); 230 | node->type = ty; 231 | node->node = unary; 232 | node->ty = CType::IntType; 233 | return node; 234 | } 235 | 236 | std::shared_ptr Sema::SemaPostIncExprNode(std::shared_ptr left, Token tok) { 237 | if (!left->isLValue && (GetMode() == Mode::Normal)) { 238 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_expected_lvalue); 239 | } 240 | auto node = std::make_shared(); 241 | node->left = left; 242 | node->ty = left->ty; 243 | return node; 244 | } 245 | 246 | /// a-- 247 | std::shared_ptr Sema::SemaPostDecExprNode( std::shared_ptr left, Token tok) { 248 | if (!left->isLValue && (GetMode() == Mode::Normal)) { 249 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_expected_lvalue); 250 | } 251 | auto node = std::make_shared(); 252 | node->left = left; 253 | node->ty = left->ty; 254 | return node; 255 | } 256 | /// a[1]; -> *(a + offset(1 * elementSize)); 257 | std::shared_ptr Sema::SemaPostSubscriptNode(std::shared_ptr left, std::shared_ptr node, Token tok) { 258 | if (left->ty->GetKind() != CType::TY_Array && left->ty->GetKind() != CType::TY_Point && (GetMode() == Mode::Normal)) { 259 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_expected_ype, "array or point"); 260 | } 261 | auto postSubScriptNode = std::make_shared(); 262 | postSubScriptNode->left = left; 263 | postSubScriptNode->node = node; 264 | if (left->ty->GetKind() == CType::TY_Array) { 265 | CArrayType *arrType = llvm::dyn_cast(left->ty.get()); 266 | postSubScriptNode->ty = arrType->GetElementType(); 267 | }else if (left->ty->GetKind() == CType::TY_Point) { 268 | CPointType *pointType = llvm::dyn_cast(left->ty.get()); 269 | postSubScriptNode->ty = pointType->GetBaseType(); 270 | } 271 | return postSubScriptNode; 272 | } 273 | 274 | std::shared_ptr Sema::SemaPostMemberDotNode(std::shared_ptr left, Token iden, Token dotTok) { 275 | if (left->ty->GetKind() != CType::TY_Record && (GetMode() == Mode::Normal)) { 276 | diagEngine.Report(llvm::SMLoc::getFromPointer(dotTok.ptr), diag::err_expected_ype, "struct or union type"); 277 | } 278 | 279 | CRecordType *recordType = llvm::dyn_cast(left->ty.get()); 280 | const auto &members = recordType->GetMembers(); 281 | 282 | bool found = false; 283 | Member curMember; 284 | for (const auto &member : members) { 285 | if (member.name == llvm::StringRef(iden.ptr, iden.len)) { 286 | found = true; 287 | curMember = member; 288 | break; 289 | } 290 | } 291 | if (!found) { 292 | diagEngine.Report(llvm::SMLoc::getFromPointer(iden.ptr), diag::err_miss, "struct or union miss field"); 293 | } 294 | 295 | 296 | auto node = std::make_shared(); 297 | node->tok = dotTok; 298 | node->ty = curMember.ty; 299 | node->left = left; 300 | node->member = curMember; 301 | return node; 302 | } 303 | 304 | std::shared_ptr Sema::SemaPostMemberArrowNode(std::shared_ptr left, Token iden, Token arrowTok) { 305 | if (left->ty->GetKind() != CType::TY_Point) { 306 | diagEngine.Report(llvm::SMLoc::getFromPointer(arrowTok.ptr), diag::err_expected_ype, "pointer type"); 307 | } 308 | 309 | CPointType *pRecordType = llvm::dyn_cast(left->ty.get()); 310 | if (pRecordType->GetBaseType()->GetKind() != CType::TY_Record) { 311 | diagEngine.Report(llvm::SMLoc::getFromPointer(arrowTok.ptr), diag::err_expected_ype, "pointer to struct or union type"); 312 | } 313 | 314 | CRecordType *recordType = llvm::dyn_cast(pRecordType->GetBaseType().get()); 315 | const auto &members = recordType->GetMembers(); 316 | 317 | bool found = false; 318 | Member curMember; 319 | for (const auto &member : members) { 320 | if (member.name == llvm::StringRef(iden.ptr, iden.len)) { 321 | found = true; 322 | curMember = member; 323 | break; 324 | } 325 | } 326 | if (!found) { 327 | diagEngine.Report(llvm::SMLoc::getFromPointer(iden.ptr), diag::err_miss, "struct or union miss field"); 328 | } 329 | 330 | 331 | auto node = std::make_shared(); 332 | node->tok = arrowTok; 333 | node->ty = curMember.ty; 334 | node->left = left; 335 | node->member = curMember; 336 | return node; 337 | } 338 | 339 | std::shared_ptr Sema::SemaNumberExprNode(Token tok,int val,std::shared_ptr ty) { 340 | auto expr = std::make_shared(); 341 | expr->tok = tok; 342 | expr->ty = ty; 343 | expr->value.v = val; 344 | return expr; 345 | } 346 | 347 | std::shared_ptr Sema::SemaNumberExprNode(Token tok, std::shared_ptr ty) { 348 | auto expr = std::make_shared(); 349 | expr->tok = tok; 350 | expr->ty = ty; 351 | if (ty->IsIntegerType()) { 352 | expr->value.v = tok.value.v; 353 | }else { 354 | expr->value.d = tok.value.d; 355 | } 356 | return expr; 357 | } 358 | 359 | std::shared_ptr Sema::SemaStringExprNode(Token tok, std::string val, std::shared_ptr ty) { 360 | auto expr = std::make_shared(); 361 | expr->tok = tok; 362 | expr->ty = ty; 363 | expr->value = val; 364 | return expr; 365 | } 366 | 367 | std::shared_ptr Sema::SemaDeclInitValue(std::shared_ptr declType, std::shared_ptr value, std::vector &offsetList, Token tok) 368 | { 369 | // if (declType->GetKind() != value->ty->GetKind() && (GetMode() == Mode::Normal)) { 370 | // diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_miss, "same type"); 371 | // } 372 | auto initValue = std::make_shared(); 373 | initValue->declType = declType; 374 | initValue->value = value; 375 | initValue->offsetList = offsetList; 376 | return initValue; 377 | } 378 | 379 | std::shared_ptr Sema::SemaIfStmtNode(std::shared_ptr condNode, std::shared_ptr thenNode, std::shared_ptr elseNode) { 380 | auto node = std::make_shared(); 381 | node->condNode = condNode; 382 | node->thenNode = thenNode; 383 | node->elseNode = elseNode; 384 | return node; 385 | } 386 | 387 | std::shared_ptr Sema::SemaTagAccess(Token tok) { 388 | llvm::StringRef text(tok.ptr, tok.len); 389 | std::shared_ptr symbol = scope.FindTagSymbol(text); 390 | if (symbol) { 391 | return symbol->GetTy();; 392 | } 393 | return nullptr; 394 | } 395 | 396 | std::shared_ptr Sema::SemaTagDecl(Token tok, const std::vector &members, TagKind tagKind) { 397 | // 1. 检测是否出现重定义 398 | llvm::StringRef text(tok.ptr, tok.len); 399 | std::shared_ptr symbol = scope.FindTagSymbolInCurEnv(text); 400 | if (symbol) { 401 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_redefined, text); 402 | } 403 | auto recordTy = std::make_shared(text, members, tagKind); 404 | if (GetMode() == Mode::Normal) { 405 | /// 2. 添加到符号表 406 | scope.AddTagSymbol(recordTy, text); 407 | } 408 | return recordTy; 409 | } 410 | 411 | std::shared_ptr Sema::SemaTagDecl(Token tok, std::shared_ptr type) { 412 | llvm::StringRef text(tok.ptr, tok.len); 413 | std::shared_ptr symbol = scope.FindTagSymbolInCurEnv(text); 414 | if (symbol) { 415 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_redefined, text); 416 | } 417 | if (GetMode() == Mode::Normal) { 418 | /// 2. 添加到符号表 419 | scope.AddTagSymbol(type, text); 420 | } 421 | return type; 422 | } 423 | 424 | std::shared_ptr Sema::SemaAnonyTagDecl(const std::vector &members, TagKind tagKind) { 425 | llvm::StringRef text = CType::GenAnonyRecordName(tagKind); 426 | auto recordTy = std::make_shared(text, members, tagKind); 427 | if (GetMode() == Mode::Normal) { 428 | /// 2. 添加到符号表 429 | scope.AddTagSymbol(recordTy, text); 430 | } 431 | return recordTy; 432 | } 433 | 434 | std::shared_ptr Sema::SemaFuncDecl(Token tok, std::shared_ptr type, std::shared_ptr blockStmt) { 435 | CFuncType *funTy = llvm::dyn_cast(type.get()); 436 | funTy->hasBody = (blockStmt) ? true : false; 437 | 438 | // 1. 检测是否出现重定义 439 | llvm::StringRef text(tok.ptr, tok.len); 440 | std::shared_ptr symbol = scope.FindObjSymbolInCurEnv(text); 441 | if (symbol) { 442 | auto symTy = symbol->GetTy(); 443 | if (symTy->GetKind() != CType::TY_Func && (GetMode() == Mode::Normal)) { 444 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_redefined, text); 445 | } 446 | CFuncType *symbolFunTy = llvm::dyn_cast(symTy.get()); 447 | if (symbolFunTy->hasBody && funTy->hasBody && (GetMode() == Mode::Normal)) { 448 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_redefined, text); 449 | } 450 | } 451 | 452 | if ((symbol == nullptr || funTy->hasBody) && (GetMode() == Mode::Normal)) { 453 | /// 2. 添加到符号表 454 | scope.AddObjSymbol(type, text); 455 | } 456 | 457 | auto funcDecl = std::make_shared(); 458 | funcDecl->ty = type; 459 | funcDecl->blockStmt = blockStmt; 460 | funcDecl->tok = tok; 461 | return funcDecl; 462 | } 463 | 464 | std::shared_ptr Sema::SemaFuncCall(std::shared_ptr left, const std::vector> &args) { 465 | Token iden = left->tok; 466 | CFuncType *cFuncTyPtr = nullptr; 467 | std::shared_ptr funcTy = nullptr; 468 | if (left->ty->GetKind() == CType::TY_Point) { 469 | CPointType *pty = llvm::dyn_cast(left->ty.get()); 470 | if (pty->GetBaseType()->GetKind() == CType::TY_Func) { 471 | cFuncTyPtr = llvm::dyn_cast(pty->GetBaseType().get()); 472 | funcTy = pty->GetBaseType(); 473 | }else { 474 | if (GetMode() == Mode::Normal) { 475 | diagEngine.Report(llvm::SMLoc::getFromPointer(iden.ptr), diag::err_expected, "functype"); 476 | } 477 | } 478 | } 479 | else if (left->ty->GetKind() != CType::TY_Func && (GetMode() == Mode::Normal)) { 480 | diagEngine.Report(llvm::SMLoc::getFromPointer(iden.ptr), diag::err_expected, "functype"); 481 | } 482 | 483 | if (!cFuncTyPtr) { 484 | cFuncTyPtr = llvm::dyn_cast(left->ty.get()); 485 | } 486 | 487 | if ((cFuncTyPtr->GetParams().size() != args.size()) && !cFuncTyPtr->IsVarArg() && (GetMode() == Mode::Normal)) { 488 | diagEngine.Report(llvm::SMLoc::getFromPointer(iden.ptr), diag::err_miss, "arg count not match"); 489 | } 490 | 491 | auto funcCall = std::make_shared(); 492 | funcCall->ty = cFuncTyPtr->GetRetType(); 493 | if (funcTy) { 494 | left->ty = funcTy; 495 | } 496 | funcCall->left = left; 497 | funcCall->args = args; 498 | funcCall->tok = left->tok; 499 | return funcCall; 500 | } 501 | 502 | void Sema::SemaTypedefDecl(std::shared_ptr type, Token tok) { 503 | llvm::StringRef name(tok.ptr, tok.len); 504 | std::shared_ptr symbol = scope.FindObjSymbolInCurEnv(name); 505 | if (symbol && (GetMode() == Mode::Normal)) { 506 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_redefined, name); 507 | } 508 | if (GetMode() == Mode::Normal) { 509 | /// 2. 添加到符号表 510 | scope.AddTypedefSymbol(type, name); 511 | } 512 | } 513 | 514 | std::shared_ptr Sema::SemaTypedefAccess(Token tok) { 515 | llvm::StringRef name(tok.ptr, tok.len); 516 | std::shared_ptr symbol = scope.FindObjSymbol(name); 517 | if (symbol == nullptr && (GetMode() == Mode::Normal)) { 518 | diagEngine.Report(llvm::SMLoc::getFromPointer(tok.ptr), diag::err_undefined, name); 519 | } 520 | if (symbol && symbol->GetKind() == SymbolKind::ktypedef) { 521 | return symbol->GetTy(); 522 | } 523 | return nullptr; 524 | } 525 | 526 | void Sema::EnterScope() { 527 | scope.EnterScope(); 528 | } 529 | 530 | void Sema::ExitScope() { 531 | scope.ExitScope(); 532 | } 533 | 534 | void Sema::SetMode(Mode mode) { 535 | modeStack.push(mode); 536 | } 537 | 538 | void Sema::UnSetMode() { 539 | modeStack.pop(); 540 | } 541 | 542 | Sema::Mode Sema::GetMode() { 543 | return modeStack.top(); 544 | } 545 | -------------------------------------------------------------------------------- /sema.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "scope.h" 3 | #include "ast.h" 4 | #include "diag_engine.h" 5 | #include 6 | class Sema { 7 | public: 8 | enum class Mode { 9 | Normal, 10 | Skip 11 | }; 12 | private: 13 | DiagEngine &diagEngine; 14 | public: 15 | Sema(DiagEngine &diagEngine):diagEngine(diagEngine) { 16 | modeStack.push(Mode::Normal); 17 | } 18 | std::shared_ptr SemaVariableDeclNode(Token tok, std::shared_ptr ty, bool isGlobal); 19 | std::shared_ptr SemaVariableAccessNode(Token tok); 20 | std::shared_ptr SemaNumberExprNode(Token tok, int val, std::shared_ptr ty); 21 | std::shared_ptr SemaNumberExprNode(Token tok, std::shared_ptr ty); 22 | std::shared_ptr SemaStringExprNode(Token tok, std::string val, std::shared_ptr ty); 23 | std::shared_ptr SemaBinaryExprNode( std::shared_ptr left,std::shared_ptr right, BinaryOp op, Token tok); 24 | 25 | std::shared_ptr SemaCastExprNode( std::shared_ptr targetType, std::shared_ptr node, Token tok); 26 | std::shared_ptr SemaUnaryExprNode( std::shared_ptr unary, UnaryOp op, Token tok); 27 | std::shared_ptr SemaThreeExprNode( std::shared_ptr cond,std::shared_ptr then, std::shared_ptr els, Token tok); 28 | std::shared_ptr SemaSizeofExprNode( std::shared_ptr unary,std::shared_ptr ty); 29 | std::shared_ptr SemaPostIncExprNode( std::shared_ptr left, Token tok); 30 | std::shared_ptr SemaPostDecExprNode( std::shared_ptr left, Token tok); 31 | std::shared_ptr SemaPostSubscriptNode(std::shared_ptr left, std::shared_ptr node, Token tok); 32 | 33 | std::shared_ptr SemaPostMemberDotNode(std::shared_ptr left, Token iden, Token dotTok); 34 | std::shared_ptr SemaPostMemberArrowNode(std::shared_ptr left, Token iden, Token arrowTok); 35 | 36 | std::shared_ptr SemaDeclInitValue(std::shared_ptr declType, std::shared_ptr value, std::vector &offsetList, Token tok); 37 | std::shared_ptr SemaIfStmtNode(std::shared_ptr condNode, std::shared_ptr thenNode, std::shared_ptr elseNode); 38 | 39 | std::shared_ptr SemaTagAccess(Token tok); 40 | std::shared_ptr SemaTagDecl(Token tok, const std::vector &members, TagKind tagKind); 41 | std::shared_ptr SemaTagDecl(Token tok, std::shared_ptr type); 42 | std::shared_ptr SemaAnonyTagDecl(const std::vector &members, TagKind tagKind); 43 | 44 | std::shared_ptr SemaFuncDecl(Token tok, std::shared_ptr type, std::shared_ptr blockStmt); 45 | std::shared_ptr SemaFuncCall(std::shared_ptr left, const std::vector> &args); 46 | 47 | void SemaTypedefDecl(std::shared_ptr type, Token tok); 48 | std::shared_ptr SemaTypedefAccess(Token tok); 49 | 50 | void EnterScope(); 51 | void ExitScope(); 52 | void SetMode(Mode mode); 53 | void UnSetMode(); 54 | private: 55 | Scope scope; 56 | std::stack modeStack; 57 | 58 | Mode GetMode(); 59 | }; -------------------------------------------------------------------------------- /studybackend/day01.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 42; 3 | } 4 | -------------------------------------------------------------------------------- /studybackend/day01.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iiicp/subc-llvm/905b51f18bfb0f9da0ad3c174a73003a30dadb1c/studybackend/day01.s -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | FetchContent_Declare( 3 | googletest 4 | URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip 5 | ) 6 | # For Windows: Prevent overriding the parent project's compiler/linker settings 7 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 8 | FetchContent_MakeAvailable(googletest) 9 | 10 | add_subdirectory(lexer) 11 | add_subdirectory(parser) 12 | add_subdirectory(codegen) -------------------------------------------------------------------------------- /test/codegen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | enable_testing() 2 | 3 | add_executable( 4 | codegen_test 5 | codegen_test.cc 6 | 7 | ../../lexer.cc 8 | ../../type.cc 9 | ../../diag_engine.cc 10 | ../../parser.cc 11 | ../../sema.cc 12 | ../../scope.cc 13 | ../../codegen.cc 14 | ../../eval_constant.cc 15 | ) 16 | 17 | llvm_map_components_to_libnames(llvm_all Support Core ExecutionEngine MC MCJIT OrcJit native TargetParser CodeGen) 18 | 19 | #message(STATUS "iiicp: ${llvm_all}") 20 | 21 | target_link_libraries( 22 | codegen_test 23 | GTest::gtest_main 24 | ${llvm_all} 25 | ) 26 | 27 | include(GoogleTest) 28 | gtest_discover_tests(codegen_test) -------------------------------------------------------------------------------- /test/lexer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | enable_testing() 2 | 3 | add_executable( 4 | lexer_test 5 | lexer_test.cc 6 | 7 | ../../lexer.cc 8 | ../../type.cc 9 | ../../diag_engine.cc 10 | ) 11 | 12 | llvm_map_components_to_libnames(llvm_all Support Core) 13 | 14 | #message(STATUS "iiicp: ${llvm_all}") 15 | 16 | target_link_libraries( 17 | lexer_test 18 | GTest::gtest_main 19 | ${llvm_all} 20 | ) 21 | 22 | include(GoogleTest) 23 | gtest_discover_tests(lexer_test) -------------------------------------------------------------------------------- /test/lexer/lexer_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lexer.h" 3 | #include 4 | 5 | bool TestLexerWithContent(llvm::StringRef content, std::function()> callback) { 6 | llvm::ErrorOr> buf = llvm::MemoryBuffer::getMemBuffer(content, "stdin"); 7 | if (!buf) { 8 | llvm::errs() << "open file failed!!!\n"; 9 | return false; 10 | } 11 | llvm::SourceMgr mgr; 12 | DiagEngine diagEngine(mgr); 13 | mgr.AddNewSourceBuffer(std::move(*buf), llvm::SMLoc()); 14 | Lexer lexer(mgr, diagEngine); 15 | 16 | std::vector expectedVec = callback(), curVec; 17 | 18 | Token tok; 19 | while (true) { 20 | lexer.NextToken(tok); 21 | if (tok.tokenType == TokenType::eof) 22 | break; 23 | curVec.push_back(tok); 24 | } 25 | 26 | EXPECT_EQ(expectedVec.size(), curVec.size()); 27 | for (int i = 0; i < expectedVec.size(); i++) { 28 | const auto &expected_tok = expectedVec[i]; 29 | const auto &cur_tok = curVec[i]; 30 | 31 | EXPECT_EQ(static_cast(expected_tok.tokenType), static_cast(cur_tok.tokenType)); 32 | EXPECT_EQ(expected_tok.row, cur_tok.row); 33 | EXPECT_EQ(expected_tok.col, cur_tok.col); 34 | } 35 | return true; 36 | } 37 | 38 | 39 | 40 | TEST(LexerTest, identifier) { 41 | 42 | bool res = TestLexerWithContent("aaaa aA_ aA0_", []()->std::vector { 43 | std::vector expectedVec; 44 | expectedVec.push_back(Token{TokenType::identifier, 1, 1}); 45 | expectedVec.push_back(Token{TokenType::identifier, 1, 6}); 46 | expectedVec.push_back(Token{TokenType::identifier, 1, 10}); 47 | return expectedVec; 48 | }); 49 | ASSERT_EQ(res, true); 50 | } 51 | 52 | TEST(LexerTest, keyword) { 53 | bool res = TestLexerWithContent(" int if else for break continue sizeof", []()->std::vector { 54 | std::vector expectedVec; 55 | expectedVec.push_back(Token{TokenType::kw_int, 1, 3}); 56 | expectedVec.push_back(Token{TokenType::kw_if, 1, 7}); 57 | expectedVec.push_back(Token{TokenType::kw_else, 1, 10}); 58 | expectedVec.push_back(Token{TokenType::kw_for, 1, 15}); 59 | expectedVec.push_back(Token{TokenType::kw_break, 1, 19}); 60 | expectedVec.push_back(Token{TokenType::kw_continue, 1, 25}); 61 | expectedVec.push_back(Token{TokenType::kw_sizeof, 1, 34}); 62 | return expectedVec; 63 | }); 64 | ASSERT_EQ(res, true); 65 | } 66 | 67 | TEST(LexerTest, number) { 68 | bool res = TestLexerWithContent(" 0123 1234 1234222 \n0" , []()->std::vector { 69 | std::vector expectedVec; 70 | expectedVec.push_back(Token{TokenType::number, 1, 2}); 71 | expectedVec.push_back(Token{TokenType::number, 1, 7}); 72 | expectedVec.push_back(Token{TokenType::number, 1, 12}); 73 | expectedVec.push_back(Token{TokenType::number, 2, 1}); 74 | return expectedVec; 75 | }); 76 | ASSERT_EQ(res, true); 77 | } 78 | 79 | TEST(LexerTest, punctuation) { 80 | bool res = TestLexerWithContent("+-*/%();,={}==!=< <=> >= || | & && >><<^", []()->std::vector { 81 | std::vector expectedVec; 82 | expectedVec.push_back(Token{TokenType::plus, 1, 1}); 83 | expectedVec.push_back(Token{TokenType::minus, 1, 2}); 84 | expectedVec.push_back(Token{TokenType::star, 1, 3}); 85 | expectedVec.push_back(Token{TokenType::slash, 1, 4}); 86 | expectedVec.push_back(Token{TokenType::percent, 1, 5}); 87 | expectedVec.push_back(Token{TokenType::l_parent, 1, 6}); 88 | expectedVec.push_back(Token{TokenType::r_parent, 1, 7}); 89 | expectedVec.push_back(Token{TokenType::semi, 1, 8}); 90 | expectedVec.push_back(Token{TokenType::comma, 1, 9}); 91 | expectedVec.push_back(Token{TokenType::equal, 1, 10}); 92 | expectedVec.push_back(Token{TokenType::l_brace, 1, 11}); 93 | expectedVec.push_back(Token{TokenType::r_brace, 1, 12}); 94 | expectedVec.push_back(Token{TokenType::equal_equal, 1, 13}); 95 | expectedVec.push_back(Token{TokenType::not_equal, 1, 15}); 96 | expectedVec.push_back(Token{TokenType::less, 1, 17}); 97 | expectedVec.push_back(Token{TokenType::less_equal, 1, 19}); 98 | expectedVec.push_back(Token{TokenType::greater, 1, 21}); 99 | expectedVec.push_back(Token{TokenType::greater_equal, 1, 23}); 100 | expectedVec.push_back(Token{TokenType::pipepipe, 1, 26}); 101 | expectedVec.push_back(Token{TokenType::pipe, 1, 29}); 102 | expectedVec.push_back(Token{TokenType::amp, 1, 31}); 103 | expectedVec.push_back(Token{TokenType::ampamp, 1,33}); 104 | expectedVec.push_back(Token{TokenType::greater_greater, 1, 36}); 105 | expectedVec.push_back(Token{TokenType::less_less, 1, 38}); 106 | expectedVec.push_back(Token{TokenType::caret, 1, 40}); 107 | return expectedVec; 108 | }); 109 | ASSERT_EQ(res, true); 110 | } 111 | 112 | TEST(LexerTest, unary) { 113 | bool res = TestLexerWithContent("+-*&++--!~+=-=*=/=%=<<=>>=&=^=|=?:", []()->std::vector { 114 | std::vector expectedVec; 115 | expectedVec.push_back(Token{TokenType::plus, 1, 1}); 116 | expectedVec.push_back(Token{TokenType::minus, 1, 2}); 117 | expectedVec.push_back(Token{TokenType::star, 1, 3}); 118 | expectedVec.push_back(Token{TokenType::amp, 1, 4}); 119 | expectedVec.push_back(Token{TokenType::plus_plus, 1, 5}); 120 | expectedVec.push_back(Token{TokenType::minus_minus, 1, 7}); 121 | expectedVec.push_back(Token{TokenType::exclaim, 1, 9}); 122 | expectedVec.push_back(Token{TokenType::tilde, 1, 10}); 123 | 124 | expectedVec.push_back(Token{TokenType::plus_equal, 1, 11}); 125 | expectedVec.push_back(Token{TokenType::minus_equal, 1, 13}); 126 | expectedVec.push_back(Token{TokenType::star_equal, 1, 15}); 127 | expectedVec.push_back(Token{TokenType::slash_equal, 1, 17}); 128 | expectedVec.push_back(Token{TokenType::percent_equal, 1, 19}); 129 | expectedVec.push_back(Token{TokenType::less_less_equal, 1, 21}); 130 | expectedVec.push_back(Token{TokenType::greater_greater_equal, 1, 24}); 131 | expectedVec.push_back(Token{TokenType::amp_equal, 1, 27}); 132 | expectedVec.push_back(Token{TokenType::caret_equal, 1, 29}); 133 | expectedVec.push_back(Token{TokenType::pipe_equal, 1, 31}); 134 | expectedVec.push_back(Token{TokenType::question, 1, 33}); 135 | expectedVec.push_back(Token{TokenType::colon, 1, 34}); 136 | return expectedVec; 137 | }); 138 | } 139 | 140 | TEST(LexerTest, expr_01) { 141 | bool res = TestLexerWithContent("1+3; 2+(4*2)/2+4;\n5-3*2;", []()->std::vector { 142 | std::vector expectedVec; 143 | expectedVec.push_back(Token{TokenType::number, 1, 1}); 144 | expectedVec.push_back(Token{TokenType::plus, 1, 2}); 145 | expectedVec.push_back(Token{TokenType::number, 1, 3}); 146 | expectedVec.push_back(Token{TokenType::semi, 1, 4}); 147 | expectedVec.push_back(Token{TokenType::number, 1, 6}); 148 | expectedVec.push_back(Token{TokenType::plus, 1, 7}); 149 | expectedVec.push_back(Token{TokenType::l_parent, 1, 8}); 150 | expectedVec.push_back(Token{TokenType::number, 1, 9}); 151 | 152 | expectedVec.push_back(Token{TokenType::star, 1, 10}); 153 | expectedVec.push_back(Token{TokenType::number, 1, 11}); 154 | expectedVec.push_back(Token{TokenType::r_parent, 1, 12}); 155 | expectedVec.push_back(Token{TokenType::slash, 1, 13}); 156 | expectedVec.push_back(Token{TokenType::number, 1, 14}); 157 | expectedVec.push_back(Token{TokenType::plus, 1, 15}); 158 | expectedVec.push_back(Token{TokenType::number, 1, 16}); 159 | expectedVec.push_back(Token{TokenType::semi, 1, 17}); 160 | expectedVec.push_back(Token{TokenType::number, 2, 1}); 161 | expectedVec.push_back(Token{TokenType::minus, 2, 2}); 162 | expectedVec.push_back(Token{TokenType::number, 2, 3}); 163 | expectedVec.push_back(Token{TokenType::star, 2, 4}); 164 | expectedVec.push_back(Token{TokenType::number, 2, 5}); 165 | expectedVec.push_back(Token{TokenType::semi, 2, 6}); 166 | return expectedVec; 167 | }); 168 | } -------------------------------------------------------------------------------- /test/parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | enable_testing() 2 | 3 | add_executable( 4 | parser_test 5 | parser_test.cc 6 | 7 | ../../lexer.cc 8 | ../../type.cc 9 | ../../diag_engine.cc 10 | ../../parser.cc 11 | ../../print_visitor.cc 12 | ../../sema.cc 13 | ../../scope.cc 14 | ../../eval_constant.cc 15 | ) 16 | 17 | llvm_map_components_to_libnames(llvm_all Support Core) 18 | 19 | #message(STATUS "iiicp: ${llvm_all}") 20 | 21 | target_link_libraries( 22 | parser_test 23 | GTest::gtest_main 24 | ${llvm_all} 25 | ) 26 | 27 | include(GoogleTest) 28 | gtest_discover_tests(parser_test) -------------------------------------------------------------------------------- /test/parser/parser_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lexer.h" 3 | #include "parser.h" 4 | #include "print_visitor.h" 5 | 6 | bool TestParserWithContent(llvm::StringRef content, llvm::StringRef expect) { 7 | llvm::ErrorOr> buf = llvm::MemoryBuffer::getMemBuffer(content, "stdin"); 8 | if (!buf) { 9 | llvm::errs() << "open file failed!!!\n"; 10 | return false; 11 | } 12 | llvm::SourceMgr mgr; 13 | DiagEngine diagEngine(mgr); 14 | mgr.AddNewSourceBuffer(std::move(*buf), llvm::SMLoc()); 15 | 16 | Lexer lex(mgr, diagEngine); 17 | Sema sema(diagEngine); 18 | Parser parser(lex, sema); 19 | 20 | auto program = parser.ParseProgram(); 21 | 22 | std::string s; 23 | llvm::raw_string_ostream ss(s); 24 | PrintVisitor printVisitor(program, &ss); 25 | if (expect != s) { 26 | llvm::outs() << "expect: " << expect << ", but got: " << s << "\n"; 27 | } 28 | EXPECT_EQ(expect, s); 29 | return true; 30 | } 31 | 32 | TEST(ParserTest, logor) { 33 | bool res = TestParserWithContent("int main(){return 1||2;}", "int main(){return 1||2;}"); 34 | ASSERT_EQ(res, true); 35 | } 36 | 37 | TEST(ParserTest, logand) { 38 | bool res = TestParserWithContent("int main(){return 1&&2;}", "int main(){return 1&&2;}"); 39 | ASSERT_EQ(res, true); 40 | } 41 | 42 | TEST(ParserTest, bitor) { 43 | bool res = TestParserWithContent("int main(){return 1|2;}", "int main(){return 1|2;}"); 44 | ASSERT_EQ(res, true); 45 | } 46 | 47 | TEST(ParserTest, bitxor) { 48 | bool res = TestParserWithContent("int main(){return 1^2;}", "int main(){return 1^2;}"); 49 | ASSERT_EQ(res, true); 50 | } 51 | 52 | TEST(ParserTest, bitand) { 53 | bool res = TestParserWithContent("int main(){return 1&2;}", "int main(){return 1&2;}"); 54 | ASSERT_EQ(res, true); 55 | } 56 | 57 | TEST(ParserTest, lshift) { 58 | bool res = TestParserWithContent("int main(){return 1<<2;}", "int main(){return 1<<2;}"); 59 | ASSERT_EQ(res, true); 60 | } 61 | 62 | TEST(ParserTest, rshift) { 63 | bool res = TestParserWithContent("int main(){return 1>>2;}", "int main(){return 1>>2;}"); 64 | ASSERT_EQ(res, true); 65 | } 66 | 67 | TEST(ParserTest, equal) { 68 | bool res = TestParserWithContent("int main(){return 1==2;}", "int main(){return 1==2;}"); 69 | ASSERT_EQ(res, true); 70 | } 71 | 72 | TEST(ParserTest, notequal) { 73 | bool res = TestParserWithContent("int main(){return 1!=2;}", "int main(){return 1!=2;}"); 74 | ASSERT_EQ(res, true); 75 | } 76 | 77 | TEST(ParserTest, add) { 78 | bool res = TestParserWithContent("int main(){return 1+2;}", "int main(){return 1+2;}"); 79 | ASSERT_EQ(res, true); 80 | } 81 | TEST(ParserTest, sub) { 82 | bool res = TestParserWithContent("int main(){return 1-2;}", "int main(){return 1-2;}"); 83 | ASSERT_EQ(res, true); 84 | } 85 | TEST(ParserTest, mul) { 86 | bool res = TestParserWithContent("int main(){return 1*2;}", "int main(){return 1*2;}"); 87 | ASSERT_EQ(res, true); 88 | } 89 | TEST(ParserTest, div) { 90 | bool res = TestParserWithContent("int main(){return 1/2;}", "int main(){return 1/2;}"); 91 | ASSERT_EQ(res, true); 92 | } 93 | TEST(ParserTest, mod) { 94 | bool res = TestParserWithContent("int main(){return 1%2;}", "int main(){return 1%2;}"); 95 | ASSERT_EQ(res, true); 96 | } 97 | 98 | TEST(ParserTest1, multi_arith) { 99 | bool res = TestParserWithContent("int main(){return 1+2/3-4*(6-9);}", "int main(){return 1+2/3-4*6-9;}"); 100 | ASSERT_EQ(res, true); 101 | } 102 | 103 | TEST(ParserTest2, assign) { 104 | bool res = TestParserWithContent("int main(){int a;a=2;return a;}", "int main(){int a;a=2;return a;}"); 105 | ASSERT_EQ(res, true); 106 | } 107 | 108 | TEST(ParserTest, multi_assign) { 109 | bool res = TestParserWithContent("int main(){int a=0,b=3;a=2;return a;}", "int main(){int a=0;int b=3;a=2;return a;}"); 110 | ASSERT_EQ(res, true); 111 | } 112 | 113 | TEST(ParserTest, half_assign) { 114 | bool res = TestParserWithContent("int main(){int a=0,b;a=5;b=2;return b;}", "int main(){int a=0;int b;a=5;b=2;return b;}"); 115 | ASSERT_EQ(res, true); 116 | } 117 | 118 | TEST(ParserTest, if_stmt) { 119 | bool res = TestParserWithContent("int main(){int a=0,b=1;if(a>=0){b=100;}else{b=50;}return 0;}", "int main(){int a=0;int b=1;if(a>=0){b=100;}else{b=50;};return 0;}"); 120 | ASSERT_EQ(res, true); 121 | } 122 | 123 | TEST(ParserTest, for_stmt) { 124 | bool res = TestParserWithContent("int main(){int a=0,b=1;for(int i=0;i<=100;i=i+1){a=a+b;}return 0;}", "int main(){int a=0;int b=1;for(int i=0;i<=100;i=i+1){a=a+b;};return 0;}"); 125 | ASSERT_EQ(res, true); 126 | } 127 | 128 | TEST(ParserTest, break_stmt) { 129 | bool res = TestParserWithContent("int main(){int a=0,b=1;for(int i=0;i<=100;i=i+1){if(a>20){break;}a=a+b;}return 0;}", "int main(){int a=0;int b=1;for(int i=0;i<=100;i=i+1){if(a>20){break;};a=a+b;};return 0;}"); 130 | ASSERT_EQ(res, true); 131 | } 132 | 133 | TEST(ParserTest, continue_stmt) { 134 | bool res = TestParserWithContent("int main(){int a=0,b=1;for(int i=0;i<=100;i=i+1){if(a==20){continue;}a=a+b;}return 0;}", "int main(){int a=0;int b=1;for(int i=0;i<=100;i=i+1){if(a==20){continue;};a=a+b;};return 0;}"); 135 | ASSERT_EQ(res, true); 136 | } 137 | 138 | TEST(ParserTest, block_stmt) { 139 | bool res = TestParserWithContent("int main(){int a;a+3;return a;}", "int main(){int a;a+3;return a;}"); 140 | ASSERT_EQ(res, true); 141 | } 142 | 143 | TEST(ParserTest, single_assign) { 144 | bool res = TestParserWithContent("int main(){int a;a=3;return a;}", "int main(){int a;a=3;return a;}"); 145 | ASSERT_EQ(res, true); 146 | } 147 | 148 | TEST(ParserTest, assign_op) { 149 | bool res = TestParserWithContent("int main(){int a;a+=3;a-=3;a*=3;a/=3;a%=3;a|=3;a^=3;a&=3;a<<=3;a>>=3;return a;}", "int main(){int a;a+=3;a-=3;a*=3;a/=3;a%=3;a|=3;a^=3;a&=3;a<<=3;a>>=3;return a;}"); 150 | ASSERT_EQ(res, true); 151 | } 152 | 153 | TEST(ParserTest, unary_op) { 154 | bool res = TestParserWithContent("int main(){int a=0;int *p=&a;+a;-a;!a;~a;++a;--a;sizeof a;&a;*p;}", "int main(){int a=0;int *p=&a;+a;-a;!a;~a;++a;--a;sizeof a;&a;*p;}"); 155 | ASSERT_EQ(res, true); 156 | } 157 | 158 | TEST(ParserTest, tree_op) { 159 | bool res = TestParserWithContent("int main(){int a=3;a>=3?a=5:-5;}", "int main(){int a=3;a>=3?a=5:-5;}"); 160 | ASSERT_EQ(res, true); 161 | } 162 | 163 | TEST(ParserTest, post_op) { 164 | bool res = TestParserWithContent("int main(){int a=3;int *p=&a;p++;p--;*p++;*p--;++*p;--*p;}", "int main(){int a=3;int *p=&a;p++;p--;*p++;*p--;++*p;--*p;}"); 165 | ASSERT_EQ(res, true); 166 | } 167 | 168 | TEST(ParserTest, multi_point_op) { 169 | bool res = TestParserWithContent("int main(){int a=3;int *p=&a;int **q=&p;--*p;}", "int main(){int a=3;int *p=&a;int **q=&p;--*p;}"); 170 | ASSERT_EQ(res, true); 171 | } 172 | 173 | TEST(ParserTest, sizeof_op) { 174 | bool res = TestParserWithContent("int main(){int a=3;sizeof a;sizeof (a);sizeof(int);}", "int main(){int a=3;sizeof a;sizeof a;sizeof (int );}"); 175 | ASSERT_EQ(res, true); 176 | } 177 | 178 | TEST(ParserTest, assign_comma_op) { 179 | bool res = TestParserWithContent("int main(){int a=3,b;a=3,b=4;}", "int main(){int a=3;int b;a=3,b=4;}"); 180 | ASSERT_EQ(res, true); 181 | } 182 | 183 | TEST(ParserTest, array_one) { 184 | bool res = TestParserWithContent("int main(){int a[3];}", "int main(){[3]int a;}"); 185 | ASSERT_EQ(res, true); 186 | } 187 | 188 | TEST(ParserTest, array_two) { 189 | bool res = TestParserWithContent("int main(){int a[3],b[5];}", "int main(){[3]int a;[5]int b;}"); 190 | ASSERT_EQ(res, true); 191 | } 192 | 193 | TEST(ParserTest, array_three) { 194 | bool res = TestParserWithContent("int main(){int a[3][5][8];}", "int main(){[3][5][8]int a;}"); 195 | ASSERT_EQ(res, true); 196 | } 197 | 198 | TEST(ParserTest, array_four) { 199 | bool res = TestParserWithContent("int main(){int** a[3][5][8];}", "int main(){[3][5][8]int **a;}"); 200 | ASSERT_EQ(res, true); 201 | } 202 | 203 | TEST(ParserTest, array_five) { 204 | bool res = TestParserWithContent("int main(){int a[3],b[5][8];int *p[5];}", "int main(){[3]int a;[5][8]int b;[5]int *p;}"); 205 | ASSERT_EQ(res, true); 206 | } 207 | 208 | TEST(ParserTest, sizeof_array1) { 209 | bool res = TestParserWithContent("int main(){sizeof (int [5]);}", "int main(){sizeof ([5]int );}"); 210 | ASSERT_EQ(res, true); 211 | } 212 | 213 | TEST(ParserTest, sizeof_array2) { 214 | bool res = TestParserWithContent("int main(){sizeof (int* [5]);}", "int main(){sizeof ([5]int *);}"); 215 | ASSERT_EQ(res, true); 216 | } 217 | 218 | TEST(ParserTest, sizeof_array3) { 219 | bool res = TestParserWithContent("int main(){sizeof (int* [5][3]);}", "int main(){sizeof ([5][3]int *);}"); 220 | ASSERT_EQ(res, true); 221 | } 222 | 223 | 224 | TEST(ParserTest, post_arr_1) { 225 | bool res = TestParserWithContent("int main(){int a[3]; a[0] = 4;}", "int main(){[3]int a;a[0]=4;}"); 226 | ASSERT_EQ(res, true); 227 | } 228 | 229 | TEST(ParserTest, arr_init1) { 230 | bool res = TestParserWithContent("int main(){int a[3]={1,2}; a[0] = 4;}", "int main(){[3]int a=1,2;a[0]=4;}"); 231 | ASSERT_EQ(res, true); 232 | } -------------------------------------------------------------------------------- /type.cc: -------------------------------------------------------------------------------- 1 | #include "type.h" 2 | 3 | std::shared_ptr CType::VoidType = std::make_shared(Kind::TY_Void, 0, 0, true); 4 | std::shared_ptr CType::CharType = std::make_shared(Kind::TY_Char, 1, 1, true); 5 | std::shared_ptr CType::UCharType = std::make_shared(Kind::TY_UChar, 1, 1, false); 6 | std::shared_ptr CType::ShortType = std::make_shared(Kind::TY_Short, 2, 2, true); 7 | std::shared_ptr CType::UShortType = std::make_shared(Kind::TY_UShort, 2, 2, false); 8 | std::shared_ptr CType::IntType = std::make_shared(Kind::TY_Int, 4, 4, true); 9 | std::shared_ptr CType::UIntType = std::make_shared(Kind::TY_UInt, 4, 4, false); 10 | std::shared_ptr CType::LongType = std::make_shared(Kind::TY_Long, 8, 8, true); 11 | std::shared_ptr CType::ULongType = std::make_shared(Kind::TY_ULong, 8, 8, false); 12 | std::shared_ptr CType::LongLongType = std::make_shared(Kind::TY_LLong, 8, 8, true); 13 | std::shared_ptr CType::ULongLongType = std::make_shared(Kind::TY_ULLong, 8, 8, false); 14 | std::shared_ptr CType::FloatType = std::make_shared(Kind::TY_Float, 4, 4, true); 15 | std::shared_ptr CType::DoubleType = std::make_shared(Kind::TY_Double, 8, 8, true); 16 | std::shared_ptr CType::LDoubleType = std::make_shared(Kind::TY_LDouble, 8, 8, true); 17 | 18 | 19 | bool CType::IsIntegerType() { 20 | if (kind == TY_Char || kind == TY_UChar || kind == TY_Short || kind == TY_UShort || 21 | kind == TY_Int || kind == TY_UInt || kind == TY_Long || kind == TY_ULong || 22 | kind == TY_LLong || kind == TY_ULLong) { 23 | return true; 24 | } 25 | return false; 26 | } 27 | 28 | bool CType::IsFloatType() { 29 | if (kind == TY_Float || kind == TY_Double || kind == TY_LDouble) 30 | return true; 31 | return false; 32 | } 33 | 34 | bool CType::IsArithType() { 35 | return IsIntegerType() || IsFloatType(); 36 | } 37 | 38 | llvm::StringRef CType::GenAnonyRecordName(TagKind tagKind) { 39 | static long long idx = 0; 40 | std::string name; 41 | if (tagKind == TagKind::kStruct) { 42 | name = "__1anony_struct_" + std::to_string(idx++) + "_"; 43 | }else { 44 | name = "__1anony_union_" + std::to_string(idx++) + "_"; 45 | } 46 | char *buf = (char *)malloc(name.size()+1); 47 | memset(buf, 0, name.size()); 48 | strcpy(buf, name.data()); 49 | return llvm::StringRef(buf, name.size()); 50 | } 51 | 52 | /// 地址对齐算法 53 | /// 找到大于等于x,且按照align(必须是2的倍数)对其的最小地址 54 | /// (0, 1) => 0 55 | /// (1, 4) => 4 56 | static int roundup(int x, int align) { 57 | return (x + align - 1) & ~(align - 1); 58 | } 59 | 60 | CRecordType::CRecordType(llvm::StringRef name, const std::vector &members, TagKind tagKind) 61 | : CType(CType::TY_Record, 0, 0), name(name), members(members), tagKind(tagKind){ 62 | if (tagKind == TagKind::kStruct) { 63 | UpdateStructOffset(); 64 | }else { 65 | UpdateUnionOffset(); 66 | } 67 | } 68 | 69 | void CRecordType::SetMembers(const std::vector& members) { 70 | this->members = members; 71 | if (tagKind == TagKind::kStruct) { 72 | UpdateStructOffset(); 73 | }else { 74 | UpdateUnionOffset(); 75 | } 76 | } 77 | /** 78 | struct -> size (all element size + padding) 79 | every element -> (offset + size) 80 | */ 81 | void CRecordType::UpdateStructOffset() { 82 | int offset = 0; 83 | int idx = 0; 84 | int total_size = 0, max_align = 0, max_element_size = 0, max_element_idx = 0; 85 | for (auto &m : members) { 86 | offset = roundup(offset, m.ty->GetAlign()); 87 | m.offset = offset; 88 | m.elemIdx = idx++; 89 | 90 | /// 求出最大member的对齐数 91 | if (max_align < m.ty->GetAlign()) { 92 | max_align = m.ty->GetAlign(); 93 | } 94 | 95 | if (max_element_size < m.ty->GetSize()) { 96 | max_element_size = m.ty->GetSize(); 97 | max_element_idx = m.elemIdx; 98 | } 99 | 100 | /// 下一个元素的offset 101 | offset += m.ty->GetSize(); 102 | } 103 | // struct A{int a; int b;} 104 | total_size = roundup(offset, max_align); 105 | 106 | size = total_size; 107 | align = max_align; 108 | maxElementIdx = max_element_idx; 109 | } 110 | 111 | void CRecordType::UpdateUnionOffset() { 112 | int max_align = 0, max_size = 0, max_element_idx = 0; 113 | int idx = 0; 114 | for (auto &m : members) { 115 | m.offset = 0; 116 | m.elemIdx = idx++; 117 | 118 | if (max_align < m.ty->GetAlign()) { 119 | max_align = m.ty->GetAlign(); 120 | } 121 | 122 | if (max_size < m.ty->GetSize()) { 123 | max_size = m.ty->GetSize(); 124 | max_element_idx = m.elemIdx; 125 | } 126 | } 127 | 128 | max_size = roundup(max_size, max_align); 129 | 130 | size = max_size; 131 | align = max_align; 132 | maxElementIdx = max_element_idx; 133 | } 134 | 135 | CFuncType::CFuncType(std::shared_ptr retType, const std::vector& params, llvm::StringRef name, bool isVarArg) 136 | : CType(CType::TY_Func, 1, 1), retType(retType), params(params), name(name), isVarArg(isVarArg) { 137 | 138 | } -------------------------------------------------------------------------------- /type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "llvm/IR/Type.h" 4 | 5 | class CPrimaryType; 6 | class CPointType; 7 | class CArrayType; 8 | class CRecordType; 9 | class CFuncType; 10 | 11 | class TypeVisitor { 12 | public: 13 | virtual ~TypeVisitor() {} 14 | virtual llvm::Type * VisitPrimaryType(CPrimaryType *ty) = 0; 15 | virtual llvm::Type * VisitPointType(CPointType *ty) = 0; 16 | virtual llvm::Type * VisitArrayType(CArrayType *ty) = 0; 17 | virtual llvm::Type * VisitRecordType(CRecordType *ty) = 0; 18 | virtual llvm::Type * VisitFuncType(CFuncType *ty) = 0; 19 | }; 20 | 21 | enum class TagKind { 22 | kStruct, 23 | kUnion 24 | }; 25 | 26 | class CType { 27 | public: 28 | enum Kind { 29 | TY_Void, 30 | TY_Char, 31 | TY_UChar, 32 | TY_Short, 33 | TY_UShort, 34 | TY_Int, 35 | TY_UInt, 36 | TY_Long, 37 | TY_ULong, 38 | TY_LLong, 39 | TY_ULLong, 40 | TY_Float, 41 | TY_Double, 42 | TY_LDouble, 43 | TY_Point, 44 | TY_Array, 45 | TY_Record, 46 | TY_Func, 47 | }; 48 | protected: 49 | Kind kind; 50 | int size; /// 字节数 51 | int align; /// 对齐数 52 | bool sign{true}; ///默认是有符号 53 | public: 54 | CType(Kind kind, int size, int align, bool sign = true):kind(kind), size(size), align(align), sign(sign) {} 55 | virtual ~CType() {} 56 | Kind GetKind() const {return kind;} 57 | int GetSize() const { 58 | return size; 59 | } 60 | int GetAlign() const { 61 | return align; 62 | } 63 | 64 | bool IsIntegerType(); 65 | bool IsFloatType(); 66 | bool IsArithType(); 67 | 68 | virtual llvm::Type * Accept(TypeVisitor *v) {return nullptr;} 69 | 70 | static std::shared_ptr VoidType; 71 | static std::shared_ptr CharType; 72 | static std::shared_ptr UCharType; 73 | static std::shared_ptr ShortType; 74 | static std::shared_ptr UShortType; 75 | static std::shared_ptr IntType; 76 | static std::shared_ptr UIntType; 77 | static std::shared_ptr LongType; 78 | static std::shared_ptr ULongType; 79 | static std::shared_ptr LongLongType; 80 | static std::shared_ptr ULongLongType; 81 | static std::shared_ptr FloatType; 82 | static std::shared_ptr DoubleType; 83 | static std::shared_ptr LDoubleType; 84 | 85 | static llvm::StringRef GenAnonyRecordName(TagKind tagKind); 86 | }; 87 | 88 | class CPrimaryType : public CType { 89 | public: 90 | CPrimaryType(Kind kind, int size, int align, bool sign):CType(kind, size, align, sign) {} 91 | 92 | llvm::Type * Accept(TypeVisitor *v) override { 93 | return v->VisitPrimaryType(this); 94 | } 95 | 96 | static bool classof(const CType *ty) { 97 | return (ty->GetKind() == TY_Char || ty->GetKind() == TY_UChar || 98 | ty->GetKind() == TY_Short || ty->GetKind() == TY_UShort || 99 | ty->GetKind() == TY_Int || ty->GetKind() == TY_UInt || 100 | ty->GetKind() == TY_Long || ty->GetKind() == TY_ULong || 101 | ty->GetKind() == TY_LLong || ty->GetKind() == TY_ULLong || 102 | ty->GetKind() == TY_Float || ty->GetKind() == TY_Double); 103 | } 104 | }; 105 | 106 | class CPointType : public CType{ 107 | private: 108 | std::shared_ptr baseType; 109 | public: 110 | CPointType(std::shared_ptr baseType):CType(Kind::TY_Point, 8, 8), baseType(baseType) {} 111 | 112 | std::shared_ptr GetBaseType() { 113 | return baseType; 114 | } 115 | 116 | llvm::Type * Accept(TypeVisitor *v) override { 117 | return v->VisitPointType(this); 118 | } 119 | 120 | static bool classof(const CType *ty) { 121 | return ty->GetKind() == TY_Point; 122 | } 123 | }; 124 | 125 | class CArrayType : public CType { 126 | private: 127 | std::shared_ptr elementType; 128 | int elementCount{-1}; 129 | public: 130 | CArrayType(std::shared_ptr elementType, int elementCount) 131 | :CType(Kind::TY_Array, elementCount * elementType->GetSize(), elementType->GetAlign()), elementType(elementType), elementCount(elementCount) {} 132 | 133 | std::shared_ptr GetElementType() { 134 | return elementType; 135 | } 136 | 137 | int GetElementCount() { 138 | return elementCount; 139 | } 140 | 141 | void SetElementCount(int count) { 142 | elementCount = count; 143 | this->size = elementCount * elementType->GetSize(); 144 | } 145 | 146 | llvm::Type * Accept(TypeVisitor *v) override { 147 | return v->VisitArrayType(this); 148 | } 149 | 150 | static bool classof(const CType *ty) { 151 | return ty->GetKind() == TY_Array; 152 | } 153 | }; 154 | 155 | struct Member { 156 | std::shared_ptr ty; 157 | llvm::StringRef name; 158 | int offset; 159 | int elemIdx; 160 | }; 161 | 162 | 163 | class CRecordType : public CType { 164 | private: 165 | llvm::StringRef name; 166 | std::vector members; 167 | TagKind tagKind; 168 | int maxElementIdx; 169 | public: 170 | CRecordType(llvm::StringRef name, const std::vector &members, TagKind tagKind); 171 | 172 | const llvm::StringRef GetName() { 173 | return name; 174 | } 175 | 176 | const std::vector &GetMembers() { 177 | return members; 178 | } 179 | 180 | void SetMembers(const std::vector& members); 181 | 182 | TagKind GetTagKind() { 183 | return tagKind; 184 | } 185 | 186 | int GetMaxElementIdx() { 187 | return maxElementIdx; 188 | } 189 | 190 | llvm::Type * Accept(TypeVisitor *v) override { 191 | return v->VisitRecordType(this); 192 | } 193 | 194 | static bool classof(const CType *ty) { 195 | return ty->GetKind() == TY_Record; 196 | } 197 | private: 198 | void UpdateStructOffset(); 199 | void UpdateUnionOffset(); 200 | }; 201 | 202 | struct Param { 203 | std::shared_ptr type; 204 | llvm::StringRef name; 205 | }; 206 | 207 | class CFuncType : public CType { 208 | private: 209 | std::shared_ptr retType; 210 | std::vector params; 211 | llvm::StringRef name; 212 | bool isVarArg{false}; 213 | public: 214 | bool hasBody{false}; 215 | CFuncType(std::shared_ptr retType, const std::vector& params, llvm::StringRef name, bool isVarArg); 216 | 217 | const llvm::StringRef GetName() { 218 | return name; 219 | } 220 | 221 | const std::vector &GetParams() { 222 | return params; 223 | } 224 | 225 | std::shared_ptr GetRetType() { 226 | return retType; 227 | } 228 | 229 | bool IsVarArg() { 230 | return isVarArg; 231 | } 232 | 233 | llvm::Type * Accept(TypeVisitor *v) override { 234 | return v->VisitFuncType(this); 235 | } 236 | 237 | static bool classof(const CType *ty) { 238 | return ty->GetKind() == TY_Func; 239 | } 240 | }; --------------------------------------------------------------------------------