Compare commits

..

3 Commits

@ -0,0 +1,96 @@
#!/bin/bash
# 测试脚本
# 用法: ./run_tests.sh [--verbose] [<单个测试文件>]
COMPILER="./build/bin/compiler"
TEST_DIR="test/test_case"
RESULT_FILE="result.txt"
VERBOSE=0
# 解析参数
if [[ "$1" == "--verbose" ]]; then
VERBOSE=1
shift
fi
# 检查编译器是否存在
if [ ! -f "$COMPILER" ]; then
echo "错误: 编译器未找到于 $COMPILER"
echo "请先完成项目构建 (cmake 和 make)"
exit 1
fi
# 如果指定了单个文件,检查文件是否存在
if [ -n "$1" ] && [ ! -f "$1" ]; then
echo "错误: 文件 $1 不存在"
exit 1
fi
# 清空(或创建)结果文件
> "$RESULT_FILE"
# 计数器
total=0
passed=0
failed=0
echo "开始测试 SysY 解析..."
echo "输出将保存到 $RESULT_FILE"
echo "------------------------"
# 确定测试文件列表
if [ -n "$1" ]; then
# 使用提供的单个文件
TEST_FILES=("$1")
else
# 收集所有 .sy 文件
mapfile -t TEST_FILES < <(find "$TEST_DIR" -type f -name "*.sy" | sort)
fi
for file in "${TEST_FILES[@]}"; do
((total++))
if [ $VERBOSE -eq 1 ]; then
echo "测试文件: $file"
else
echo -n "测试 $file ... "
fi
echo "========== $file ==========" >> "$RESULT_FILE"
if [ $VERBOSE -eq 1 ]; then
"$COMPILER" --emit-parse-tree "$file" 2>&1 | tee -a "$RESULT_FILE"
result=${PIPESTATUS[0]}
else
"$COMPILER" --emit-parse-tree "$file" >> "$RESULT_FILE" 2>&1
result=$?
fi
echo "" >> "$RESULT_FILE"
if [ $result -eq 0 ]; then
if [ $VERBOSE -eq 0 ]; then
echo "通过"
fi
((passed++))
else
if [ $VERBOSE -eq 0 ]; then
echo "失败"
else
echo ">>> 解析失败: $file"
fi
((failed++))
fi
done
echo "------------------------"
echo "总计: $total"
echo "通过: $passed"
echo "失败: $failed"
echo "详细输出已保存至 $RESULT_FILE"
if [ $failed -gt 0 ]; then
exit 1
else
exit 0
fi

@ -1,68 +1,172 @@
// SysY 子集语法:支持形如 // SysY 子集语法
// int main() { int a = 1; int b = 2; return a + b; } grammar SysY;
// 的最小返回表达式编译。
// 后续需要自行添加 //----词法规则(优先级从高到低)----//
//keywords
Void : 'void';
Int : 'int';
Float : 'float';
Const : 'const';
If : 'if';
Else : 'else';
While : 'while';
Break : 'break';
Continue: 'continue';
Return : 'return';
grammar SysY; //Two-character operator (long preferred)
LeOp : '<=';
GeOp : '>=';
EqOp : '==';
NeOp : '!=';
AndOp : '&&';
OrOp : '||';
/*===-------------------------------------------===*/ //single character operators
/* Lexer rules */ AddOp : '+';
/*===-------------------------------------------===*/ SubOp : '-';
MulOp : '*';
DivOp : '/';
QuoOp : '%';
NotOp : '!';
LOp : '<';
GOp : '>';
Assign : '=';
INT: 'int'; //Separator
RETURN: 'return'; Semi : ';';
Comma : ',';
L_PAREN : '(';
R_PAREN : ')';
L_BRACK : '[';
R_BRACK : ']';
L_BRACE : '{';
R_BRACE : '}';
ASSIGN: '='; //const numeric classes
ADD: '+'; //Number... change
// float first
// 16进制float first
HEX_FLOAT
: '0' [xX](
// 形式1: 0x1.921fb6p+1 (有小数点和指数)
HEX_DIGIT* '.' HEX_DIGIT+ [pP] [+-]? DECIMAL_DIGIT+
| // 形式2: 0x1p+1 (没有小数点,只有指数)
HEX_DIGIT+ [pP] [+-]? DECIMAL_DIGIT+
| // 形式3: 0x.AP-3 (小数点开头)
'.' HEX_DIGIT+ [pP] [+-]? DECIMAL_DIGIT+
)
;
fragment HEX_DIGIT: [0-9a-fA-F];
fragment DECIMAL_DIGIT: [0-9];
LPAREN: '('; // 10进制float
RPAREN: ')'; DEC_FLOAT
LBRACE: '{'; : [0-9]+ '.' [0-9]* EXP? //1.2/1./1.2e10/...
RBRACE: '}'; | '.' [0-9]+ EXP? //.1/.1e2
SEMICOLON: ';'; | [0-9]+ EXP //1e2/1e-2
;
fragment EXP: [eE] [+-]? [0-9]+;
ID: [a-zA-Z_][a-zA-Z_0-9]*; HEX_INT: '0' [xX] [0-9a-fA-F]+; //16进制
ILITERAL: [0-9]+; OCTAL_INT: '0' [0-7]*; //8进制
DECIMAL_INT: [1-9][0-9]*; //10进制
ZERO: '0'; //单独0
WS: [ \t\r\n] -> skip; // TODO: 后续完善IR后移除Number兼容规则
LINECOMMENT: '//' ~[\r\n]* -> skip; Number
BLOCKCOMMENT: '/*' .*? '*/' -> skip; : HEX_FLOAT
| DEC_FLOAT
| HEX_INT
| OCTAL_INT
| DECIMAL_INT
| ZERO
;
// 标识符(放最后)
Ident
: [a-zA-Z_][a-zA-Z_0-9]*
;
/*===-------------------------------------------===*/ // 注释和空白
/* Syntax rules */ WS
/*===-------------------------------------------===*/ : [ \t\r\n]+ -> skip
;
COMMENT
: '//' ~[\r\n]* -> skip
;
BLOCK_COMMENT
: '/*' .*? '*/' -> skip
;
//----语法规则----//
compUnit compUnit
: funcDef EOF : (funcDef|decl|program) EOF
;
program
: (decl|funcDef)+
; ;
decl decl
: btype varDef SEMICOLON : varDecl
| constDecl
;
constDecl
: Const bType constDef (Comma constDef)* Semi
;
bType
: Int
| Float
; ;
btype constDef
: INT : Ident (L_BRACK constExp R_BRACK)* Assign constInitVal
;
constInitVal
: constExp
| L_BRACE (constInitVal (Comma constInitVal)*)? R_BRACE
;
varDecl
: bType varDef (Comma varDef)* Semi
| Int Ident (Assign exp)? Semi
; ;
varDef varDef
: lValue (ASSIGN initValue)? : Ident (L_BRACK constExp R_BRACK)* (Assign initVal)?
; ;
initValue initVal
: exp : exp
| L_BRACE (initVal (Comma initVal)*)? R_BRACE
; ;
funcDef funcDef
: funcType ID LPAREN RPAREN blockStmt : funcType Ident L_PAREN (funcFParams)? R_PAREN block
; ;
funcType funcType
: INT : Void
| Int
| Float
;
funcFParams
: funcFParam (Comma funcFParam)*
;
funcFParam
: bType Ident (L_BRACK R_BRACK (L_BRACK exp R_BRACK)*)?
; ;
blockStmt block
: LBRACE blockItem* RBRACE : L_BRACE (blockItem)* R_BRACE
; ;
blockItem blockItem
@ -71,28 +175,92 @@ blockItem
; ;
stmt stmt
: returnStmt : lVal Assign exp Semi
| (exp)? Semi
| block
| If L_PAREN cond R_PAREN stmt (Else stmt)?
| While L_PAREN cond R_PAREN stmt
| Break Semi
| Continue Semi
| returnStmt
; ;
returnStmt returnStmt
: RETURN exp SEMICOLON : Return (exp)? Semi
; ;
exp exp
: LPAREN exp RPAREN # parenExp : addExp
| var # varExp ;
| number # numberExp
| exp ADD exp # additiveExp cond
: lOrExp
;
lVal
: Ident (L_BRACK exp R_BRACK)*
;
primary
: L_PAREN exp R_PAREN
| lVal
| Number // 让旧代码能用
| HEX_FLOAT
| DEC_FLOAT
| HEX_INT
| OCTAL_INT
| DECIMAL_INT
| ZERO
| Ident
;
unaryExp
: primary
| Ident L_PAREN (funcRParams)? R_PAREN
| unaryOp unaryExp
; ;
var unaryOp
: ID : AddOp
| SubOp
| NotOp
; ;
lValue funcRParams
: ID : exp (Comma exp)*
; ;
number mulExp
: ILITERAL : unaryExp
| mulExp (MulOp|DivOp|QuoOp) unaryExp
; ;
addExp
: mulExp
| addExp (AddOp|SubOp) mulExp
| primary (AddOp primary)*
;
relExp
: addExp
| relExp (LOp|GOp|LeOp|GeOp) addExp
;
eqExp
: relExp
| eqExp (EqOp|NeOp) relExp
;
lAndExp
: eqExp
| lAndExp AndOp eqExp
;
lOrExp
: lAndExp
| lOrExp OrOp lAndExp
;
constExp
: addExp
;
Loading…
Cancel
Save