aboutsummaryrefslogtreecommitdiff
path: root/lib/Parser/ParserExpression.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-16 09:41:13 +0000
committer_ov4 <ov4@ov4.org>2026-10-16 09:41:13 +0000
commitdb6ac29d0ac769ff780f3901ed987b97965f3f5e (patch)
treec7d5f4b06712aefa2a885f338143aec9fe68e322 /lib/Parser/ParserExpression.cc
parent7ee2b877cf396e680582b4a2d6094d4f3ad89abb (diff)
refactor(parser): split expression and control flow parsing
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib/Parser/ParserExpression.cc')
-rw-r--r--lib/Parser/ParserExpression.cc237
1 files changed, 237 insertions, 0 deletions
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;
+}