支持嵌套
This commit is contained in:
parent
9662e722a4
commit
f2f30b8d7b
@ -28,7 +28,7 @@ public class OperatorTokenScanner extends AbstractTokenScanner {
|
||||
*/
|
||||
@Override
|
||||
public boolean canHandle(char c, LexerContext ctx) {
|
||||
return "=!<>|&".indexOf(c) >= 0;
|
||||
return "=!<>|&%".indexOf(c) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,6 +84,10 @@ public class OperatorTokenScanner extends AbstractTokenScanner {
|
||||
type = TokenType.LESS_THAN;
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
lexeme = "%";
|
||||
type = TokenType.MODULO;
|
||||
break;
|
||||
case '&':
|
||||
if (ctx.match('&')) {
|
||||
lexeme = "&&";
|
||||
|
||||
@ -34,6 +34,9 @@ public enum TokenType {
|
||||
/** 赋值符号 "=" */
|
||||
EQUALS,
|
||||
|
||||
MODULO, // %
|
||||
|
||||
|
||||
/** 加号 "+" */
|
||||
PLUS,
|
||||
|
||||
|
||||
@ -4,11 +4,24 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* 表示 if 语句的 AST 节点。
|
||||
* 包含一个条件表达式和一个 then 分支的语句列表,不包含 else 分支。
|
||||
* 示例:{@code if (x > 0) { print(x); }}
|
||||
* 包含条件表达式、then 分支语句列表,以及可选的 else 分支。
|
||||
* 示例:
|
||||
* <pre>{@code
|
||||
* if (x > 0) {
|
||||
* print("Positive");
|
||||
* } else {
|
||||
* print("Negative");
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param condition 条件表达式,控制是否执行 then 分支。
|
||||
* @param thenBranch 条件为真时执行的语句列表。
|
||||
* @param condition 条件表达式,控制是否进入 thenBranch。
|
||||
* @param thenBranch 条件为真时执行的语句列表。
|
||||
* @param elseBranch 条件为假时执行的语句列表(可为空)。
|
||||
*/
|
||||
public record IfNode(ExpressionNode condition, List<StatementNode> thenBranch) implements StatementNode {
|
||||
public record IfNode(
|
||||
ExpressionNode condition,
|
||||
List<StatementNode> thenBranch,
|
||||
List<StatementNode> elseBranch
|
||||
) implements StatementNode {
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ public class PrattExpressionParser implements ExpressionParser {
|
||||
infixes.put("-", new BinaryOperatorParselet(Precedence.SUM, true));
|
||||
infixes.put("*", new BinaryOperatorParselet(Precedence.PRODUCT, true));
|
||||
infixes.put("/", new BinaryOperatorParselet(Precedence.PRODUCT, true));
|
||||
infixes.put("%", new BinaryOperatorParselet(Precedence.PRODUCT, true));
|
||||
infixes.put(">", new BinaryOperatorParselet(Precedence.SUM, true));
|
||||
infixes.put("<", new BinaryOperatorParselet(Precedence.SUM, true));
|
||||
infixes.put("==", new BinaryOperatorParselet(Precedence.SUM, true));
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
package org.jcnc.snow.compiler.parser.statement;
|
||||
|
||||
import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
import org.jcnc.snow.compiler.parser.ast.StatementNode;
|
||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||
import org.jcnc.snow.compiler.parser.factory.StatementParserFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BlockStatementParser {
|
||||
|
||||
public List<StatementNode> parse(ParserContext ctx, String endKeyword, String endSubKeyword) {
|
||||
List<StatementNode> statements = new ArrayList<>();
|
||||
|
||||
while (!isAtEnd(ctx, endKeyword, endSubKeyword)) {
|
||||
Token token = ctx.getTokens().peek();
|
||||
String keyword = (token.getType() == TokenType.KEYWORD) ? token.getLexeme() : "";
|
||||
|
||||
StatementParser parser = StatementParserFactory.get(keyword);
|
||||
statements.add(parser.parse(ctx));
|
||||
}
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
private boolean isAtEnd(ParserContext ctx, String kw1, String kw2) {
|
||||
if (ctx.getTokens().isAtEnd()) return true;
|
||||
Token t1 = ctx.getTokens().peek();
|
||||
Token t2 = ctx.getTokens().peek(1);
|
||||
return t1.getType() == TokenType.KEYWORD &&
|
||||
t1.getLexeme().equals(kw1) &&
|
||||
t2 != null &&
|
||||
t2.getType() == TokenType.KEYWORD &&
|
||||
t2.getLexeme().equals(kw2);
|
||||
}
|
||||
}
|
||||
@ -30,20 +30,26 @@ public class ExpressionStatementParser implements StatementParser {
|
||||
public StatementNode parse(ParserContext ctx) {
|
||||
TokenStream ts = ctx.getTokens();
|
||||
|
||||
// 检查是否是赋值形式(identifier = expr)
|
||||
// 空行或非法起始符号,提前退出(安全防护)
|
||||
if (ts.peek().getType() == TokenType.NEWLINE || ts.peek().getType() == TokenType.KEYWORD) {
|
||||
throw new IllegalStateException("Cannot parse expression starting with keyword: " + ts.peek().getLexeme());
|
||||
}
|
||||
|
||||
// 判断是否是赋值语句(形如:identifier = expr)
|
||||
if (ts.peek().getType() == TokenType.IDENTIFIER
|
||||
&& ts.peek(1).getLexeme().equals("=")) {
|
||||
|
||||
String varName = ts.next().getLexeme(); // 消费 identifier
|
||||
ts.expect("="); // 消费 '='
|
||||
String varName = ts.next().getLexeme(); // consume identifier
|
||||
ts.expect("="); // consume '='
|
||||
ExpressionNode value = new PrattExpressionParser().parse(ctx);
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
return new AssignmentNode(varName, value);
|
||||
}
|
||||
|
||||
// 否则解析为普通表达式语句
|
||||
// 普通表达式语句(如函数调用)
|
||||
ExpressionNode expr = new PrattExpressionParser().parse(ctx);
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
return new ExpressionStatementNode(expr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package org.jcnc.snow.compiler.parser.statement;
|
||||
|
||||
import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
import org.jcnc.snow.compiler.parser.ast.IfNode;
|
||||
import org.jcnc.snow.compiler.parser.ast.StatementNode;
|
||||
@ -11,45 +12,79 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* if 语句解析器,支持基本格式:
|
||||
* if 语句解析器,支持:
|
||||
* <pre>{@code
|
||||
* if condition then
|
||||
* statements...
|
||||
* else
|
||||
* statements...
|
||||
* end if
|
||||
* }</pre>
|
||||
* 不支持 else 分支,仅支持 then 分支。
|
||||
*/
|
||||
public class IfStatementParser implements StatementParser {
|
||||
|
||||
/**
|
||||
* 解析 if 表达式,并构造 {@link IfNode}。
|
||||
*
|
||||
* @param ctx 当前解析上下文。
|
||||
* @return 表示 if 语句的 AST 节点。
|
||||
*/
|
||||
@Override
|
||||
public IfNode parse(ParserContext ctx) {
|
||||
ctx.getTokens().expect("if");
|
||||
var ts = ctx.getTokens();
|
||||
|
||||
ts.expect("if");
|
||||
|
||||
// 解析条件表达式
|
||||
var cond = new PrattExpressionParser().parse(ctx);
|
||||
|
||||
ctx.getTokens().expect("then");
|
||||
ctx.getTokens().expectType(TokenType.NEWLINE);
|
||||
ts.expect("then");
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
|
||||
// 解析 then 分支的语句块
|
||||
List<StatementNode> thenBranch = new ArrayList<>();
|
||||
while (!ctx.getTokens().peek().getLexeme().equals("end")) {
|
||||
String keyword = ctx.getTokens().peek().getLexeme();
|
||||
List<StatementNode> elseBranch = new ArrayList<>();
|
||||
|
||||
// --- THEN 分支 ---
|
||||
while (true) {
|
||||
Token peek = ts.peek();
|
||||
|
||||
// 跳过空行
|
||||
if (peek.getType() == TokenType.NEWLINE) {
|
||||
ts.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (peek.getType() == TokenType.KEYWORD &&
|
||||
(peek.getLexeme().equals("else") || peek.getLexeme().equals("end"))) {
|
||||
break;
|
||||
}
|
||||
|
||||
String keyword = peek.getType() == TokenType.KEYWORD ? peek.getLexeme() : "";
|
||||
StatementNode stmt = StatementParserFactory.get(keyword).parse(ctx);
|
||||
thenBranch.add(stmt);
|
||||
}
|
||||
|
||||
// 匹配 end if 结束语句
|
||||
ctx.getTokens().expect("end");
|
||||
ctx.getTokens().expect("if");
|
||||
ctx.getTokens().expectType(TokenType.NEWLINE);
|
||||
// --- ELSE 分支 ---
|
||||
if (ts.peek().getLexeme().equals("else")) {
|
||||
ts.next(); // consume 'else'
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
|
||||
return new IfNode(cond, thenBranch);
|
||||
while (true) {
|
||||
Token peek = ts.peek();
|
||||
|
||||
if (peek.getType() == TokenType.NEWLINE) {
|
||||
ts.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (peek.getType() == TokenType.KEYWORD && peek.getLexeme().equals("end")) {
|
||||
break;
|
||||
}
|
||||
|
||||
String keyword = peek.getType() == TokenType.KEYWORD ? peek.getLexeme() : "";
|
||||
StatementNode stmt = StatementParserFactory.get(keyword).parse(ctx);
|
||||
elseBranch.add(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
ts.expect("end");
|
||||
ts.expect("if");
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
|
||||
return new IfNode(cond, thenBranch, elseBranch);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package org.jcnc.snow.compiler.parser.statement;
|
||||
|
||||
import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
import org.jcnc.snow.compiler.parser.ast.AssignmentNode;
|
||||
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
|
||||
@ -31,12 +32,6 @@ import java.util.List;
|
||||
*/
|
||||
public class LoopStatementParser implements StatementParser {
|
||||
|
||||
/**
|
||||
* 解析一个完整的 loop 语句块,返回 {@link LoopNode}。
|
||||
*
|
||||
* @param ctx 当前的解析上下文。
|
||||
* @return 表示 loop 结构的 AST 节点。
|
||||
*/
|
||||
@Override
|
||||
public LoopNode parse(ParserContext ctx) {
|
||||
TokenStream ts = ctx.getTokens();
|
||||
@ -61,8 +56,7 @@ public class LoopStatementParser implements StatementParser {
|
||||
ts.expect(":");
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
skipNewlines(ts);
|
||||
ExpressionNode condition =
|
||||
new PrattExpressionParser().parse(ctx);
|
||||
ExpressionNode condition = new PrattExpressionParser().parse(ctx);
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
skipNewlines(ts);
|
||||
|
||||
@ -71,6 +65,7 @@ public class LoopStatementParser implements StatementParser {
|
||||
ts.expect(":");
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
skipNewlines(ts);
|
||||
|
||||
String varName = ts.expectType(TokenType.IDENTIFIER).getLexeme();
|
||||
ts.expect("=");
|
||||
ExpressionNode updateExpr = new PrattExpressionParser().parse(ctx);
|
||||
@ -83,9 +78,18 @@ public class LoopStatementParser implements StatementParser {
|
||||
ts.expect(":");
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
skipNewlines(ts);
|
||||
|
||||
List<StatementNode> body = new ArrayList<>();
|
||||
while (!"end".equals(ts.peek().getLexeme())) {
|
||||
body.add(StatementParserFactory.get(ts.peek().getLexeme()).parse(ctx));
|
||||
while (!(ts.peek().getType() == TokenType.KEYWORD &&
|
||||
ts.peek().getLexeme().equals("end") &&
|
||||
ts.peek(1).getLexeme().equals("body"))) {
|
||||
|
||||
String keyword = ts.peek().getType() == TokenType.KEYWORD
|
||||
? ts.peek().getLexeme()
|
||||
: "";
|
||||
|
||||
StatementNode stmt = StatementParserFactory.get(keyword).parse(ctx);
|
||||
body.add(stmt);
|
||||
skipNewlines(ts);
|
||||
}
|
||||
|
||||
@ -104,9 +108,7 @@ public class LoopStatementParser implements StatementParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳过连续的 NEWLINE token,用于容错和格式整洁。
|
||||
*
|
||||
* @param ts 当前的 Token 流。
|
||||
* 跳过多余的换行,用于清理语法结构和容错。
|
||||
*/
|
||||
private void skipNewlines(TokenStream ts) {
|
||||
while (ts.peek().getType() == TokenType.NEWLINE) {
|
||||
|
||||
60
test
60
test
@ -1,11 +1,15 @@
|
||||
module: CommonTasks
|
||||
function: add_numbers
|
||||
|
||||
body:
|
||||
return num1 + num2
|
||||
end body
|
||||
|
||||
parameter:
|
||||
|
||||
declare num1: int
|
||||
declare num2: int
|
||||
|
||||
return_type: int
|
||||
|
||||
end function
|
||||
@ -49,34 +53,60 @@ module: MainModule
|
||||
end function
|
||||
|
||||
|
||||
function: main
|
||||
function: main
|
||||
parameter:
|
||||
declare args: string
|
||||
return_type: void
|
||||
body:
|
||||
declare input_number: int = BuiltinUtils.to_int(args)
|
||||
|
||||
if input_number <= 0 then
|
||||
input_number = 5
|
||||
end if
|
||||
|
||||
loop:
|
||||
initializer:
|
||||
declare counter: int = 5
|
||||
declare i: int = 0
|
||||
condition:
|
||||
counter > 0
|
||||
i < input_number
|
||||
update:
|
||||
counter = counter - 1
|
||||
i = i + 1
|
||||
body:
|
||||
BuiltinUtils.print(counter)
|
||||
if i % 2 == 0 then
|
||||
BuiltinUtils.print("i is even: " + BuiltinUtils.to_string(i))
|
||||
else
|
||||
BuiltinUtils.print("i is odd: " + BuiltinUtils.to_string(i))
|
||||
|
||||
loop:
|
||||
initializer:
|
||||
declare j: int = 0
|
||||
condition:
|
||||
j < i
|
||||
update:
|
||||
j = j + 1
|
||||
body:
|
||||
if j == 1 then
|
||||
BuiltinUtils.print(" first inner")
|
||||
else
|
||||
if j % 2 == 0 then
|
||||
BuiltinUtils.print(" j even")
|
||||
else
|
||||
BuiltinUtils.print(" j odd")
|
||||
end if
|
||||
end if
|
||||
end body
|
||||
end loop
|
||||
end if
|
||||
|
||||
declare sum: int = CommonTasks.add_numbers(i, 10)
|
||||
declare squared: int = MathUtils.square_number(sum)
|
||||
BuiltinUtils.print(" i+10 squared = " + BuiltinUtils.to_string(squared))
|
||||
end body
|
||||
end loop
|
||||
|
||||
declare input_number: int = BuiltinUtils.to_int(args)
|
||||
if input_number == 0 then
|
||||
input_number = 999
|
||||
end if
|
||||
|
||||
declare sum_result: int = CommonTasks.add_numbers(input_number, 20)
|
||||
|
||||
declare squared_result: int = MathUtils.square_number(sum_result)
|
||||
|
||||
declare final_message: string = StringUtils.concatenate("Result:",BuiltinUtils.to_string(squared_result))
|
||||
declare final_message: string = StringUtils.concatenate("Finished with input: ", BuiltinUtils.to_string(input_number))
|
||||
BuiltinUtils.print(final_message)
|
||||
end body
|
||||
end function
|
||||
|
||||
end module
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user