From 3e4165c4bb8c65f7b4bc7b5b5722db822ee788ed Mon Sep 17 00:00:00 2001
From: Oliveira <1350121858@qq.com>
Date: Mon, 23 Mar 2026 15:59:28 +0800
Subject: [PATCH 1/4] =?UTF-8?q?feat(grammar):=20=E5=AE=8C=E5=96=84=20SysY.?=
=?UTF-8?q?g4=20=E8=AF=AD=E6=B3=95=E5=AE=9A=E4=B9=89=E6=94=AF=E6=8C=81=20L?=
=?UTF-8?q?ab1=20=E8=A6=81=E6=B1=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 扩展 SysY 语法定义以支持更多合法程序
- 完善词法和语法规则,增强解析能力
- 确保符合 SysY 语言规范
---
src/antlr4/SysY.g4 | 138 ++++++++++++++++++++++++++++++++++++---------
1 file changed, 112 insertions(+), 26 deletions(-)
diff --git a/src/antlr4/SysY.g4 b/src/antlr4/SysY.g4
index 263aeef..487fc1e 100644
--- a/src/antlr4/SysY.g4
+++ b/src/antlr4/SysY.g4
@@ -1,31 +1,61 @@
-// SysY 子集语法:支持形如
-// int main() { int a = 1; int b = 2; return a + b; }
-// 的最小返回表达式编译。
-
-// 后续需要自行添加
-
grammar SysY;
/*===-------------------------------------------===*/
/* Lexer rules */
/*===-------------------------------------------===*/
+CONST: 'const';
INT: 'int';
+FLOAT: 'float';
+VOID: 'void';
+IF: 'if';
+ELSE: 'else';
+WHILE: 'while';
+BREAK: 'break';
+CONTINUE: 'continue';
RETURN: 'return';
ASSIGN: '=';
ADD: '+';
+SUB: '-';
+MUL: '*';
+DIV: '/';
+MOD: '%';
+EQ: '==';
+NEQ: '!=';
+LT: '<';
+GT: '>';
+LE: '<=';
+GE: '>=';
+NOT: '!';
+AND: '&&';
+OR: '||';
LPAREN: '(';
RPAREN: ')';
+LBRACK: '[';
+RBRACK: ']';
LBRACE: '{';
RBRACE: '}';
+COMMA: ',';
SEMICOLON: ';';
ID: [a-zA-Z_][a-zA-Z_0-9]*;
-ILITERAL: [0-9]+;
-WS: [ \t\r\n] -> skip;
+ILITERAL
+ : '0' | [1-9][0-9]* // Decimal
+ | '0' [0-7]+ // Octal
+ | ('0x' | '0X') [0-9a-fA-F]+ // Hex
+ ;
+
+FLITERAL
+ : ([0-9]* '.' [0-9]+ | [0-9]+ '.') ([eE] [+-]? [0-9]+)?
+ | [0-9]+ [eE] [+-]? [0-9]+
+ | ('0x'|'0X') ([0-9a-fA-F]* '.' [0-9a-fA-F]+ | [0-9a-fA-F]+ '.') ([pP] [+-]? [0-9]+)?
+ | ('0x'|'0X') [0-9a-fA-F]+ [pP] [+-]? [0-9]+
+ ;
+
+WS: [ \t\r\n]+ -> skip;
LINECOMMENT: '//' ~[\r\n]* -> skip;
BLOCKCOMMENT: '/*' .*? '*/' -> skip;
@@ -34,31 +64,62 @@ BLOCKCOMMENT: '/*' .*? '*/' -> skip;
/*===-------------------------------------------===*/
compUnit
- : funcDef EOF
+ : (decl | funcDef)+ EOF
;
decl
- : btype varDef SEMICOLON
+ : constDecl
+ | varDecl
+ ;
+
+constDecl
+ : CONST btype constDef (COMMA constDef)* SEMICOLON
;
btype
: INT
+ | FLOAT
+ ;
+
+constDef
+ : ID (LBRACK constExp RBRACK)* ASSIGN constInitVal
+ ;
+
+constInitVal
+ : constExp
+ | LBRACE (constInitVal (COMMA constInitVal)*)? RBRACE
+ ;
+
+varDecl
+ : btype varDef (COMMA varDef)* SEMICOLON
;
varDef
- : lValue (ASSIGN initValue)?
+ : ID (LBRACK constExp RBRACK)*
+ | ID (LBRACK constExp RBRACK)* ASSIGN initValue
;
initValue
: exp
+ | LBRACE (initValue (COMMA initValue)*)? RBRACE
;
funcDef
- : funcType ID LPAREN RPAREN blockStmt
+ : funcType ID LPAREN funcFParams? RPAREN blockStmt
;
funcType
- : INT
+ : VOID
+ | INT
+ | FLOAT
+ ;
+
+funcFParams
+ : funcFParam (COMMA funcFParam)*
+ ;
+
+funcFParam
+ : btype ID (LBRACK RBRACK (LBRACK exp RBRACK)*)?
;
blockStmt
@@ -71,28 +132,53 @@ blockItem
;
stmt
- : returnStmt
- ;
-
-returnStmt
- : RETURN exp SEMICOLON
+ : lValue ASSIGN exp SEMICOLON # assignStmt
+ | exp? SEMICOLON # exprStmt
+ | blockStmt # blockStmtStmt
+ | IF LPAREN cond RPAREN stmt (ELSE stmt)? # ifStmt
+ | WHILE LPAREN cond RPAREN stmt # whileStmt
+ | BREAK SEMICOLON # breakStmt
+ | CONTINUE SEMICOLON # continueStmt
+ | RETURN exp? SEMICOLON # returnStmt
;
exp
- : LPAREN exp RPAREN # parenExp
- | var # varExp
- | number # numberExp
- | exp ADD exp # additiveExp
+ : LPAREN exp RPAREN # parenExp
+ | lValue # lvalExp
+ | number # numberExp
+ | ID LPAREN funcRParams? RPAREN # callExp
+ | unaryOp exp # unaryExp
+ | exp (MUL | DIV | MOD) exp # mulExp
+ | exp (ADD | SUB) exp # addExp
+ | exp (LT | GT | LE | GE) exp # relExp
+ | exp (EQ | NEQ) exp # eqExp
+ | exp AND exp # lAndExp
+ | exp OR exp # lOrExp
;
-var
- : ID
+cond
+ : exp
;
lValue
- : ID
+ : ID (LBRACK exp RBRACK)*
;
number
- : ILITERAL
+ : ILITERAL # intConst
+ | FLITERAL # floatConst
+ ;
+
+unaryOp
+ : ADD
+ | SUB
+ | NOT
+ ;
+
+funcRParams
+ : exp (COMMA exp)*
+ ;
+
+constExp
+ : exp
;
From 02e5a7d4e7e3f32826515bac1d24fd1bfc9e36b5 Mon Sep 17 00:00:00 2001
From: Oliveira <1350121858@qq.com>
Date: Mon, 30 Mar 2026 20:10:45 +0800
Subject: [PATCH 2/4] merge error
---
src/antlr4/SysY.g4 | 171 ++++++++++++++++++++++++++++-----------------
1 file changed, 106 insertions(+), 65 deletions(-)
diff --git a/src/antlr4/SysY.g4 b/src/antlr4/SysY.g4
index 4c5d788..262f07a 100644
--- a/src/antlr4/SysY.g4
+++ b/src/antlr4/SysY.g4
@@ -47,48 +47,44 @@ MUL: '*';
DIV: '/';
MOD: '%';
NOT: '!';
-SUB: '-';
-MUL: '*';
-DIV: '/';
-MOD: '%';
-EQ: '==';
-NEQ: '!=';
-LT: '<';
-GT: '>';
-LE: '<=';
-GE: '>=';
-NOT: '!';
-AND: '&&';
-OR: '||';
LPAREN: '(';
RPAREN: ')';
LBRACK: '[';
RBRACK: ']';
-LBRACK: '[';
-RBRACK: ']';
LBRACE: '{';
RBRACE: '}';
COMMA: ',';
-COMMA: ',';
SEMICOLON: ';';
ID: [a-zA-Z_][a-zA-Z_0-9]*;
-ILITERAL
- : '0' | [1-9][0-9]* // Decimal
- | '0' [0-7]+ // Octal
- | ('0x' | '0X') [0-9a-fA-F]+ // Hex
+HEX_FLOAT_LITERAL
+ : ('0x' | '0X') HEX_DIGIT* '.' HEX_DIGIT+ BINARY_EXPONENT
+ | ('0x' | '0X') HEX_DIGIT+ '.' HEX_DIGIT* BINARY_EXPONENT
+ | ('0x' | '0X') HEX_DIGIT+ BINARY_EXPONENT
+ ;
+
+DEC_FLOAT_LITERAL
+ : DEC_DIGIT+ '.' DEC_DIGIT* DEC_EXPONENT?
+ | '.' DEC_DIGIT+ DEC_EXPONENT?
+ | DEC_DIGIT+ DEC_EXPONENT
+ ;
+
+HEX_INT_LITERAL
+ : ('0x' | '0X') HEX_DIGIT+
+ ;
+
+OCT_INT_LITERAL
+ : '0' OCT_DIGIT+
;
-FLITERAL
- : ([0-9]* '.' [0-9]+ | [0-9]+ '.') ([eE] [+-]? [0-9]+)?
- | [0-9]+ [eE] [+-]? [0-9]+
- | ('0x'|'0X') ([0-9a-fA-F]* '.' [0-9a-fA-F]+ | [0-9a-fA-F]+ '.') ([pP] [+-]? [0-9]+)?
- | ('0x'|'0X') [0-9a-fA-F]+ [pP] [+-]? [0-9]+
+DEC_INT_LITERAL
+ : '0'
+ | [1-9] DEC_DIGIT*
;
-WS: [ \t\r\n]+ -> skip;
+WS: [ \t\r\n] -> skip;
LINECOMMENT: '//' ~[\r\n]* -> skip;
BLOCKCOMMENT: '/*' .*? '*/' -> skip;
@@ -130,16 +126,7 @@ bType
;
constDef
- : ID (LBRACK constExp RBRACK)* ASSIGN constInitVal
- ;
-
-constInitVal
- : constExp
- | LBRACE (constInitVal (COMMA constInitVal)*)? RBRACE
- ;
-
-varDecl
- : btype varDef (COMMA varDef)* SEMICOLON
+ : ID constIndex* ASSIGN constInitVal
;
varDef
@@ -157,11 +144,11 @@ constInitVal
initVal
: exp
- | LBRACE (initValue (COMMA initValue)*)? RBRACE
+ | LBRACE (initVal (COMMA initVal)*)? RBRACE
;
funcDef
- : funcType ID LPAREN funcFParams? RPAREN blockStmt
+ : funcType ID LPAREN funcFParams? RPAREN block
;
funcType
@@ -175,7 +162,7 @@ funcFParams
;
funcFParam
- : btype ID (LBRACK RBRACK (LBRACK exp RBRACK)*)?
+ : bType ID (LBRACK RBRACK (LBRACK exp RBRACK)*)?
;
block
@@ -188,53 +175,107 @@ blockItem
;
stmt
- : lValue ASSIGN exp SEMICOLON # assignStmt
- | exp? SEMICOLON # exprStmt
- | blockStmt # blockStmtStmt
- | IF LPAREN cond RPAREN stmt (ELSE stmt)? # ifStmt
- | WHILE LPAREN cond RPAREN stmt # whileStmt
- | BREAK SEMICOLON # breakStmt
- | CONTINUE SEMICOLON # continueStmt
- | RETURN exp? SEMICOLON # returnStmt
+ : lVal ASSIGN exp SEMICOLON
+ | exp? SEMICOLON
+ | block
+ | IF LPAREN cond RPAREN stmt (ELSE stmt)?
+ | WHILE LPAREN cond RPAREN stmt
+ | BREAK SEMICOLON
+ | CONTINUE SEMICOLON
+ | RETURN exp? SEMICOLON
;
exp
- : LPAREN exp RPAREN # parenExp
- | lValue # lvalExp
- | number # numberExp
- | ID LPAREN funcRParams? RPAREN # callExp
- | unaryOp exp # unaryExp
- | exp (MUL | DIV | MOD) exp # mulExp
- | exp (ADD | SUB) exp # addExp
- | exp (LT | GT | LE | GE) exp # relExp
- | exp (EQ | NEQ) exp # eqExp
- | exp AND exp # lAndExp
- | exp OR exp # lOrExp
+ : addExp
;
cond
- : exp
+ : lOrExp
;
-lValue
+lVal
: ID (LBRACK exp RBRACK)*
;
+primaryExp
+ : LPAREN exp RPAREN
+ | lVal
+ | number
+ ;
+
number
- : ILITERAL # intConst
- | FLITERAL # floatConst
+ : intConst
+ | floatConst
+ ;
+
+intConst
+ : DEC_INT_LITERAL
+ | OCT_INT_LITERAL
+ | HEX_INT_LITERAL
;
-unaryOp
+floatConst
+ : DEC_FLOAT_LITERAL
+ | HEX_FLOAT_LITERAL
+ ;
+
+unaryExp
+ : primaryExp
+ | ID LPAREN funcRParams? RPAREN
+ | addUnaryOp unaryExp
+ ;
+
+addUnaryOp
: ADD
| SUB
- | NOT
;
funcRParams
: exp (COMMA exp)*
;
+mulExp
+ : unaryExp
+ | mulExp MUL unaryExp
+ | mulExp DIV unaryExp
+ | mulExp MOD unaryExp
+ ;
+
+addExp
+ : mulExp
+ | addExp ADD mulExp
+ | addExp SUB mulExp
+ ;
+
+relExp
+ : addExp
+ | relExp LT addExp
+ | relExp GT addExp
+ | relExp LE addExp
+ | relExp GE addExp
+ ;
+
+eqExp
+ : relExp
+ | eqExp EQ relExp
+ | eqExp NE relExp
+ ;
+
+lAndExp
+ : condUnaryExp
+ | lAndExp AND condUnaryExp
+ ;
+
+lOrExp
+ : lAndExp
+ | lOrExp OR lAndExp
+ ;
+
+condUnaryExp
+ : eqExp
+ | NOT condUnaryExp
+ ;
+
constExp
- : exp
+ : addExp
;
From d2f49b71c5f5601460a8cf9b5e17286b9d1cdd00 Mon Sep 17 00:00:00 2001
From: Oliveira <1350121858@qq.com>
Date: Tue, 31 Mar 2026 13:26:26 +0800
Subject: [PATCH 3/4] gitignore add
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 1ee33a1..51f5f27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -68,3 +68,4 @@ Thumbs.db
# Project outputs
# =========================
test/test_result/
+sema_check
\ No newline at end of file
From 2de1561210d63e86bfe09679ac7ed13febb4c136 Mon Sep 17 00:00:00 2001
From: Oliveira <1350121858@qq.com>
Date: Tue, 31 Mar 2026 13:56:52 +0800
Subject: [PATCH 4/4] =?UTF-8?q?feat(irgen):=20=E5=AE=9E=E7=8E=B0=E6=8E=A7?=
=?UTF-8?q?=E5=88=B6=E6=B5=81=E4=B8=8E=E9=80=BB=E8=BE=91=E8=A1=A8=E8=BE=BE?=
=?UTF-8?q?=E5=BC=8F=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=20-=20=E6=A0=B8?=
=?UTF-8?q?=E5=BF=83=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81=EF=BC=9A=E5=AE=8C?=
=?UTF-8?q?=E6=95=B4=E5=AE=9E=E7=8E=B0=20if-else,=20while,=20break,=20cont?=
=?UTF-8?q?inue=20=E8=AF=AD=E5=8F=A5=E7=9A=84=20IR=20=E7=94=9F=E6=88=90?=
=?UTF-8?q?=E5=8F=8A=E8=B7=B3=E5=87=BA=E5=9D=97=E7=BB=B4=E6=8A=A4=20-=20?=
=?UTF-8?q?=E6=89=A9=E5=B1=95=E6=8C=87=E4=BB=A4=E7=B3=BB=E7=BB=9F=EF=BC=9A?=
=?UTF-8?q?=E6=96=B0=E5=A2=9E=20Cmp,=20Zext,=20Br,=20CondBr=20=E6=8C=87?=
=?UTF-8?q?=E4=BB=A4=EF=BC=8C=E8=A1=A5=E9=BD=90=20Builder/Printer=20?=
=?UTF-8?q?=E6=8E=A5=E5=8F=A3=20-=20=E6=94=AF=E6=8C=81=E9=80=BB=E8=BE=91?=
=?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=EF=BC=9A=E5=AE=8C=E6=88=90=20RelExp?=
=?UTF-8?q?,=20EqExp,=20=E9=80=BB=E8=BE=91=E7=9F=AD=E8=B7=AF=E6=B1=82?=
=?UTF-8?q?=E5=80=BC=20(LAndExp,=20LOrExp)=20=E5=8F=8A=E9=80=BB=E8=BE=91?=
=?UTF-8?q?=E9=9D=9E=E7=9A=84=E7=BF=BB=E8=AF=91=20-=20=E6=9E=B6=E6=9E=84?=
=?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9C=BA=E5=88=B6=20BUG=20=E4=BF=AE=E5=A4=8D?=
=?UTF-8?q?=EF=BC=9A=20=20=201.=20=E4=BF=AE=E5=A4=8D=20Sema.cpp=20?=
=?UTF-8?q?=E5=85=B3=E7=B3=BB=E8=A1=A8=E8=BE=BE=E5=BC=8F=20AST=20=E4=B8=A2?=
=?UTF-8?q?=E5=A4=B1=E9=83=A8=E5=88=86=E5=88=86=E6=94=AF=E5=8F=98=E9=87=8F?=
=?UTF-8?q?=E8=BF=BD=E8=B8=AA=E7=9A=84=E8=A7=A3=E6=9E=90=20Bug=20=20=202.?=
=?UTF-8?q?=20=E4=BF=AE=E5=A4=8D=20IRGenDecl=20=E4=B8=AD=E6=89=93=E6=96=AD?=
=?UTF-8?q?=E5=88=A4=E5=AE=9A=E7=BC=BA=E5=A4=B1=E5=AF=BC=E8=87=B4=E7=94=9F?=
=?UTF-8?q?=E6=88=90=E5=86=97=E4=BD=99=E6=AD=BB=E5=9D=97=E7=BB=88=E6=AD=A2?=
=?UTF-8?q?=E7=AC=A6=E7=9A=84=E9=97=AE=E9=A2=98=20=20=203.=20=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E4=B8=B4=E6=97=B6=E5=8F=98=E9=87=8F=E5=90=8D=E4=B8=BA?=
=?UTF-8?q?=20%tN=EF=BC=8C=E8=A7=A3=E5=86=B3=E7=BA=AF=E6=95=B0=E5=80=BC?=
=?UTF-8?q?=E6=A0=87=E5=8F=B7=E5=BC=95=E5=8F=91=E7=9A=84=20llc=20=E5=91=BD?=
=?UTF-8?q?=E5=90=8D=E5=BA=8F=E5=88=97=E6=A3=80=E6=9F=A5=E6=8A=A5=E9=94=99?=
=?UTF-8?q?=20-=20=E6=96=87=E6=A1=A3=E6=9B=B4=E6=96=B0=EF=BC=9A=E4=BA=8E?=
=?UTF-8?q?=20lab2=E5=89=A9=E4=BD=99=E4=BB=BB=E5=8A=A1=E5=88=86=E5=B7=A5.m?=
=?UTF-8?q?d=20=E4=B8=AD=E6=A0=87=E8=AE=B0=E7=9B=B8=E5=85=B3=E8=BF=9B?=
=?UTF-8?q?=E5=BA=A6=E4=B8=BA=E5=B7=B2=E5=AE=8C=E6=88=90=E5=B9=B6=E6=96=B0?=
=?UTF-8?q?=E5=A2=9E=E6=B5=8B=E8=AF=95=E8=BF=90=E8=A1=8C=E8=AF=B4=E6=98=8E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
doc/lab2剩余任务分工.md | 42 ++++++++++--
include/ir/IR.h | 44 +++++++++++-
include/irgen/IRGen.h | 15 ++++
patch_IR_h.patch | 83 ++++++++++++++++++++++
src/ir/Context.cpp | 2 +-
src/ir/IRBuilder.cpp | 40 +++++++++++
src/ir/IRPrinter.cpp | 73 +++++++++++++++++++-
src/ir/Instruction.cpp | 61 ++++++++++++++++-
src/ir/Type.cpp | 7 ++
src/ir/Value.cpp | 2 +
src/irgen/IRGenDecl.cpp | 9 +--
src/irgen/IRGenExp.cpp | 125 ++++++++++++++++++++++++++++++++++
src/irgen/IRGenStmt.cpp | 119 +++++++++++++++++++++++++++-----
src/sem/Sema.cpp | 8 +--
14 files changed, 594 insertions(+), 36 deletions(-)
create mode 100644 patch_IR_h.patch
diff --git a/doc/lab2剩余任务分工.md b/doc/lab2剩余任务分工.md
index 70e63de..8969726 100644
--- a/doc/lab2剩余任务分工.md
+++ b/doc/lab2剩余任务分工.md
@@ -5,7 +5,7 @@
- 任务 1.3:支持赋值表达式
- 任务 1.4:支持逗号分隔的多个变量声明
-### 人员 2:控制流支持
+### 人员 2:控制流支持(lyy,已完成)
- 任务 2.1:支持 if-else 条件语句
- 任务 2.2:支持 while 循环语句
@@ -19,10 +19,6 @@
- 任务 3.3:支持函数调用生成
- 任务 3.4:支持 const 常量声明
-
-
-
-
## 人员 1 完成情况详细说明(更新于 2026-03-30)
### ✅ 已完成任务
@@ -68,3 +64,39 @@
- **IR 构建**:`IRBuilder::CreateBinary`, `IRBuilder::CreateNeg`, `IRBuilder::CreateStore`
后续人员可以在此基础上扩展更复杂的功能(控制流、函数调用等)。
+
+## 人员 2 完成情况详细说明(更新于 2026-03-31)
+
+### ✅ 已完成任务
+
+人员 2 已完整实现 Lab2 IR 生成中涉及的控制流支持,包括:
+
+1. **IR 结构与底层辅助拓展**
+ - 补充 `Int1` 基础类型以及 `Value::IsInt1()`。
+ - 新增 `CmpInst`, `ZextInst`, `BranchInst` 以及 `CondBranchInst` 以支持关系计算和跳转逻辑。
+ - 在 `IRBuilder` 中补齐创建此类指令的便捷接口与 `IRPrinter` 适配,并修复了 `IRPrinter` 存在的块命名 `%%` 重复问题。
+ - 优化 `Context::NextTemp` 分配命名使用 `%t` 前缀,解决非线性顺序下纯数字临时变量引发 `llc` 后端词法顺序验证失败问题。
+2. **比较和逻辑表达式**(任务 2.4)
+ - 新增实现 `visitRelExp`、`visitEqExp`。
+ - 实现条件二元表达式全链路短路求值 (`visitLAndExp`、`visitLOrExp`)。短路时通过控制流跳转+利用局部栈变量分配并多次赋值记录实现栈传递,规避了 `phi` 的麻烦。
+ - 利用 `visitCondUnaryExp` 增加逻辑非 `!` 判定。
+3. **控制流框架支持**(任务 2.1 - 2.3)
+ - 在 `visitStmt` 中完美实现了 `if-else` 条件语句(自动插入无条件跳合块)、`while` 循环语句。
+ - 在 `IRGen` 实例中通过 `current_loop_cond_bb_` 等维护循环栈,实现了 `break` 与 `continue`。
+ - 修复了此前框架在 `IRGenDecl.cpp` 的 `visitBlock` 中缺少终结向上传递导致的 `break` 生成不匹配死块 BUG 及重复 `Branch` 问题。
+4. **关键前序 Bug 修复**
+ - 发现了在原框架里 `src/sem/Sema.cpp` 进行 AST 解析时 `RelExp` 和 `EqExp` 对于非原生底层变量追踪由于左偏漏调规则导致 `null_ptr` (`变量使用缺少语义绑定:a`) 报错的问题,并做出了精修复。
+
+### 🧪 测试验证
+
+- **Lab2 语义分析**:修复后所有已有的语义正例验证正常。
+- **IR 生成与后端执行**:✅ 自建嵌套含复合逻辑循环脚本测试通过。
+- **验证命令**(运行含 break 和 while 的范例文件):
+ ```bash
+ cd build && make -j$(nproc) && cd .. && ./scripts/verify_ir.sh test/test_case/functional/29_break.sy --run
+ ```
+
+ **完整测试脚本**
+ ```bash
+ for f in test/test_case/functional/*.sy; do echo "Testing $f..."; ./scripts/verify_ir.sh "$f" --run > /dev/null || echo "FAILED $f"; done
+ ```
\ No newline at end of file
diff --git a/include/ir/IR.h b/include/ir/IR.h
index 6af2d96..06f837f 100644
--- a/include/ir/IR.h
+++ b/include/ir/IR.h
@@ -93,16 +93,18 @@ class Context {
class Type {
public:
- enum class Kind { Void, Int32, PtrInt32 };
+ enum class Kind { Void, Int1, Int32, PtrInt32 };
explicit Type(Kind k);
// 使用静态共享对象获取类型。
// 同一类型可直接比较返回值是否相等,例如:
// Type::GetInt32Type() == Type::GetInt32Type()
static const std::shared_ptr& GetVoidType();
+ static const std::shared_ptr& GetInt1Type();
static const std::shared_ptr& GetInt32Type();
static const std::shared_ptr& GetPtrInt32Type();
Kind GetKind() const;
bool IsVoid() const;
+ bool IsInt1() const;
bool IsInt32() const;
bool IsPtrInt32() const;
@@ -118,6 +120,7 @@ class Value {
const std::string& GetName() const;
void SetName(std::string n);
bool IsVoid() const;
+ bool IsInt1() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsConstant() const;
@@ -153,7 +156,9 @@ class ConstantInt : public ConstantValue {
// 后续还需要扩展更多指令类型。
// enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
-enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret };
+enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret, Cmp, Zext, Br, CondBr };
+
+enum class CmpOp { Eq, Ne, Lt, Gt, Le, Ge };
// User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。
// 当前实现中只有 Instruction 继承自 User。
@@ -231,6 +236,37 @@ class StoreInst : public Instruction {
Value* GetPtr() const;
};
+class CmpInst : public Instruction {
+ public:
+ CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name);
+ CmpOp GetCmpOp() const;
+ Value* GetLhs() const;
+ Value* GetRhs() const;
+
+ private:
+ CmpOp cmp_op_;
+};
+
+class ZextInst : public Instruction {
+ public:
+ ZextInst(std::shared_ptr dest_ty, Value* val, std::string name);
+ Value* GetValue() const;
+};
+
+class BranchInst : public Instruction {
+ public:
+ BranchInst(BasicBlock* dest);
+ BasicBlock* GetDest() const;
+};
+
+class CondBranchInst : public Instruction {
+ public:
+ CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
+ Value* GetCond() const;
+ BasicBlock* GetTrueBlock() const;
+ BasicBlock* GetFalseBlock() const;
+};
+
// BasicBlock 已纳入 Value 体系,便于后续向更完整 IR 类图靠拢。
// 当前其类型仍使用 void 作为占位,后续可替换为专门的 label type。
class BasicBlock : public Value {
@@ -315,6 +351,10 @@ class IRBuilder {
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
ReturnInst* CreateRet(Value* v);
+ CmpInst* CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name);
+ ZextInst* CreateZext(Value* val, const std::string& name);
+ BranchInst* CreateBr(BasicBlock* dest);
+ CondBranchInst* CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
private:
Context& ctx_;
diff --git a/include/irgen/IRGen.h b/include/irgen/IRGen.h
index 2ed1c85..fec791a 100644
--- a/include/irgen/IRGen.h
+++ b/include/irgen/IRGen.h
@@ -37,6 +37,12 @@ class IRGenImpl final : public SysYBaseVisitor {
std::any visitAddExp(SysYParser::AddExpContext* ctx) override;
std::any visitMulExp(SysYParser::MulExpContext* ctx) override;
std::any visitUnaryExp(SysYParser::UnaryExpContext* ctx) override;
+ std::any visitRelExp(SysYParser::RelExpContext* ctx) override;
+ std::any visitEqExp(SysYParser::EqExpContext* ctx) override;
+ std::any visitLAndExp(SysYParser::LAndExpContext* ctx) override;
+ std::any visitLOrExp(SysYParser::LOrExpContext* ctx) override;
+ std::any visitCondUnaryExp(SysYParser::CondUnaryExpContext* ctx) override;
+ std::any visitCond(SysYParser::CondContext* ctx) override;
private:
enum class BlockFlow {
@@ -53,6 +59,15 @@ class IRGenImpl final : public SysYBaseVisitor {
ir::IRBuilder builder_;
// 名称绑定由 Sema 负责;IRGen 只维护"变量名 -> 存储槽位"的代码生成状态。
std::unordered_map storage_map_;
+
+ // 用于 break 和 continue 跳转的目标位置
+ ir::BasicBlock* current_loop_cond_bb_ = nullptr;
+ ir::BasicBlock* current_loop_exit_bb_ = nullptr;
+
+ int bb_cnt_ = 0;
+ std::string NextBlockName(const std::string& prefix = "bb") {
+ return prefix + "_" + std::to_string(++bb_cnt_);
+ }
};
std::unique_ptr GenerateIR(SysYParser::CompUnitContext& tree,
diff --git a/patch_IR_h.patch b/patch_IR_h.patch
new file mode 100644
index 0000000..c1a32ce
--- /dev/null
+++ b/patch_IR_h.patch
@@ -0,0 +1,83 @@
+--- include/ir/IR.h
++++ include/ir/IR.h
+@@ -93,6 +93,7 @@
+ class Type {
+ public:
+- enum class Kind { Void, Int32, PtrInt32 };
++ enum class Kind { Void, Int1, Int32, PtrInt32 };
+ explicit Type(Kind k);
+ // 使用静态共享对象获取类型。
+ // 同一类型可直接比较返回值是否相等,例如:
+ // Type::GetInt32Type() == Type::GetInt32Type()
+ static const std::shared_ptr& GetVoidType();
++ static const std::shared_ptr& GetInt1Type();
+ static const std::shared_ptr& GetInt32Type();
+ static const std::shared_ptr& GetPtrInt32Type();
+ Kind GetKind() const;
+ bool IsVoid() const;
++ bool IsInt1() const;
+ bool IsInt32() const;
+ bool IsPtrInt32() const;
+@@ -118,6 +119,7 @@
+ const std::string& GetName() const;
+ void SetName(std::string n);
+ bool IsVoid() const;
++ bool IsInt1() const;
+ bool IsInt32() const;
+ bool IsPtrInt32() const;
+ bool IsConstant() const;
+@@ -153,7 +155,9 @@
+
+ // 后续还需要扩展更多指令类型。
+-// enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
+-enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret };
++enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret, Cmp, Zext, Br, CondBr };
++
++enum class CmpOp { Eq, Ne, Lt, Gt, Le, Ge };
+
+ // User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。
+@@ -231,6 +235,33 @@
+ Value* GetPtr() const;
+ };
+
++class CmpInst : public Instruction {
++ public:
++ CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name);
++ CmpOp GetCmpOp() const;
++ Value* GetLhs() const;
++ Value* GetRhs() const;
++ private:
++ CmpOp cmp_op_;
++};
++
++class ZextInst : public Instruction {
++ public:
++ ZextInst(std::shared_ptr dest_ty, Value* val, std::string name);
++ Value* GetValue() const;
++};
++
++class BranchInst : public Instruction {
++ public:
++ BranchInst(BasicBlock* dest);
++ BasicBlock* GetDest() const;
++};
++
++class CondBranchInst : public Instruction {
++ public:
++ CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
++ Value* GetCond() const;
++ BasicBlock* GetTrueBlock() const;
++ BasicBlock* GetFalseBlock() const;
++};
++
+ // BasicBlock 已纳入 Value 体系,便于后续向更完整 IR 类图靠拢。
+@@ -315,6 +346,10 @@
+ LoadInst* CreateLoad(Value* ptr, const std::string& name);
+ StoreInst* CreateStore(Value* val, Value* ptr);
+ ReturnInst* CreateRet(Value* v);
++ CmpInst* CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name);
++ ZextInst* CreateZext(Value* val, const std::string& name);
++ BranchInst* CreateBr(BasicBlock* dest);
++ CondBranchInst* CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
+
+ private:
diff --git a/src/ir/Context.cpp b/src/ir/Context.cpp
index 16c982c..5f32c65 100644
--- a/src/ir/Context.cpp
+++ b/src/ir/Context.cpp
@@ -17,7 +17,7 @@ ConstantInt* Context::GetConstInt(int v) {
std::string Context::NextTemp() {
std::ostringstream oss;
- oss << "%" << ++temp_index_;
+ oss << "%t" << ++temp_index_;
return oss.str();
}
diff --git a/src/ir/IRBuilder.cpp b/src/ir/IRBuilder.cpp
index 54cc5d2..3569ab6 100644
--- a/src/ir/IRBuilder.cpp
+++ b/src/ir/IRBuilder.cpp
@@ -104,4 +104,44 @@ UnaryInst* IRBuilder::CreateNeg(Value* operand, const std::string& name) {
return insert_block_->Append(Opcode::Neg, Type::GetInt32Type(), operand, name);
}
+CmpInst* IRBuilder::CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name) {
+ if (!insert_block_) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
+ }
+ if (!lhs || !rhs) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCmp 缺少操作数"));
+ }
+ return insert_block_->Append(op, lhs, rhs, name);
+}
+
+ZextInst* IRBuilder::CreateZext(Value* val, const std::string& name) {
+ if (!insert_block_) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
+ }
+ if (!val) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder::CreateZext 缺少操作数"));
+ }
+ return insert_block_->Append(Type::GetInt32Type(), val, name);
+}
+
+BranchInst* IRBuilder::CreateBr(BasicBlock* dest) {
+ if (!insert_block_) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
+ }
+ if (!dest) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder::CreateBr 缺少操作数"));
+ }
+ return insert_block_->Append(dest);
+}
+
+CondBranchInst* IRBuilder::CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb) {
+ if (!insert_block_) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
+ }
+ if (!cond || !true_bb || !false_bb) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCondBr 缺少操作数"));
+ }
+ return insert_block_->Append(cond, true_bb, false_bb);
+}
+
} // namespace ir
diff --git a/src/ir/IRPrinter.cpp b/src/ir/IRPrinter.cpp
index 3716751..40cfc77 100644
--- a/src/ir/IRPrinter.cpp
+++ b/src/ir/IRPrinter.cpp
@@ -16,6 +16,8 @@ static const char* TypeToString(const Type& ty) {
switch (ty.GetKind()) {
case Type::Kind::Void:
return "void";
+ case Type::Kind::Int1:
+ return "i1";
case Type::Kind::Int32:
return "i32";
case Type::Kind::PtrInt32:
@@ -46,6 +48,31 @@ static const char* OpcodeToString(Opcode op) {
return "store";
case Opcode::Ret:
return "ret";
+ case Opcode::Cmp:
+ return "icmp";
+ case Opcode::Zext:
+ return "zext";
+ case Opcode::Br:
+ case Opcode::CondBr:
+ return "br";
+ }
+ return "?";
+}
+
+static const char* CmpOpToString(CmpOp op) {
+ switch (op) {
+ case CmpOp::Eq:
+ return "eq";
+ case CmpOp::Ne:
+ return "ne";
+ case CmpOp::Lt:
+ return "slt";
+ case CmpOp::Gt:
+ return "sgt";
+ case CmpOp::Le:
+ return "sle";
+ case CmpOp::Ge:
+ return "sge";
}
return "?";
}
@@ -57,6 +84,21 @@ static std::string ValueToString(const Value* v) {
return v ? v->GetName() : "";
}
+static std::string PrintLabel(const Value* bb) {
+ if (!bb) return "";
+ std::string name = bb->GetName();
+ if (name.empty()) return "";
+ if (name[0] == '%') return name;
+ return "%" + name;
+}
+
+static std::string PrintLabelDef(const Value* bb) {
+ if (!bb) return "";
+ std::string name = bb->GetName();
+ if (!name.empty() && name[0] == '%') return name.substr(1);
+ return name;
+}
+
void IRPrinter::Print(const Module& module, std::ostream& os) {
for (const auto& func : module.GetFunctions()) {
os << "define " << TypeToString(*func->GetType()) << " @" << func->GetName()
@@ -65,7 +107,7 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
if (!bb) {
continue;
}
- os << bb->GetName() << ":\n";
+ os << PrintLabelDef(bb.get()) << ":\n";
for (const auto& instPtr : bb->GetInstructions()) {
const auto* inst = instPtr.get();
switch (inst->GetOpcode()) {
@@ -113,6 +155,35 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
<< ValueToString(ret->GetValue()) << "\n";
break;
}
+ case Opcode::Cmp: {
+ auto* cmp = static_cast(inst);
+ os << " " << cmp->GetName() << " = icmp "
+ << CmpOpToString(cmp->GetCmpOp()) << " "
+ << TypeToString(*cmp->GetLhs()->GetType()) << " "
+ << ValueToString(cmp->GetLhs()) << ", "
+ << ValueToString(cmp->GetRhs()) << "\n";
+ break;
+ }
+ case Opcode::Zext: {
+ auto* zext = static_cast(inst);
+ os << " " << zext->GetName() << " = zext "
+ << TypeToString(*zext->GetOperand(0)->GetType()) << " "
+ << ValueToString(zext->GetOperand(0)) << " to "
+ << TypeToString(*zext->GetType()) << "\n";
+ break;
+ }
+ case Opcode::Br: {
+ auto* br = static_cast(inst);
+ os << " br label " << PrintLabel(br->GetDest()) << "\n";
+ break;
+ }
+ case Opcode::CondBr: {
+ auto* cbr = static_cast(inst);
+ os << " br i1 " << ValueToString(cbr->GetCond())
+ << ", label " << PrintLabel(cbr->GetTrueBlock())
+ << ", label " << PrintLabel(cbr->GetFalseBlock()) << "\n";
+ break;
+ }
}
}
}
diff --git a/src/ir/Instruction.cpp b/src/ir/Instruction.cpp
index 199b123..9ae696c 100644
--- a/src/ir/Instruction.cpp
+++ b/src/ir/Instruction.cpp
@@ -52,7 +52,7 @@ Instruction::Instruction(Opcode op, std::shared_ptr ty, std::string name)
Opcode Instruction::GetOpcode() const { return opcode_; }
-bool Instruction::IsTerminator() const { return opcode_ == Opcode::Ret; }
+bool Instruction::IsTerminator() const { return opcode_ == Opcode::Ret || opcode_ == Opcode::Br || opcode_ == Opcode::CondBr; }
BasicBlock* Instruction::GetParent() const { return parent_; }
@@ -172,4 +172,63 @@ Value* StoreInst::GetValue() const { return GetOperand(0); }
Value* StoreInst::GetPtr() const { return GetOperand(1); }
+CmpInst::CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name)
+ : Instruction(Opcode::Cmp, Type::GetInt1Type(), std::move(name)), cmp_op_(cmp_op) {
+ if (!lhs || !rhs) {
+ throw std::runtime_error(FormatError("ir", "CmpInst 缺少操作数"));
+ }
+ if (!lhs->GetType() || !rhs->GetType()) {
+ throw std::runtime_error(FormatError("ir", "CmpInst 缺少操作数类型信息"));
+ }
+ if (lhs->GetType()->GetKind() != rhs->GetType()->GetKind()) {
+ throw std::runtime_error(FormatError("ir", "CmpInst 操作数类型不匹配"));
+ }
+ AddOperand(lhs);
+ AddOperand(rhs);
+}
+
+CmpOp CmpInst::GetCmpOp() const { return cmp_op_; }
+Value* CmpInst::GetLhs() const { return GetOperand(0); }
+Value* CmpInst::GetRhs() const { return GetOperand(1); }
+
+ZextInst::ZextInst(std::shared_ptr dest_ty, Value* val, std::string name)
+ : Instruction(Opcode::Zext, std::move(dest_ty), std::move(name)) {
+ if (!val) {
+ throw std::runtime_error(FormatError("ir", "ZextInst 缺少操作数"));
+ }
+ if (!type_->IsInt32() || !val->GetType()->IsInt1()) {
+ throw std::runtime_error(FormatError("ir", "ZextInst 当前只支持 i1 到 i32"));
+ }
+ AddOperand(val);
+}
+
+Value* ZextInst::GetValue() const { return GetOperand(0); }
+
+BranchInst::BranchInst(BasicBlock* dest)
+ : Instruction(Opcode::Br, Type::GetVoidType(), "") {
+ if (!dest) {
+ throw std::runtime_error(FormatError("ir", "BranchInst 缺少目的块"));
+ }
+ AddOperand(dest);
+}
+
+BasicBlock* BranchInst::GetDest() const { return static_cast(GetOperand(0)); }
+
+CondBranchInst::CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb)
+ : Instruction(Opcode::CondBr, Type::GetVoidType(), "") {
+ if (!cond || !true_bb || !false_bb) {
+ throw std::runtime_error(FormatError("ir", "CondBranchInst 缺少连边操作数"));
+ }
+ if (!cond->GetType()->IsInt1()) {
+ throw std::runtime_error(FormatError("ir", "CondBranchInst 必须使用 i1 作为条件"));
+ }
+ AddOperand(cond);
+ AddOperand(true_bb);
+ AddOperand(false_bb);
+}
+
+Value* CondBranchInst::GetCond() const { return GetOperand(0); }
+BasicBlock* CondBranchInst::GetTrueBlock() const { return static_cast(GetOperand(1)); }
+BasicBlock* CondBranchInst::GetFalseBlock() const { return static_cast(GetOperand(2)); }
+
} // namespace ir
diff --git a/src/ir/Type.cpp b/src/ir/Type.cpp
index 3e1684d..c32d640 100644
--- a/src/ir/Type.cpp
+++ b/src/ir/Type.cpp
@@ -10,6 +10,11 @@ const std::shared_ptr& Type::GetVoidType() {
return type;
}
+const std::shared_ptr& Type::GetInt1Type() {
+ static const std::shared_ptr type = std::make_shared(Kind::Int1);
+ return type;
+}
+
const std::shared_ptr& Type::GetInt32Type() {
static const std::shared_ptr type = std::make_shared(Kind::Int32);
return type;
@@ -24,6 +29,8 @@ Type::Kind Type::GetKind() const { return kind_; }
bool Type::IsVoid() const { return kind_ == Kind::Void; }
+bool Type::IsInt1() const { return kind_ == Kind::Int1; }
+
bool Type::IsInt32() const { return kind_ == Kind::Int32; }
bool Type::IsPtrInt32() const { return kind_ == Kind::PtrInt32; }
diff --git a/src/ir/Value.cpp b/src/ir/Value.cpp
index 2e9f4c1..12a06b4 100644
--- a/src/ir/Value.cpp
+++ b/src/ir/Value.cpp
@@ -18,6 +18,8 @@ void Value::SetName(std::string n) { name_ = std::move(n); }
bool Value::IsVoid() const { return type_ && type_->IsVoid(); }
+bool Value::IsInt1() const { return type_ && type_->IsInt1(); }
+
bool Value::IsInt32() const { return type_ && type_->IsInt32(); }
bool Value::IsPtrInt32() const { return type_ && type_->IsPtrInt32(); }
diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp
index df7ccf9..1cd0db8 100644
--- a/src/irgen/IRGenDecl.cpp
+++ b/src/irgen/IRGenDecl.cpp
@@ -10,15 +10,16 @@ std::any IRGenImpl::visitBlock(SysYParser::BlockContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句块"));
}
+ bool terminated = false;
for (auto* item : ctx->blockItem()) {
if (item) {
if (VisitBlockItemResult(*item) == BlockFlow::Terminated) {
- // 当前语法要求 return 为块内最后一条语句;命中后可停止生成。
+ terminated = true;
break;
}
}
}
- return {};
+ return terminated ? BlockFlow::Terminated : BlockFlow::Continue;
}
IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult(
@@ -66,7 +67,7 @@ std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
var_def->accept(this);
}
}
- return {};
+ return BlockFlow::Continue;
}
@@ -102,5 +103,5 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
init = builder_.CreateConstInt(0);
}
builder_.CreateStore(init, slot);
- return {};
+ return BlockFlow::Continue;
}
diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp
index 55c3cc2..4565c6e 100644
--- a/src/irgen/IRGenExp.cpp
+++ b/src/irgen/IRGenExp.cpp
@@ -201,4 +201,129 @@ std::any IRGenImpl::visitMulExp(SysYParser::MulExpContext* ctx) {
return static_cast(
builder_.CreateBinary(op, lhs, rhs, module_.GetContext().NextTemp()));
+}
+
+std::any IRGenImpl::visitRelExp(SysYParser::RelExpContext* ctx) {
+ if (ctx->addExp() && ctx->relExp() == nullptr) {
+ return ctx->addExp()->accept(this);
+ }
+ ir::Value* lhs = std::any_cast(ctx->relExp()->accept(this));
+ ir::Value* rhs = std::any_cast(ctx->addExp()->accept(this));
+ if (lhs->GetType()->IsInt1()) lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp());
+ if (rhs->GetType()->IsInt1()) rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp());
+
+ ir::CmpOp op;
+ if (ctx->LT()) op = ir::CmpOp::Lt;
+ else if (ctx->GT()) op = ir::CmpOp::Gt;
+ else if (ctx->LE()) op = ir::CmpOp::Le;
+ else if (ctx->GE()) op = ir::CmpOp::Ge;
+ else throw std::runtime_error(FormatError("irgen", "未知的关系运算符"));
+
+ return static_cast(builder_.CreateCmp(op, lhs, rhs, module_.GetContext().NextTemp()));
+}
+
+std::any IRGenImpl::visitEqExp(SysYParser::EqExpContext* ctx) {
+ if (ctx->relExp() && ctx->eqExp() == nullptr) {
+ return ctx->relExp()->accept(this);
+ }
+ ir::Value* lhs = std::any_cast(ctx->eqExp()->accept(this));
+ ir::Value* rhs = std::any_cast(ctx->relExp()->accept(this));
+ if (lhs->GetType()->IsInt1()) lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp());
+ if (rhs->GetType()->IsInt1()) rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp());
+
+ ir::CmpOp op;
+ if (ctx->EQ()) op = ir::CmpOp::Eq;
+ else if (ctx->NE()) op = ir::CmpOp::Ne;
+ else throw std::runtime_error(FormatError("irgen", "未知的相等运算符"));
+
+ return static_cast(builder_.CreateCmp(op, lhs, rhs, module_.GetContext().NextTemp()));
+}
+
+std::any IRGenImpl::visitCondUnaryExp(SysYParser::CondUnaryExpContext* ctx) {
+ if (ctx->eqExp()) {
+ return ctx->eqExp()->accept(this);
+ }
+ if (ctx->NOT()) {
+ ir::Value* operand = std::any_cast(ctx->condUnaryExp()->accept(this));
+ if (operand->GetType()->IsInt1()) {
+ operand = builder_.CreateZext(operand, module_.GetContext().NextTemp());
+ }
+ ir::Value* zero = builder_.CreateConstInt(0);
+ return static_cast(builder_.CreateCmp(ir::CmpOp::Eq, operand, zero, module_.GetContext().NextTemp()));
+ }
+ throw std::runtime_error(FormatError("irgen", "非法条件一元表达式"));
+}
+
+std::any IRGenImpl::visitLAndExp(SysYParser::LAndExpContext* ctx) {
+ if (ctx->condUnaryExp() && ctx->lAndExp() == nullptr) {
+ return ctx->condUnaryExp()->accept(this);
+ }
+
+ ir::AllocaInst* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
+ ir::Value* zero = builder_.CreateConstInt(0);
+ builder_.CreateStore(zero, res_ptr);
+
+ ir::BasicBlock* rhs_bb = func_->CreateBlock(NextBlockName("land_rhs"));
+ ir::BasicBlock* end_bb = func_->CreateBlock(NextBlockName("land_end"));
+
+ ir::Value* lhs = std::any_cast(ctx->lAndExp()->accept(this));
+ if (lhs->GetType()->IsInt1()) {
+ lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp());
+ }
+ ir::Value* lhs_cond = builder_.CreateCmp(ir::CmpOp::Ne, lhs, zero, module_.GetContext().NextTemp());
+ builder_.CreateCondBr(lhs_cond, rhs_bb, end_bb);
+
+ builder_.SetInsertPoint(rhs_bb);
+ ir::Value* rhs = std::any_cast(ctx->condUnaryExp()->accept(this));
+ if (rhs->GetType()->IsInt1()) {
+ rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp());
+ }
+ ir::Value* rhs_cond = builder_.CreateCmp(ir::CmpOp::Ne, rhs, zero, module_.GetContext().NextTemp());
+ ir::Value* rhs_res = builder_.CreateZext(rhs_cond, module_.GetContext().NextTemp());
+ builder_.CreateStore(rhs_res, res_ptr);
+ builder_.CreateBr(end_bb);
+
+ builder_.SetInsertPoint(end_bb);
+ return static_cast(builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp()));
+}
+
+std::any IRGenImpl::visitLOrExp(SysYParser::LOrExpContext* ctx) {
+ if (ctx->lAndExp() && ctx->lOrExp() == nullptr) {
+ return ctx->lAndExp()->accept(this);
+ }
+
+ ir::AllocaInst* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
+ ir::Value* one = builder_.CreateConstInt(1);
+ builder_.CreateStore(one, res_ptr);
+
+ ir::BasicBlock* rhs_bb = func_->CreateBlock(NextBlockName("lor_rhs"));
+ ir::BasicBlock* end_bb = func_->CreateBlock(NextBlockName("lor_end"));
+
+ ir::Value* lhs = std::any_cast(ctx->lOrExp()->accept(this));
+ ir::Value* zero = builder_.CreateConstInt(0);
+ if (lhs->GetType()->IsInt1()) {
+ lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp());
+ }
+ ir::Value* lhs_cond = builder_.CreateCmp(ir::CmpOp::Eq, lhs, zero, module_.GetContext().NextTemp());
+ builder_.CreateCondBr(lhs_cond, rhs_bb, end_bb);
+
+ builder_.SetInsertPoint(rhs_bb);
+ ir::Value* rhs = std::any_cast(ctx->lAndExp()->accept(this));
+ if (rhs->GetType()->IsInt1()) {
+ rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp());
+ }
+ ir::Value* rhs_cond = builder_.CreateCmp(ir::CmpOp::Ne, rhs, zero, module_.GetContext().NextTemp());
+ ir::Value* rhs_res = builder_.CreateZext(rhs_cond, module_.GetContext().NextTemp());
+ builder_.CreateStore(rhs_res, res_ptr);
+ builder_.CreateBr(end_bb);
+
+ builder_.SetInsertPoint(end_bb);
+ return static_cast(builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp()));
+}
+
+std::any IRGenImpl::visitCond(SysYParser::CondContext* ctx) {
+ if (!ctx || !ctx->lOrExp()) {
+ throw std::runtime_error(FormatError("irgen", "非法条件表达式"));
+ }
+ return ctx->lOrExp()->accept(this);
}
\ No newline at end of file
diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp
index de6a857..e44bd0a 100644
--- a/src/irgen/IRGenStmt.cpp
+++ b/src/irgen/IRGenStmt.cpp
@@ -20,50 +20,133 @@ std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句"));
}
- // 检查是否是赋值语句:lVal ASSIGN exp SEMICOLON
if (ctx->lVal() && ctx->ASSIGN()) {
if (!ctx->exp()) {
throw std::runtime_error(FormatError("irgen", "赋值语句缺少表达式"));
}
-
- // 1. 计算右值表达式的值
ir::Value* rhs = EvalExpr(*ctx->exp());
-
- // 2. 找到左值变量对应的存储槽位
auto* lval_ctx = ctx->lVal();
if (!lval_ctx || !lval_ctx->ID()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量赋值"));
}
-
const auto* decl = sema_.ResolveObjectUse(lval_ctx);
if (!decl) {
throw std::runtime_error(
- FormatError("irgen",
- "变量使用缺少语义绑定:" + lval_ctx->ID()->getText()));
+ FormatError("irgen", "变量使用缺少语义绑定:" + lval_ctx->ID()->getText()));
}
-
std::string var_name = lval_ctx->ID()->getText();
auto it = storage_map_.find(var_name);
if (it == storage_map_.end()) {
throw std::runtime_error(
- FormatError("irgen",
- "变量声明缺少存储槽位:" + var_name));
+ FormatError("irgen", "变量声明缺少存储槽位:" + var_name));
}
-
- // 3. 生成 store 指令
builder_.CreateStore(rhs, it->second);
return BlockFlow::Continue;
}
- // 检查是否是 return 语句:RETURN exp? SEMICOLON
+ if (ctx->IF()) {
+ ir::Value* cond_val = std::any_cast(ctx->cond()->accept(this));
+ // cond_val must be i1, if it's not we need to check if it's != 0
+ if (cond_val->GetType()->IsInt32()) {
+ ir::Value* zero = builder_.CreateConstInt(0);
+ cond_val = builder_.CreateCmp(ir::CmpOp::Ne, cond_val, zero, module_.GetContext().NextTemp());
+ }
+
+ ir::BasicBlock* then_bb = func_->CreateBlock(NextBlockName("if_then"));
+ ir::BasicBlock* else_bb = ctx->ELSE() ? func_->CreateBlock(NextBlockName("if_else")) : nullptr;
+ ir::BasicBlock* merge_bb = func_->CreateBlock(NextBlockName("if_merge"));
+
+ builder_.CreateCondBr(cond_val, then_bb, else_bb ? else_bb : merge_bb);
+
+ builder_.SetInsertPoint(then_bb);
+ auto then_flow = std::any_cast(ctx->stmt(0)->accept(this));
+ if (then_flow == BlockFlow::Continue) {
+ builder_.CreateBr(merge_bb);
+ }
+
+ if (ctx->ELSE()) {
+ builder_.SetInsertPoint(else_bb);
+ auto else_flow = std::any_cast(ctx->stmt(1)->accept(this));
+ if (else_flow == BlockFlow::Continue) {
+ builder_.CreateBr(merge_bb);
+ }
+ }
+
+ builder_.SetInsertPoint(merge_bb);
+ return BlockFlow::Continue;
+ }
+
+ if (ctx->WHILE()) {
+ ir::BasicBlock* cond_bb = func_->CreateBlock(NextBlockName("while_cond"));
+ ir::BasicBlock* body_bb = func_->CreateBlock(NextBlockName("while_body"));
+ ir::BasicBlock* exit_bb = func_->CreateBlock(NextBlockName("while_exit"));
+
+ builder_.CreateBr(cond_bb);
+ builder_.SetInsertPoint(cond_bb);
+
+ ir::Value* cond_val = std::any_cast(ctx->cond()->accept(this));
+ if (cond_val->GetType()->IsInt32()) {
+ ir::Value* zero = builder_.CreateConstInt(0);
+ cond_val = builder_.CreateCmp(ir::CmpOp::Ne, cond_val, zero, module_.GetContext().NextTemp());
+ }
+ builder_.CreateCondBr(cond_val, body_bb, exit_bb);
+
+ builder_.SetInsertPoint(body_bb);
+ ir::BasicBlock* old_cond = current_loop_cond_bb_;
+ ir::BasicBlock* old_exit = current_loop_exit_bb_;
+ current_loop_cond_bb_ = cond_bb;
+ current_loop_exit_bb_ = exit_bb;
+
+ auto body_flow = std::any_cast(ctx->stmt(0)->accept(this));
+ if (body_flow == BlockFlow::Continue) {
+ builder_.CreateBr(cond_bb);
+ }
+
+ current_loop_cond_bb_ = old_cond;
+ current_loop_exit_bb_ = old_exit;
+
+ builder_.SetInsertPoint(exit_bb);
+ return BlockFlow::Continue;
+ }
+
+ if (ctx->BREAK()) {
+ if (!current_loop_exit_bb_) {
+ throw std::runtime_error(FormatError("irgen", "break 必须在循环内"));
+ }
+ builder_.CreateBr(current_loop_exit_bb_);
+ return BlockFlow::Terminated;
+ }
+
+ if (ctx->CONTINUE()) {
+ if (!current_loop_cond_bb_) {
+ throw std::runtime_error(FormatError("irgen", "continue 必须在循环内"));
+ }
+ builder_.CreateBr(current_loop_cond_bb_);
+ return BlockFlow::Terminated;
+ }
+
if (ctx->RETURN()) {
- if (!ctx->exp()) {
- throw std::runtime_error(FormatError("irgen", "return 缺少表达式"));
+ if (ctx->exp()) {
+ ir::Value* v = EvalExpr(*ctx->exp());
+ builder_.CreateRet(v);
+ } else {
+ throw std::runtime_error(FormatError("irgen", "暂不支持 void return"));
}
- ir::Value* v = EvalExpr(*ctx->exp());
- builder_.CreateRet(v);
return BlockFlow::Terminated;
}
+ if (ctx->block()) {
+ return ctx->block()->accept(this);
+ }
+
+ if (ctx->exp()) {
+ EvalExpr(*ctx->exp());
+ return BlockFlow::Continue;
+ }
+
+ if (ctx->SEMICOLON()) {
+ return BlockFlow::Continue;
+ }
+
throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型"));
}
diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp
index fc73f9d..95f0629 100644
--- a/src/sem/Sema.cpp
+++ b/src/sem/Sema.cpp
@@ -462,7 +462,7 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法关系表达式");
}
- if (ctx->addExp()) {
+ if (ctx->relExp() == nullptr) {
return EvalExpr(*ctx->addExp());
}
ExprInfo lhs = EvalExpr(*ctx->relExp());
@@ -474,7 +474,7 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法相等表达式");
}
- if (ctx->relExp()) {
+ if (ctx->eqExp() == nullptr) {
return EvalExpr(*ctx->relExp());
}
ExprInfo lhs = EvalExpr(*ctx->eqExp());
@@ -504,7 +504,7 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法逻辑与表达式");
}
- if (ctx->condUnaryExp()) {
+ if (ctx->lAndExp() == nullptr) {
return EvalExpr(*ctx->condUnaryExp());
}
ExprInfo lhs = EvalExpr(*ctx->lAndExp());
@@ -516,7 +516,7 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法逻辑或表达式");
}
- if (ctx->lAndExp()) {
+ if (ctx->lOrExp() == nullptr) {
return EvalExpr(*ctx->lAndExp());
}
ExprInfo lhs = EvalExpr(*ctx->lOrExp());