diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-16 13:21:05 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-16 13:21:05 +0000 |
| commit | e44bdc6a2a0cf624b08046ecc7e5c5d5d9d2d66c (patch) | |
| tree | f5276cc0dd2f34e4d30a58f80223912265a1c5a0 /lib/Parser | |
| parent | e1e789ac0249149a4aa1671f5f9260d488cb617a (diff) | |
fix(compiler): correct CIE semantics and diagnostic locations
Use standard WHILE headers and default-public class fields, resolve
pseudocode identifiers without case sensitivity, and check signed i64
literal boundaries before conversion. Preserve source locations across
recursive emission and function diagnostics.
Add 22 regression cases and update compiler examples and documentation.
Validated all 69 CTest entries with the original Linux Actions seed and
verified the release package's embedded, native and IR output paths.
Diffstat (limited to 'lib/Parser')
| -rw-r--r-- | lib/Parser/Parser.cc | 2 | ||||
| -rw-r--r-- | lib/Parser/ParserControlFlow.cc | 12 | ||||
| -rw-r--r-- | lib/Parser/ParserExpression.cc | 42 | ||||
| -rw-r--r-- | lib/Parser/ParserFunction.cc | 6 | ||||
| -rw-r--r-- | lib/Parser/ParserType.cc | 27 |
5 files changed, 63 insertions, 26 deletions
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc index d8fecdc..f2fcbc8 100644 --- a/lib/Parser/Parser.cc +++ b/lib/Parser/Parser.cc @@ -86,7 +86,9 @@ std::vector<std::unique_ptr<StmtAST>> Parser::ParseBlock(std::initializer_list<i } std::unique_ptr<StmtAST> Parser::ParseStatement() { + int Line = Lex.getLine(); auto Stmt = ParseStatementImpl(); + if (Stmt && !Stmt->getLine()) Stmt->setLine(Line); if (!Stmt) ++NumErrors; return Stmt; } diff --git a/lib/Parser/ParserControlFlow.cc b/lib/Parser/ParserControlFlow.cc index d01e561..afa8bd8 100644 --- a/lib/Parser/ParserControlFlow.cc +++ b/lib/Parser/ParserControlFlow.cc @@ -27,7 +27,7 @@ std::unique_ptr<StmtAST> Parser::ParseIfStmt() { if (!Cond) return nullptr; if (CurTok != tok_then) { - fprintf(stderr, "error: expected THEN\n"); + fprintf(stderr, "error: expected THEN at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -41,7 +41,7 @@ std::unique_ptr<StmtAST> Parser::ParseIfStmt() { } if (CurTok != tok_endif) { - fprintf(stderr, "error: expected ENDIF\n"); + fprintf(stderr, "error: expected ENDIF at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -54,12 +54,6 @@ std::unique_ptr<StmtAST> Parser::ParseWhileStmt() { 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) { @@ -135,7 +129,7 @@ std::unique_ptr<StmtAST> Parser::ParseForStmt() { return nullptr; } - if (Lex.IdentifierStr != VarName) { + if (!sameIdentifier(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; diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc index d32c407..b8952a8 100644 --- a/lib/Parser/ParserExpression.cc +++ b/lib/Parser/ParserExpression.cc @@ -1,6 +1,7 @@ #include "cps/Parser.h" #include "cps/FunctionAST.h" #include <cstdio> +#include <limits> using namespace cps; @@ -13,15 +14,29 @@ int Parser::GetTokPrecedence() { } +bool Parser::ParseIntegerValue(bool Negative, int64_t &Out) { + const uint64_t Max = uint64_t(std::numeric_limits<int64_t>::max()); + if (Lex.NumVal > Max + (Negative ? 1u : 0u)) { + fprintf(stderr, "error: Integer literal is outside the i64 range at line %d\n", Lex.getLine()); + getNextToken(); + return false; + } + Out = Negative && Lex.NumVal == Max + 1 + ? std::numeric_limits<int64_t>::min() + : Negative ? -static_cast<int64_t>(Lex.NumVal) : static_cast<int64_t>(Lex.NumVal); + getNextToken(); + return true; +} + 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; + int64_t Value; + if (!ParseIntegerValue(false, Value)) return nullptr; + return std::make_unique<IntegerExprAST>(Value); } std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { @@ -109,7 +124,7 @@ std::unique_ptr<ExprAST> Parser::ParseParenExpr() { auto V = ParseExpression(); if (!V) return nullptr; if (CurTok != ')') { - fprintf(stderr, "error: expected ')'\n"); + fprintf(stderr, "error: expected ')' at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -117,6 +132,13 @@ std::unique_ptr<ExprAST> Parser::ParseParenExpr() { } std::unique_ptr<ExprAST> Parser::ParsePrimary() { + int Line = Lex.getLine(); + auto Expr = ParsePrimaryImpl(); + if (Expr && !Expr->getLine()) Expr->setLine(Line); + return Expr; +} + +std::unique_ptr<ExprAST> Parser::ParsePrimaryImpl() { switch (CurTok) { case tok_identifier: return ParseIdentifierExpr(); case tok_number_int: return ParseNumberExpr(); @@ -148,6 +170,13 @@ std::unique_ptr<ExprAST> Parser::ParsePrimary() { } std::unique_ptr<ExprAST> Parser::ParseUnary() { + int Line = Lex.getLine(); + auto Expr = ParseUnaryImpl(); + if (Expr && !Expr->getLine()) Expr->setLine(Line); + return Expr; +} + +std::unique_ptr<ExprAST> Parser::ParseUnaryImpl() { if (CurTok == tok_not) { getNextToken(); auto Operand = ParseUnary(); @@ -178,6 +207,11 @@ std::unique_ptr<ExprAST> Parser::ParseUnary() { if (CurTok == '-') { getNextToken(); + if (CurTok == tok_number_int) { + int64_t Value; + if (!ParseIntegerValue(true, Value)) return nullptr; + return std::make_unique<IntegerExprAST>(Value); + } auto Operand = ParseUnary(); if (!Operand) return nullptr; return std::make_unique<UnaryExprAST>('-', std::move(Operand)); diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc index c47485e..fe53731 100644 --- a/lib/Parser/ParserFunction.cc +++ b/lib/Parser/ParserFunction.cc @@ -17,9 +17,7 @@ bool Parser::ParseSignedIntBound(int64_t &Out) { Lex.getLine()); return false; } - Out = Negative ? -Lex.NumVal : Lex.NumVal; - getNextToken(); - return true; + return ParseIntegerValue(Negative, Out); } // ( [BYREF|BYVAL] <name> : <type> @@ -107,7 +105,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef } for (const ParamDecl &Prev : Params) { - if (Prev.Name == P.Name) { + if (sameIdentifier(Prev.Name, P.Name)) { fprintf(stderr, "error: Duplicate parameter name '%s' at line %d\n", P.Name.c_str(), Lex.getLine()); return std::nullopt; diff --git a/lib/Parser/ParserType.cc b/lib/Parser/ParserType.cc index 918b7f6..a57c8a6 100644 --- a/lib/Parser/ParserType.cc +++ b/lib/Parser/ParserType.cc @@ -112,19 +112,19 @@ std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody( const char *Keyword = IsClass ? "CLASS" : "TYPE"; const char *EndKeyword = IsClass ? "ENDCLASS" : "ENDTYPE"; auto AtField = [&] { - return IsClass ? (CurTok == tok_public || CurTok == tok_private) + return IsClass ? (CurTok == tok_public || CurTok == tok_private || CurTok == tok_identifier) : CurTok == tok_declare; }; std::vector<RecordFieldDecl> Fields; bool HadFieldError = false; while (CurTok != EndToken && CurTok != tok_eof) { if (AtField()) { - // Record fields are always public; class fields have no default. - bool IsPublic = !IsClass || CurTok == tok_public; + // Class fields default to public, like record fields. + bool IsPublic = CurTok != tok_private; if (ParseRecordField(Fields, IsPublic)) continue; } else { fprintf(stderr, "error: Expected %s or %s in %s %s at line %d\n", - IsClass ? "PUBLIC or PRIVATE" : "DECLARE", EndKeyword, + IsClass ? "field, PUBLIC or PRIVATE" : "DECLARE", EndKeyword, Keyword, Name.c_str(), Lex.getLine()); } HadFieldError = true; @@ -155,7 +155,7 @@ std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody( bool Parser::ParseRecordField(std::vector<RecordFieldDecl> &Out, bool IsPublic) { const char *Introducer = CurTok == tok_declare ? "DECLARE" : CurTok == tok_public ? "PUBLIC" : "PRIVATE"; - getNextToken(); // eat field introducer + if (CurTok != tok_identifier) getNextToken(); // optional class access keyword if (CurTok != tok_identifier) { fprintf(stderr, "error: Expected field name after %s at line %d\n", Introducer, Lex.getLine()); return false; @@ -213,7 +213,7 @@ std::string Parser::ParseTypeName(bool AllowVoid) { } if (CurTok == tok_identifier) { std::string TypeName = Lex.IdentifierStr; - if (!AllowVoid && TypeName == "VOID") { + if (!AllowVoid && sameIdentifier(TypeName, "VOID")) { fprintf(stderr, "error: VOID is not allowed here\n"); return ""; } @@ -321,9 +321,18 @@ std::unique_ptr<StmtAST> Parser::ParseConstant() { fprintf(stderr, "error: CONSTANT initializer must be a literal at line %d\n", Line); return nullptr; } - auto Value = ParsePrimary(); - if (!Value) return nullptr; - if (Negative) Value = std::make_unique<UnaryExprAST>('-', std::move(Value)); + std::unique_ptr<ExprAST> Value; + if (CurTok == tok_number_int) { + int Line = Lex.getLine(); + int64_t Integer; + if (!ParseIntegerValue(Negative, Integer)) return nullptr; + Value = std::make_unique<IntegerExprAST>(Integer); + Value->setLine(Line); + } else { + Value = ParsePrimary(); + if (!Value) return nullptr; + if (Negative) Value = std::make_unique<UnaryExprAST>('-', std::move(Value)); + } if (GetTokPrecedence() >= 0) { fprintf(stderr, "error: CONSTANT initializer must be a literal, not an expression, at line %d\n", Line); return nullptr; |
