aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AGENTS/ARCH.md5
-rw-r--r--AGENTS/EXTENDING.md6
-rw-r--r--CMakeLists.txt2
-rw-r--r--lib/Parser/Parser.cc484
-rw-r--r--lib/Parser/ParserControlFlow.cc146
-rw-r--r--lib/Parser/ParserExpression.cc237
-rw-r--r--lib/Parser/ParserType.cc115
7 files changed, 506 insertions, 489 deletions
diff --git a/AGENTS/ARCH.md b/AGENTS/ARCH.md
index 216187f..1a3979c 100644
--- a/AGENTS/ARCH.md
+++ b/AGENTS/ARCH.md
@@ -260,10 +260,11 @@ do not modify the real release for local verification.
|---|---|
| `include/cps/` | All headers, included as `"cps/Foo.h"` |
| `lib/Lexer/Lexer.cc` | Entire lexer: one function, `Lexer::gettok()` |
-| `lib/Parser/Parser.cc` | Statements, expressions, designators, precedence table |
+| `lib/Parser/Parser.cc` | Entry point, statement dispatch, assignment parsing and error recovery |
+| `lib/Parser/ParserExpression.cc`, `ParserControlFlow.cc` | Expressions/designators and control-flow statement parsing |
| `lib/Parser/ParserFunction.cc` | FUNCTION/PROCEDURE/CALL/RETURN + parameter-list parsing |
| `lib/Parser/ParserFile.cc` | OPENFILE/READFILE/WRITEFILE/CLOSEFILE parsing |
-| `lib/Parser/ParserType.cc` | TYPE/ENDTYPE and CLASS/ENDCLASS declarations, shared field parsing, SET/DEFINE reserved stubs |
+| `lib/Parser/ParserType.cc` | Type names, variable/array declarations, TYPE/ENDTYPE and CLASS/ENDCLASS declarations, shared field parsing, SET/DEFINE reserved stubs |
| `lib/CodeGen/CodeGen.cc` | Hub: dispatch, coercion, control flow, INPUT/OUTPUT, main() |
| `lib/CodeGen/Designator.cc` | CodeGen methods for the TYPE system: type pre-pass, `emitLValue`/`loadFromLValue`, `emitCoercedExpr` gate, user-kind binary-op interception |
| `lib/CodeGen/CTypeGen.cc` | CodeGen methods for native C scalar conversions, casts, arithmetic and input/output |
diff --git a/AGENTS/EXTENDING.md b/AGENTS/EXTENDING.md
index a396867..b859c9d 100644
--- a/AGENTS/EXTENDING.md
+++ b/AGENTS/EXTENDING.md
@@ -6,8 +6,8 @@ below assumes those invariants.
**New statement:** token in `Lexer.h` enum + keyword match in `Lexer.cc`'s if-chain →
node class in `AST.h` or a feature header (`FunctionAST.h`/`FileAST.h` precedent;
unique_ptr children, move ctor, raw-ptr getters) → `ParseXxx` in
-`Parser.cc` + branch in `ParseStatementImpl` (block statements parse their body with
-`ParseBlock({terminator tokens})`; comma-separated expression lists use
+the matching `Parser*.cc` file + branch in `ParseStatementImpl` (block statements parse their body with
+`ParseBlock({terminator tokens})`; control-flow parsers live in `ParserControlFlow.cc`; comma-separated expression lists use
`ParseExprList(close, allowEmpty)`; add the new statement's leading keyword to
`syncToStatementStart`) → `dynamic_cast` branch in `CodeGen::emitStmt`. Guard every
fall-through branch in control-flow codegen with
@@ -32,7 +32,7 @@ STRING operands by pseudocode type then call `StringHandler::emitCompare`.
**New builtin type:** register in `TypeSystem::registerBuiltins` (sizes are derived —
never hand-written) + `TypeKind` case in the **exhaustive, default-less switches**:
`getZeroValue`, `coerceValueToType`, `emitOutputValue`, `TypeInfo::isOutputtable`,
-the INPUT branch in CodeGen + lexer keyword + `ParseTypeName` case. The compiler
+the INPUT branch in CodeGen + lexer keyword + `ParseTypeName` case in `ParserType.cc`. The compiler
warns on a missing enumerator — that is the anti-silent-fall-through mechanism;
never add a `default`.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9deae11..3a1d4b4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,6 +45,8 @@ include_directories(include)
add_library(CPSLexer STATIC lib/Lexer/Lexer.cc)
add_library(CPSParser STATIC
lib/Parser/Parser.cc
+ lib/Parser/ParserExpression.cc
+ lib/Parser/ParserControlFlow.cc
lib/Parser/ParserFunction.cc
lib/Parser/ParserFile.cc
lib/Parser/ParserType.cc
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc
index db2790b..3e8a096 100644
--- a/lib/Parser/Parser.cc
+++ b/lib/Parser/Parser.cc
@@ -28,258 +28,10 @@ Parser::Parser(Lexer &L) : Lex(L) {
BinopPrecedence[tok_mod] = 40;
}
-int Parser::GetTokPrecedence() {
- if (BinopPrecedence.find(CurTok) == BinopPrecedence.end()) return -1;
- int TokPrec = BinopPrecedence[CurTok];
- if (TokPrec <= 0) return -1;
- return TokPrec;
-}
-
int Parser::getNextToken() {
return CurTok = Lex.gettok();
}
-std::unique_ptr<ExprAST> Parser::ParseNumberExpr() {
- if (CurTok == tok_number_real) {
- auto Result = std::make_unique<RealExprAST>(Lex.RealVal);
- getNextToken();
- return Result;
- }
- auto Result = std::make_unique<IntegerExprAST>(Lex.NumVal);
- getNextToken();
- return Result;
-}
-
-std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() {
- std::string IdName = Lex.IdentifierStr;
- int Line = Lex.getLine();
- getNextToken();
-
- if (CurTok == '(') {
- getNextToken();
- auto Args = ParseExprList(')', true);
- if (!Args) return nullptr;
- if (CurTok == '[' || CurTok == '.' || CurTok == '^') {
- fprintf(stderr, "error: record/array/pointer access on a function result is not supported at line %d\n",
- Lex.getLine());
- return nullptr;
- }
- return std::make_unique<CallExprAST>(IdName, std::move(*Args), Line);
- }
-
- std::vector<DesignatorAccess> Accesses;
- if (!ParseDesignatorSuffix(Accesses)) return nullptr;
-
- // Degrade rule: shapes that existed before designators keep their nodes.
- if (Accesses.empty())
- return std::make_unique<VariableExprAST>(IdName);
- if (Accesses.size() == 1 && Accesses[0].Kind == AccessKind::Index)
- return std::make_unique<ArrayAccessExprAST>(IdName, std::move(Accesses[0].Indices), Line);
- return std::make_unique<DesignatorExprAST>(IdName, std::move(Accesses), Line);
-}
-
-// Postfix accessor chain after an identifier: '[' exprs ']' | '.' IDENT | '^'
-bool Parser::ParseDesignatorSuffix(std::vector<DesignatorAccess> &Out) {
- while (true) {
- if (CurTok == '[') {
- getNextToken();
- auto Indices = ParseExprList(']', false);
- if (!Indices) return false;
- DesignatorAccess A;
- A.Kind = AccessKind::Index;
- A.Indices = std::move(*Indices);
- Out.push_back(std::move(A));
- } else if (CurTok == '.') {
- getNextToken();
- if (CurTok != tok_identifier) {
- fprintf(stderr, "error: Expected field name after '.' at line %d\n", Lex.getLine());
- return false;
- }
- DesignatorAccess A;
- A.Kind = AccessKind::Field;
- A.FieldName = Lex.IdentifierStr;
- Out.push_back(std::move(A));
- getNextToken();
- } else if (CurTok == '^') {
- getNextToken();
- DesignatorAccess A;
- A.Kind = AccessKind::Deref;
- Out.push_back(std::move(A));
- } else {
- return true;
- }
- }
-}
-
-std::string Parser::ParseTypeName(bool AllowVoid) {
- switch (CurTok) {
- case tok_c_int: getNextToken(); return "C_INT";
- case tok_c_char: getNextToken(); return "C_CHAR";
- case tok_c_string: getNextToken(); return "C_STRING";
- case tok_c_double: getNextToken(); return "C_DOUBLE";
- default: break;
- }
- if (CurTok == tok_integer_kw) {
- getNextToken();
- return "INTEGER";
- }
- if (CurTok == tok_real_kw) {
- getNextToken();
- return "REAL";
- }
- if (CurTok == tok_boolean_kw) {
- getNextToken();
- return "BOOLEAN";
- }
- if (CurTok == tok_string_kw) {
- getNextToken();
- return "STRING";
- }
- if (CurTok == tok_char_kw) {
- getNextToken();
- return "CHAR";
- }
- if (CurTok == tok_identifier) {
- std::string TypeName = Lex.IdentifierStr;
- if (!AllowVoid && TypeName == "VOID") {
- fprintf(stderr, "error: VOID is not allowed here\n");
- return "";
- }
- getNextToken();
- return TypeName;
- }
-
- fprintf(stderr, "error: Unknown type name\n");
- return "";
-}
-
-std::unique_ptr<ExprAST> Parser::ParseParenExpr() {
- getNextToken();
- bool IsType = CurTok == tok_integer_kw || CurTok == tok_real_kw ||
- CurTok == tok_boolean_kw || CurTok == tok_string_kw || CurTok == tok_char_kw ||
- CurTok == tok_c_int || CurTok == tok_c_char || CurTok == tok_c_string ||
- CurTok == tok_c_double ||
- (CurTok == tok_identifier && TypeNames.count(Lex.IdentifierStr));
- if (IsType) {
- std::string TypeName = ParseTypeName();
- if (TypeName.empty()) return nullptr;
- if (CurTok != ')') {
- fprintf(stderr, "error: Expected ')' after cast type at line %d\n", Lex.getLine());
- return nullptr;
- }
- getNextToken();
- auto Operand = ParseUnary();
- if (!Operand) return nullptr;
- return std::make_unique<CastExprAST>(TypeName, std::move(Operand));
- }
- auto V = ParseExpression();
- if (!V) return nullptr;
- if (CurTok != ')') {
- fprintf(stderr, "error: expected ')'\n");
- return nullptr;
- }
- getNextToken();
- return V;
-}
-
-std::unique_ptr<ExprAST> Parser::ParsePrimary() {
- switch (CurTok) {
- case tok_identifier: return ParseIdentifierExpr();
- case tok_number_int: return ParseNumberExpr();
- case tok_number_real: return ParseNumberExpr();
- case tok_string_literal: {
- auto Res = std::make_unique<StringExprAST>(Lex.StringVal);
- getNextToken();
- return Res;
- }
- case tok_char_literal: {
- auto Res = std::make_unique<CharExprAST>(Lex.CharVal);
- getNextToken();
- return Res;
- }
- case tok_true: {
- getNextToken();
- return std::make_unique<BooleanExprAST>(true);
- }
- case tok_false: {
- getNextToken();
- return std::make_unique<BooleanExprAST>(false);
- }
- case '(': return ParseParenExpr();
- default:
- fprintf(stderr, "error: unknown token '%c' (%d) at line %d when expecting an expression\n",
- (char)CurTok, CurTok, Lex.getLine());
- return nullptr;
- }
-}
-
-std::unique_ptr<ExprAST> Parser::ParseUnary() {
- if (CurTok == tok_not) {
- getNextToken();
- auto Operand = ParseUnary();
- if (!Operand) return nullptr;
- return std::make_unique<UnaryExprAST>(tok_not, std::move(Operand));
- }
-
- // ^<designator> — address-of; the operand must be an lvalue shape.
- if (CurTok == '^') {
- int Line = Lex.getLine();
- getNextToken();
- if (CurTok != tok_identifier) {
- fprintf(stderr, "error: '^' (address-of) requires a variable, array element or record field at line %d\n",
- Line);
- return nullptr;
- }
- std::string BaseName = Lex.IdentifierStr;
- getNextToken();
- if (CurTok == '(') {
- fprintf(stderr, "error: cannot take the address of a function result at line %d\n", Line);
- return nullptr;
- }
- std::vector<DesignatorAccess> Accesses;
- if (!ParseDesignatorSuffix(Accesses)) return nullptr;
- auto Target = std::make_unique<DesignatorExprAST>(BaseName, std::move(Accesses), Line);
- return std::make_unique<AddrOfExprAST>(std::move(Target));
- }
-
- if (CurTok == '-') {
- getNextToken();
- auto Operand = ParseUnary();
- if (!Operand) return nullptr;
- return std::make_unique<UnaryExprAST>('-', std::move(Operand));
- }
-
- return ParsePrimary();
-}
-
-std::unique_ptr<ExprAST> Parser::ParseBinOpRHS(int ExprPrec, std::unique_ptr<ExprAST> LHS) {
- while (true) {
- int TokPrec = GetTokPrecedence();
- if (TokPrec < ExprPrec) return LHS;
-
- int BinOp = CurTok;
- int Line = Lex.getLine();
- getNextToken();
-
- auto RHS = ParseUnary();
- if (!RHS) return nullptr;
-
- int NextPrec = GetTokPrecedence();
- if (TokPrec < NextPrec) {
- RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS));
- if (!RHS) return nullptr;
- }
-
- LHS = std::make_unique<BinaryExprAST>(BinOp, std::move(LHS), std::move(RHS), Line);
- }
-}
-
-std::unique_ptr<ExprAST> Parser::ParseExpression() {
- auto LHS = ParseUnary();
- if (!LHS) return nullptr;
- return ParseBinOpRHS(0, std::move(LHS));
-}
-
std::vector<std::unique_ptr<StmtAST>> Parser::Parse() {
return ParseBlock({});
}
@@ -327,242 +79,6 @@ std::vector<std::unique_ptr<StmtAST>> Parser::ParseBlock(std::initializer_list<i
return Body;
}
-std::optional<std::vector<std::unique_ptr<ExprAST>>> Parser::ParseExprList(char CloseDelim, bool AllowEmpty) {
- std::vector<std::unique_ptr<ExprAST>> Elems;
- if (AllowEmpty && CurTok == CloseDelim) {
- getNextToken();
- return Elems;
- }
-
- while (true) {
- auto E = ParseExpression();
- if (!E) return std::nullopt;
- Elems.push_back(std::move(E));
-
- if (CurTok == CloseDelim) break;
- if (CurTok != ',') {
- fprintf(stderr, "error: Expected ',' or '%c' at line %d\n", CloseDelim, Lex.getLine());
- return std::nullopt;
- }
- getNextToken();
- }
- getNextToken();
- return Elems;
-}
-
-std::unique_ptr<StmtAST> Parser::ParseDeclare() {
- getNextToken();
- if (CurTok != tok_identifier) {
- fprintf(stderr, "error: Expected identifier after DECLARE at line %d\n", Lex.getLine());
- return nullptr;
- }
- std::string Name = Lex.IdentifierStr;
- getNextToken();
-
- if (CurTok != tok_colon) {
- fprintf(stderr, "error: Expected ':' after variable name '%s' at line %d\n", Name.c_str(), Lex.getLine());
- return nullptr;
- }
- getNextToken();
-
- if (CurTok == tok_array) {
- getNextToken();
- if (CurTok != '[') {
- fprintf(stderr, "error: Expected '[' after ARRAY\n");
- return nullptr;
- }
- getNextToken();
-
- std::vector<std::pair<std::unique_ptr<ExprAST>, std::unique_ptr<ExprAST>>> Bounds;
-
- while (true) {
- auto Lower = ParseExpression();
- if (!Lower) return nullptr;
-
- if (CurTok != tok_colon) {
- fprintf(stderr, "error: Expected ':' in array range (e.g. 1:10)\n");
- return nullptr;
- }
- getNextToken();
-
- auto Upper = ParseExpression();
- if (!Upper) return nullptr;
-
- Bounds.push_back({std::move(Lower), std::move(Upper)});
-
- if (CurTok == ']') break;
- if (CurTok == ',') {
- getNextToken();
- continue;
- }
- fprintf(stderr, "error: Expected ',' or ']' in array dims\n");
- return nullptr;
- }
- getNextToken();
-
- if (CurTok != tok_of) {
- fprintf(stderr, "error: Expected OF after array dims\n");
- return nullptr;
- }
- getNextToken();
-
- std::string TypeStr = ParseTypeName(false);
- if (TypeStr.empty()) {
- return nullptr;
- }
-
- return std::make_unique<ArrayDeclareStmtAST>(Name, std::move(Bounds), TypeStr);
- }
- else {
- std::string TypeStr = ParseTypeName(false);
- if (TypeStr.empty()) {
- return nullptr;
- }
- return std::make_unique<DeclareStmtAST>(Name, TypeStr);
- }
-}
-
-std::unique_ptr<StmtAST> Parser::ParseTryStmt() {
- getNextToken();
- auto Body = ParseBlock({tok_catch, tok_endtry});
- if (CurTok != tok_catch) {
- fprintf(stderr, "error: Expected CATCH in TRY at line %d\n", Lex.getLine());
- return nullptr;
- }
- getNextToken();
- auto CatchBody = ParseBlock({tok_endtry, tok_catch});
- if (CurTok != tok_endtry) {
- fprintf(stderr, "error: Expected ENDTRY after CATCH at line %d\n", Lex.getLine());
- return nullptr;
- }
- getNextToken();
- return std::make_unique<TryStmtAST>(std::move(Body), std::move(CatchBody));
-}
-
-std::unique_ptr<StmtAST> Parser::ParseIfStmt() {
- getNextToken();
- auto Cond = ParseExpression();
- if (!Cond) return nullptr;
-
- if (CurTok != tok_then) {
- fprintf(stderr, "error: expected THEN\n");
- return nullptr;
- }
- getNextToken();
-
- std::vector<std::unique_ptr<StmtAST>> ThenStmts = ParseBlock({tok_else, tok_endif});
-
- std::vector<std::unique_ptr<StmtAST>> ElseStmts;
- if (CurTok == tok_else) {
- getNextToken();
- ElseStmts = ParseBlock({tok_endif});
- }
-
- if (CurTok != tok_endif) {
- fprintf(stderr, "error: expected ENDIF\n");
- return nullptr;
- }
- getNextToken();
-
- return std::make_unique<IfStmtAST>(std::move(Cond), std::move(ThenStmts), std::move(ElseStmts));
-}
-
-std::unique_ptr<StmtAST> Parser::ParseWhileStmt() {
- getNextToken();
- auto Cond = ParseExpression();
- if (!Cond) return nullptr;
-
- if (CurTok != tok_do) {
- fprintf(stderr, "error: expected DO after WHILE condition\n");
- return nullptr;
- }
- getNextToken();
-
- std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_endwhile});
-
- if (CurTok != tok_endwhile) {
- fprintf(stderr, "error: expected ENDWHILE\n");
- return nullptr;
- }
- getNextToken();
-
- return std::make_unique<WhileStmtAST>(std::move(Cond), std::move(Body));
-}
-
-std::unique_ptr<StmtAST> Parser::ParseRepeatStmt() {
- getNextToken();
-
- std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_until});
-
- if (CurTok != tok_until) {
- fprintf(stderr, "error: expected UNTIL\n");
- return nullptr;
- }
- getNextToken();
-
- auto Cond = ParseExpression();
- if (!Cond) return nullptr;
-
- return std::make_unique<RepeatStmtAST>(std::move(Body), std::move(Cond));
-}
-
-std::unique_ptr<StmtAST> Parser::ParseForStmt() {
- getNextToken();
- if (CurTok != tok_identifier) {
- fprintf(stderr, "error: expected identifier after FOR\n");
- return nullptr;
- }
- std::string VarName = Lex.IdentifierStr;
- getNextToken();
-
- if (CurTok != tok_assign) {
- fprintf(stderr, "error: expected '<-' in FOR loop\n");
- return nullptr;
- }
- getNextToken();
-
- auto Start = ParseExpression();
- if (!Start) return nullptr;
-
- if (CurTok != tok_to) {
- fprintf(stderr, "error: expected TO in FOR loop\n");
- return nullptr;
- }
- getNextToken();
-
- auto End = ParseExpression();
- if (!End) return nullptr;
-
- std::unique_ptr<ExprAST> Step = nullptr;
- if (CurTok == tok_step) {
- getNextToken();
- Step = ParseExpression();
- if (!Step) return nullptr;
- }
-
- std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_next});
-
- if (CurTok != tok_next) {
- fprintf(stderr, "error: expected NEXT\n");
- return nullptr;
- }
- getNextToken();
-
- if (CurTok != tok_identifier) {
- fprintf(stderr, "error: expected identifier after NEXT (e.g., NEXT %s)\n", VarName.c_str());
- return nullptr;
- }
-
- if (Lex.IdentifierStr != VarName) {
- fprintf(stderr, "error: NEXT identifier '%s' does not match FOR variable '%s'\n",
- Lex.IdentifierStr.c_str(), VarName.c_str());
- return nullptr;
- }
- getNextToken();
-
- return std::make_unique<ForStmtAST>(VarName, std::move(Start), std::move(End), std::move(Step), std::move(Body));
-}
-
std::unique_ptr<StmtAST> Parser::ParseStatement() {
auto Stmt = ParseStatementImpl();
if (!Stmt) ++NumErrors;
diff --git a/lib/Parser/ParserControlFlow.cc b/lib/Parser/ParserControlFlow.cc
new file mode 100644
index 0000000..cb32466
--- /dev/null
+++ b/lib/Parser/ParserControlFlow.cc
@@ -0,0 +1,146 @@
+#include "cps/Parser.h"
+#include "cps/FunctionAST.h"
+#include <cstdio>
+
+using namespace cps;
+
+std::unique_ptr<StmtAST> Parser::ParseTryStmt() {
+ getNextToken();
+ auto Body = ParseBlock({tok_catch, tok_endtry});
+ if (CurTok != tok_catch) {
+ fprintf(stderr, "error: Expected CATCH in TRY at line %d\n", Lex.getLine());
+ return nullptr;
+ }
+ getNextToken();
+ auto CatchBody = ParseBlock({tok_endtry, tok_catch});
+ if (CurTok != tok_endtry) {
+ fprintf(stderr, "error: Expected ENDTRY after CATCH at line %d\n", Lex.getLine());
+ return nullptr;
+ }
+ getNextToken();
+ return std::make_unique<TryStmtAST>(std::move(Body), std::move(CatchBody));
+}
+
+std::unique_ptr<StmtAST> Parser::ParseIfStmt() {
+ getNextToken();
+ auto Cond = ParseExpression();
+ if (!Cond) return nullptr;
+
+ if (CurTok != tok_then) {
+ fprintf(stderr, "error: expected THEN\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ std::vector<std::unique_ptr<StmtAST>> ThenStmts = ParseBlock({tok_else, tok_endif});
+
+ std::vector<std::unique_ptr<StmtAST>> ElseStmts;
+ if (CurTok == tok_else) {
+ getNextToken();
+ ElseStmts = ParseBlock({tok_endif});
+ }
+
+ if (CurTok != tok_endif) {
+ fprintf(stderr, "error: expected ENDIF\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ return std::make_unique<IfStmtAST>(std::move(Cond), std::move(ThenStmts), std::move(ElseStmts));
+}
+
+std::unique_ptr<StmtAST> Parser::ParseWhileStmt() {
+ getNextToken();
+ auto Cond = ParseExpression();
+ if (!Cond) return nullptr;
+
+ if (CurTok != tok_do) {
+ fprintf(stderr, "error: expected DO after WHILE condition\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_endwhile});
+
+ if (CurTok != tok_endwhile) {
+ fprintf(stderr, "error: expected ENDWHILE\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ return std::make_unique<WhileStmtAST>(std::move(Cond), std::move(Body));
+}
+
+std::unique_ptr<StmtAST> Parser::ParseRepeatStmt() {
+ getNextToken();
+
+ std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_until});
+
+ if (CurTok != tok_until) {
+ fprintf(stderr, "error: expected UNTIL\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ auto Cond = ParseExpression();
+ if (!Cond) return nullptr;
+
+ return std::make_unique<RepeatStmtAST>(std::move(Body), std::move(Cond));
+}
+
+std::unique_ptr<StmtAST> Parser::ParseForStmt() {
+ getNextToken();
+ if (CurTok != tok_identifier) {
+ fprintf(stderr, "error: expected identifier after FOR\n");
+ return nullptr;
+ }
+ std::string VarName = Lex.IdentifierStr;
+ getNextToken();
+
+ if (CurTok != tok_assign) {
+ fprintf(stderr, "error: expected '<-' in FOR loop\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ auto Start = ParseExpression();
+ if (!Start) return nullptr;
+
+ if (CurTok != tok_to) {
+ fprintf(stderr, "error: expected TO in FOR loop\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ auto End = ParseExpression();
+ if (!End) return nullptr;
+
+ std::unique_ptr<ExprAST> Step = nullptr;
+ if (CurTok == tok_step) {
+ getNextToken();
+ Step = ParseExpression();
+ if (!Step) return nullptr;
+ }
+
+ std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_next});
+
+ if (CurTok != tok_next) {
+ fprintf(stderr, "error: expected NEXT\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ if (CurTok != tok_identifier) {
+ fprintf(stderr, "error: expected identifier after NEXT (e.g., NEXT %s)\n", VarName.c_str());
+ return nullptr;
+ }
+
+ if (Lex.IdentifierStr != VarName) {
+ fprintf(stderr, "error: NEXT identifier '%s' does not match FOR variable '%s'\n",
+ Lex.IdentifierStr.c_str(), VarName.c_str());
+ return nullptr;
+ }
+ getNextToken();
+
+ return std::make_unique<ForStmtAST>(VarName, std::move(Start), std::move(End), std::move(Step), std::move(Body));
+}
diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc
new file mode 100644
index 0000000..3e2665f
--- /dev/null
+++ b/lib/Parser/ParserExpression.cc
@@ -0,0 +1,237 @@
+#include "cps/Parser.h"
+#include "cps/FunctionAST.h"
+#include <cstdio>
+
+using namespace cps;
+
+int Parser::GetTokPrecedence() {
+ if (BinopPrecedence.find(CurTok) == BinopPrecedence.end()) return -1;
+ int TokPrec = BinopPrecedence[CurTok];
+ if (TokPrec <= 0) return -1;
+ return TokPrec;
+}
+
+
+std::unique_ptr<ExprAST> Parser::ParseNumberExpr() {
+ if (CurTok == tok_number_real) {
+ auto Result = std::make_unique<RealExprAST>(Lex.RealVal);
+ getNextToken();
+ return Result;
+ }
+ auto Result = std::make_unique<IntegerExprAST>(Lex.NumVal);
+ getNextToken();
+ return Result;
+}
+
+std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() {
+ std::string IdName = Lex.IdentifierStr;
+ int Line = Lex.getLine();
+ getNextToken();
+
+ if (CurTok == '(') {
+ getNextToken();
+ auto Args = ParseExprList(')', true);
+ if (!Args) return nullptr;
+ if (CurTok == '[' || CurTok == '.' || CurTok == '^') {
+ fprintf(stderr, "error: record/array/pointer access on a function result is not supported at line %d\n",
+ Lex.getLine());
+ return nullptr;
+ }
+ return std::make_unique<CallExprAST>(IdName, std::move(*Args), Line);
+ }
+
+ std::vector<DesignatorAccess> Accesses;
+ if (!ParseDesignatorSuffix(Accesses)) return nullptr;
+
+ // Degrade rule: shapes that existed before designators keep their nodes.
+ if (Accesses.empty())
+ return std::make_unique<VariableExprAST>(IdName);
+ if (Accesses.size() == 1 && Accesses[0].Kind == AccessKind::Index)
+ return std::make_unique<ArrayAccessExprAST>(IdName, std::move(Accesses[0].Indices), Line);
+ return std::make_unique<DesignatorExprAST>(IdName, std::move(Accesses), Line);
+}
+
+// Postfix accessor chain after an identifier: '[' exprs ']' | '.' IDENT | '^'
+bool Parser::ParseDesignatorSuffix(std::vector<DesignatorAccess> &Out) {
+ while (true) {
+ if (CurTok == '[') {
+ getNextToken();
+ auto Indices = ParseExprList(']', false);
+ if (!Indices) return false;
+ DesignatorAccess A;
+ A.Kind = AccessKind::Index;
+ A.Indices = std::move(*Indices);
+ Out.push_back(std::move(A));
+ } else if (CurTok == '.') {
+ getNextToken();
+ if (CurTok != tok_identifier) {
+ fprintf(stderr, "error: Expected field name after '.' at line %d\n", Lex.getLine());
+ return false;
+ }
+ DesignatorAccess A;
+ A.Kind = AccessKind::Field;
+ A.FieldName = Lex.IdentifierStr;
+ Out.push_back(std::move(A));
+ getNextToken();
+ } else if (CurTok == '^') {
+ getNextToken();
+ DesignatorAccess A;
+ A.Kind = AccessKind::Deref;
+ Out.push_back(std::move(A));
+ } else {
+ return true;
+ }
+ }
+}
+
+
+std::unique_ptr<ExprAST> Parser::ParseParenExpr() {
+ getNextToken();
+ bool IsType = CurTok == tok_integer_kw || CurTok == tok_real_kw ||
+ CurTok == tok_boolean_kw || CurTok == tok_string_kw || CurTok == tok_char_kw ||
+ CurTok == tok_c_int || CurTok == tok_c_char || CurTok == tok_c_string ||
+ CurTok == tok_c_double ||
+ (CurTok == tok_identifier && TypeNames.count(Lex.IdentifierStr));
+ if (IsType) {
+ std::string TypeName = ParseTypeName();
+ if (TypeName.empty()) return nullptr;
+ if (CurTok != ')') {
+ fprintf(stderr, "error: Expected ')' after cast type at line %d\n", Lex.getLine());
+ return nullptr;
+ }
+ getNextToken();
+ auto Operand = ParseUnary();
+ if (!Operand) return nullptr;
+ return std::make_unique<CastExprAST>(TypeName, std::move(Operand));
+ }
+ auto V = ParseExpression();
+ if (!V) return nullptr;
+ if (CurTok != ')') {
+ fprintf(stderr, "error: expected ')'\n");
+ return nullptr;
+ }
+ getNextToken();
+ return V;
+}
+
+std::unique_ptr<ExprAST> Parser::ParsePrimary() {
+ switch (CurTok) {
+ case tok_identifier: return ParseIdentifierExpr();
+ case tok_number_int: return ParseNumberExpr();
+ case tok_number_real: return ParseNumberExpr();
+ case tok_string_literal: {
+ auto Res = std::make_unique<StringExprAST>(Lex.StringVal);
+ getNextToken();
+ return Res;
+ }
+ case tok_char_literal: {
+ auto Res = std::make_unique<CharExprAST>(Lex.CharVal);
+ getNextToken();
+ return Res;
+ }
+ case tok_true: {
+ getNextToken();
+ return std::make_unique<BooleanExprAST>(true);
+ }
+ case tok_false: {
+ getNextToken();
+ return std::make_unique<BooleanExprAST>(false);
+ }
+ case '(': return ParseParenExpr();
+ default:
+ fprintf(stderr, "error: unknown token '%c' (%d) at line %d when expecting an expression\n",
+ (char)CurTok, CurTok, Lex.getLine());
+ return nullptr;
+ }
+}
+
+std::unique_ptr<ExprAST> Parser::ParseUnary() {
+ if (CurTok == tok_not) {
+ getNextToken();
+ auto Operand = ParseUnary();
+ if (!Operand) return nullptr;
+ return std::make_unique<UnaryExprAST>(tok_not, std::move(Operand));
+ }
+
+ // ^<designator> — address-of; the operand must be an lvalue shape.
+ if (CurTok == '^') {
+ int Line = Lex.getLine();
+ getNextToken();
+ if (CurTok != tok_identifier) {
+ fprintf(stderr, "error: '^' (address-of) requires a variable, array element or record field at line %d\n",
+ Line);
+ return nullptr;
+ }
+ std::string BaseName = Lex.IdentifierStr;
+ getNextToken();
+ if (CurTok == '(') {
+ fprintf(stderr, "error: cannot take the address of a function result at line %d\n", Line);
+ return nullptr;
+ }
+ std::vector<DesignatorAccess> Accesses;
+ if (!ParseDesignatorSuffix(Accesses)) return nullptr;
+ auto Target = std::make_unique<DesignatorExprAST>(BaseName, std::move(Accesses), Line);
+ return std::make_unique<AddrOfExprAST>(std::move(Target));
+ }
+
+ if (CurTok == '-') {
+ getNextToken();
+ auto Operand = ParseUnary();
+ if (!Operand) return nullptr;
+ return std::make_unique<UnaryExprAST>('-', std::move(Operand));
+ }
+
+ return ParsePrimary();
+}
+
+std::unique_ptr<ExprAST> Parser::ParseBinOpRHS(int ExprPrec, std::unique_ptr<ExprAST> LHS) {
+ while (true) {
+ int TokPrec = GetTokPrecedence();
+ if (TokPrec < ExprPrec) return LHS;
+
+ int BinOp = CurTok;
+ int Line = Lex.getLine();
+ getNextToken();
+
+ auto RHS = ParseUnary();
+ if (!RHS) return nullptr;
+
+ int NextPrec = GetTokPrecedence();
+ if (TokPrec < NextPrec) {
+ RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS));
+ if (!RHS) return nullptr;
+ }
+
+ LHS = std::make_unique<BinaryExprAST>(BinOp, std::move(LHS), std::move(RHS), Line);
+ }
+}
+
+std::unique_ptr<ExprAST> Parser::ParseExpression() {
+ auto LHS = ParseUnary();
+ if (!LHS) return nullptr;
+ return ParseBinOpRHS(0, std::move(LHS));
+}
+
+
+std::optional<std::vector<std::unique_ptr<ExprAST>>> Parser::ParseExprList(char CloseDelim, bool AllowEmpty) {
+ std::vector<std::unique_ptr<ExprAST>> Elems;
+ if (AllowEmpty && CurTok == CloseDelim) {
+ getNextToken();
+ return Elems;
+ }
+
+ while (true) {
+ auto E = ParseExpression();
+ if (!E) return std::nullopt;
+ Elems.push_back(std::move(E));
+
+ if (CurTok == CloseDelim) break;
+ if (CurTok != ',') {
+ fprintf(stderr, "error: Expected ',' or '%c' at line %d\n", CloseDelim, Lex.getLine());
+ return std::nullopt;
+ }
+ getNextToken();
+ }
+ getNextToken();
+ return Elems;
+}
diff --git a/lib/Parser/ParserType.cc b/lib/Parser/ParserType.cc
index de1f3ea..6c7703c 100644
--- a/lib/Parser/ParserType.cc
+++ b/lib/Parser/ParserType.cc
@@ -182,3 +182,118 @@ bool Parser::ParseRecordField(std::vector<RecordFieldDecl> &Out, bool IsPublic)
Out.push_back({FieldName, TypeName, IsPublic});
return true;
}
+
+std::string Parser::ParseTypeName(bool AllowVoid) {
+ switch (CurTok) {
+ case tok_c_int: getNextToken(); return "C_INT";
+ case tok_c_char: getNextToken(); return "C_CHAR";
+ case tok_c_string: getNextToken(); return "C_STRING";
+ case tok_c_double: getNextToken(); return "C_DOUBLE";
+ default: break;
+ }
+ if (CurTok == tok_integer_kw) {
+ getNextToken();
+ return "INTEGER";
+ }
+ if (CurTok == tok_real_kw) {
+ getNextToken();
+ return "REAL";
+ }
+ if (CurTok == tok_boolean_kw) {
+ getNextToken();
+ return "BOOLEAN";
+ }
+ if (CurTok == tok_string_kw) {
+ getNextToken();
+ return "STRING";
+ }
+ if (CurTok == tok_char_kw) {
+ getNextToken();
+ return "CHAR";
+ }
+ if (CurTok == tok_identifier) {
+ std::string TypeName = Lex.IdentifierStr;
+ if (!AllowVoid && TypeName == "VOID") {
+ fprintf(stderr, "error: VOID is not allowed here\n");
+ return "";
+ }
+ getNextToken();
+ return TypeName;
+ }
+
+ fprintf(stderr, "error: Unknown type name\n");
+ return "";
+}
+
+
+std::unique_ptr<StmtAST> Parser::ParseDeclare() {
+ getNextToken();
+ if (CurTok != tok_identifier) {
+ fprintf(stderr, "error: Expected identifier after DECLARE at line %d\n", Lex.getLine());
+ return nullptr;
+ }
+ std::string Name = Lex.IdentifierStr;
+ getNextToken();
+
+ if (CurTok != tok_colon) {
+ fprintf(stderr, "error: Expected ':' after variable name '%s' at line %d\n", Name.c_str(), Lex.getLine());
+ return nullptr;
+ }
+ getNextToken();
+
+ if (CurTok == tok_array) {
+ getNextToken();
+ if (CurTok != '[') {
+ fprintf(stderr, "error: Expected '[' after ARRAY\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ std::vector<std::pair<std::unique_ptr<ExprAST>, std::unique_ptr<ExprAST>>> Bounds;
+
+ while (true) {
+ auto Lower = ParseExpression();
+ if (!Lower) return nullptr;
+
+ if (CurTok != tok_colon) {
+ fprintf(stderr, "error: Expected ':' in array range (e.g. 1:10)\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ auto Upper = ParseExpression();
+ if (!Upper) return nullptr;
+
+ Bounds.push_back({std::move(Lower), std::move(Upper)});
+
+ if (CurTok == ']') break;
+ if (CurTok == ',') {
+ getNextToken();
+ continue;
+ }
+ fprintf(stderr, "error: Expected ',' or ']' in array dims\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ if (CurTok != tok_of) {
+ fprintf(stderr, "error: Expected OF after array dims\n");
+ return nullptr;
+ }
+ getNextToken();
+
+ std::string TypeStr = ParseTypeName(false);
+ if (TypeStr.empty()) {
+ return nullptr;
+ }
+
+ return std::make_unique<ArrayDeclareStmtAST>(Name, std::move(Bounds), TypeStr);
+ }
+ else {
+ std::string TypeStr = ParseTypeName(false);
+ if (TypeStr.empty()) {
+ return nullptr;
+ }
+ return std::make_unique<DeclareStmtAST>(Name, TypeStr);
+ }
+}