From db6ac29d0ac769ff780f3901ed987b97965f3f5e Mon Sep 17 00:00:00 2001 From: _ov4 Date: Fri, 16 Oct 2026 09:41:13 +0000 Subject: refactor(parser): split expression and control flow parsing Co-Authored-By: Claude Fable 5.1 --- lib/Parser/ParserExpression.cc | 237 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 lib/Parser/ParserExpression.cc (limited to 'lib/Parser/ParserExpression.cc') 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 + +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 Parser::ParseNumberExpr() { + if (CurTok == tok_number_real) { + auto Result = std::make_unique(Lex.RealVal); + getNextToken(); + return Result; + } + auto Result = std::make_unique(Lex.NumVal); + getNextToken(); + return Result; +} + +std::unique_ptr 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(IdName, std::move(*Args), Line); + } + + std::vector Accesses; + if (!ParseDesignatorSuffix(Accesses)) return nullptr; + + // Degrade rule: shapes that existed before designators keep their nodes. + if (Accesses.empty()) + return std::make_unique(IdName); + if (Accesses.size() == 1 && Accesses[0].Kind == AccessKind::Index) + return std::make_unique(IdName, std::move(Accesses[0].Indices), Line); + return std::make_unique(IdName, std::move(Accesses), Line); +} + +// Postfix accessor chain after an identifier: '[' exprs ']' | '.' IDENT | '^' +bool Parser::ParseDesignatorSuffix(std::vector &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 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(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 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(Lex.StringVal); + getNextToken(); + return Res; + } + case tok_char_literal: { + auto Res = std::make_unique(Lex.CharVal); + getNextToken(); + return Res; + } + case tok_true: { + getNextToken(); + return std::make_unique(true); + } + case tok_false: { + getNextToken(); + return std::make_unique(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 Parser::ParseUnary() { + if (CurTok == tok_not) { + getNextToken(); + auto Operand = ParseUnary(); + if (!Operand) return nullptr; + return std::make_unique(tok_not, std::move(Operand)); + } + + // ^ — 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 Accesses; + if (!ParseDesignatorSuffix(Accesses)) return nullptr; + auto Target = std::make_unique(BaseName, std::move(Accesses), Line); + return std::make_unique(std::move(Target)); + } + + if (CurTok == '-') { + getNextToken(); + auto Operand = ParseUnary(); + if (!Operand) return nullptr; + return std::make_unique('-', std::move(Operand)); + } + + return ParsePrimary(); +} + +std::unique_ptr Parser::ParseBinOpRHS(int ExprPrec, std::unique_ptr 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(BinOp, std::move(LHS), std::move(RHS), Line); + } +} + +std::unique_ptr Parser::ParseExpression() { + auto LHS = ParseUnary(); + if (!LHS) return nullptr; + return ParseBinOpRHS(0, std::move(LHS)); +} + + +std::optional>> Parser::ParseExprList(char CloseDelim, bool AllowEmpty) { + std::vector> 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; +} -- cgit v1.3.1-4-g156e