diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/CodeGen/ArrayHandler.cc | 4 | ||||
| -rw-r--r-- | lib/CodeGen/Builtins.h | 3 | ||||
| -rw-r--r-- | lib/CodeGen/CTypeGen.cc | 6 | ||||
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 6 | ||||
| -rw-r--r-- | lib/CodeGen/ConstantGen.cc | 2 | ||||
| -rw-r--r-- | lib/CodeGen/ControlFlowGen.cc | 3 | ||||
| -rw-r--r-- | lib/CodeGen/Designator.cc | 3 | ||||
| -rw-r--r-- | lib/CodeGen/ExpressionGen.cc | 5 | ||||
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 58 | ||||
| -rw-r--r-- | lib/CodeGen/StatementGen.cc | 1 | ||||
| -rw-r--r-- | lib/CodeGen/TypeCheckGen.cc | 7 | ||||
| -rw-r--r-- | lib/CodeGen/TypeSystem.cc | 6 | ||||
| -rw-r--r-- | lib/Lexer/Lexer.cc | 11 | ||||
| -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 |
18 files changed, 134 insertions, 70 deletions
diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc index 40a330f..5eb8a52 100644 --- a/lib/CodeGen/ArrayHandler.cc +++ b/lib/CodeGen/ArrayHandler.cc @@ -12,7 +12,7 @@ using namespace cps; ArrayHandler::ArrayHandler(LLVMContext &C, IRBuilder<> &B, Module &M, - std::map<std::string, SymbolInfo> &Sym, + IdentifierMap<SymbolInfo> &Sym, TypeSystem &TS, RuntimeCheck &RC) : TheContext(&C), @@ -253,7 +253,7 @@ Value *ArrayHandler::emitElementAddress(ArrayAccessExprAST *Expr, CG, ElemTypeNameOut); } -std::map<std::string, ArrayMetadata> ArrayHandler::exchangeTable(std::map<std::string, ArrayMetadata> NewTable) { +IdentifierMap<ArrayMetadata> ArrayHandler::exchangeTable(IdentifierMap<ArrayMetadata> NewTable) { std::swap(ArrayTable, NewTable); return NewTable; } diff --git a/lib/CodeGen/Builtins.h b/lib/CodeGen/Builtins.h index 34e36a9..e7f60e4 100644 --- a/lib/CodeGen/Builtins.h +++ b/lib/CodeGen/Builtins.h @@ -1,4 +1,5 @@ #pragma once +#include "cps/Identifier.h" #include <string> namespace cps::detail { @@ -29,7 +30,7 @@ inline constexpr BuiltinInfo Builtins[] = { inline const BuiltinInfo *findBuiltin(const std::string &Name) { for (const auto &B : Builtins) { - if (Name == B.Name) return &B; + if (sameIdentifier(Name, B.Name)) return &B; } return nullptr; } diff --git a/lib/CodeGen/CTypeGen.cc b/lib/CodeGen/CTypeGen.cc index a20306e..80a7d3b 100644 --- a/lib/CodeGen/CTypeGen.cc +++ b/lib/CodeGen/CTypeGen.cc @@ -81,7 +81,7 @@ Value *CodeGen::emitCast(CastExprAST *Cast) { Value *CodeGen::emitCBinaryOp(int Op, Value *L, const TypeInfo *Left, Value *R, const TypeInfo *Right, int Line) { if (!Left || !Right || !Left->isC() || !Right->isC()) { - reportError("C and pseudocode operands require an explicit cast (line %d)", Line); + reportError("C and pseudocode operands require an explicit cast"); return nullptr; } if (Left->isPointer() || Right->isPointer()) { @@ -99,7 +99,7 @@ Value *CodeGen::emitCBinaryOp(int Op, Value *L, const TypeInfo *Left, return nullptr; } if (Op == '&' || ((Op == tok_div || Op == tok_mod) && !Common->isIntegral())) { - reportError("Operator is not supported for these C operand types (line %d)", Line); + reportError("Operator is not supported for these C operand types"); return nullptr; } if (Op == tok_and || Op == tok_or) { @@ -154,7 +154,7 @@ Value *CodeGen::emitCBinaryOp(int Op, Value *L, const TypeInfo *Left, : Builder->CreateICmpUGE(L, R, "c_ge"); } } - reportError("Unsupported operator for C operands (line %d)", Line); + reportError("Unsupported operator for C operands"); return nullptr; } diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index b793657..dff4009 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -24,6 +24,7 @@ void CodeGen::reportError(const char *Fmt, ...) { va_start(Args, Fmt); fprintf(stderr, "error: "); vfprintf(stderr, Fmt, Args); + if (DiagnosticLine) fprintf(stderr, " at line %d", DiagnosticLine); fprintf(stderr, "\n"); va_end(Args); HadError = true; @@ -51,7 +52,7 @@ CodeGen::CodeGen() { *Types, *Exceptions, Symbols, - HadError); + HadError, DiagnosticLine); ArithHandler = std::make_unique<ArithmeticHandler>(*TheContext, *Builder, HadError, *RuntimeChecker); @@ -158,12 +159,14 @@ void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) { // Pre-register every top-level FUNCTION/PROCEDURE prototype so calls may // precede definitions. for (const auto &Stmt : Statements) { + SaveAndRestore<int> Location(DiagnosticLine, Stmt->getLine()); if (auto *FuncDef = dynamic_cast<FunctionDefAST*>(Stmt.get())) { FuncGen->emitPrototype(FuncDef->getProto()); } } for (const auto &Stmt : Statements) { + SaveAndRestore<int> Location(DiagnosticLine, Stmt->getLine()); emitStmt(Stmt.get()); } @@ -197,6 +200,7 @@ bool CodeGen::marshalCallArgs(const std::string &Callee, const std::vector<std::unique_ptr<ExprAST>> &ArgExprs, int Line, std::vector<Value*> &Out) { + SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine); const FuncSig *Sig = FuncGen->getSignature(Callee); if (!Sig) { reportError("Call to undefined function %s", Callee.c_str()); diff --git a/lib/CodeGen/ConstantGen.cc b/lib/CodeGen/ConstantGen.cc index e9f81ae..e14e22f 100644 --- a/lib/CodeGen/ConstantGen.cc +++ b/lib/CodeGen/ConstantGen.cc @@ -19,7 +19,7 @@ bool CodeGen::prepareSymbolDeclaration(const std::string &Name, bool IsConstant) auto &Scope = ConstantScopes.back(); auto It = Symbols.find(Name); if (It != Symbols.end()) { - if ((IsConstant || It->second.ConstantValue) && It->second.ScopeID == Scope.ID) { + if (It->second.ScopeID == Scope.ID) { reportError("Declaration of %s conflicts with an existing declaration in this scope", Name.c_str()); return false; } diff --git a/lib/CodeGen/ControlFlowGen.cc b/lib/CodeGen/ControlFlowGen.cc index d34f640..17f43f2 100644 --- a/lib/CodeGen/ControlFlowGen.cc +++ b/lib/CodeGen/ControlFlowGen.cc @@ -190,6 +190,7 @@ void CodeGen::emitCaseStmt(CaseStmtAST *Stmt) { auto *After = BasicBlock::Create(*TheContext, "case_cont", F); auto SavedArrays = Arrays->snapshotTable(); for (const auto &Branch : Stmt->getBranches()) { + SaveAndRestore<int> Location(DiagnosticLine, Branch.Line); auto *Body = BasicBlock::Create(*TheContext, "case_body", F); auto *Next = BasicBlock::Create(*TheContext, "case_next", F); auto Compare = [&](int Op, ExprAST *Label) -> Value * { @@ -199,7 +200,7 @@ void CodeGen::emitCaseStmt(CaseStmtAST *Stmt) { } const TypeInfo *LabelType = getExprTypeInfo(Label); if (!LabelType) { - reportError("Cannot determine CASE label type at line %d", Branch.Line); + reportError("Cannot determine CASE label type"); return nullptr; } Value *LabelValue = emitExpr(Label); diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc index afaf0a4..fcc6919 100644 --- a/lib/CodeGen/Designator.cc +++ b/lib/CodeGen/Designator.cc @@ -15,6 +15,7 @@ void CodeGen::runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statem std::string Err; for (const auto &S : Statements) { + SaveAndRestore<int> Location(DiagnosticLine, S->getLine()); bool Ok = true; if (auto *C = dynamic_cast<CTypeDeclAST*>(S.get())) Ok = Types->defineCAlias(C->getName(), C->getExpression(), Err); @@ -28,6 +29,7 @@ void CodeGen::runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statem } for (const auto &S : Statements) { + SaveAndRestore<int> Location(DiagnosticLine, S->getLine()); bool Ok = true; if (auto *E = dynamic_cast<EnumTypeDeclAST*>(S.get())) { Ok = Types->defineEnum(E->getName(), E->getValueNames(), Err); @@ -44,6 +46,7 @@ void CodeGen::runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statem // of its storage plus the type name stored there. Array indexing goes through // ArrayHandler's checked pipeline; dereferences emit the null-pointer check. bool CodeGen::emitLValue(ExprAST *E, LValueInfo &Out) { + SaveAndRestore<int> Location(DiagnosticLine, E && E->getLine() ? E->getLine() : DiagnosticLine); if (auto *Var = dynamic_cast<VariableExprAST*>(E)) { const SymbolInfo *Info = getSymbolInfo(Var->getName()); if (!Info) { diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc index f3dadb7..b3655fd 100644 --- a/lib/CodeGen/ExpressionGen.cc +++ b/lib/CodeGen/ExpressionGen.cc @@ -11,6 +11,7 @@ using namespace cps; using namespace cps::detail; Value *CodeGen::emitExpr(ExprAST *Expr) { + SaveAndRestore<int> Location(DiagnosticLine, Expr && Expr->getLine() ? Expr->getLine() : DiagnosticLine); if (auto *Cast = dynamic_cast<CastExprAST*>(Expr)) return emitCast(Cast); if (!Expr) return nullptr; @@ -126,6 +127,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { if (auto *Call = dynamic_cast<CallExprAST*>(Expr)) { std::string Name = Call->getCallee(); if (const BuiltinInfo *B = findBuiltin(Name)) { + Name = B->Name; if (Call->getArgs().size() != B->Arity) { reportError("%s expects %u arg%s", B->Name, B->Arity, B->Arity == 1 ? "" : "s"); return nullptr; @@ -247,6 +249,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { // Ordinary binary expressions and CASE use the same typed operations. Value *CodeGen::emitBinaryOp(int Op, Value *L, const TypeInfo *LT, Value *R, const TypeInfo *RT, int Line) { + SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine); if (!L || !R) return nullptr; if ((LT && LT->isC()) || (RT && RT->isC())) return emitCBinaryOp(Op, L, LT, R, RT, Line); @@ -261,7 +264,7 @@ Value *CodeGen::emitBinaryOp(int Op, Value *L, const TypeInfo *LT, case tok_eq: case tok_ne: case '<': case '>': case tok_le: case tok_ge: if ((LT && LT->isString()) || (RT && RT->isString())) { if (!(LT && LT->isString() && RT && RT->isString())) { - reportError("STRING comparison requires two STRING operands (line %d)", Line); + reportError("STRING comparison requires two STRING operands"); return nullptr; } return StrHandler->emitCompare(Op, L, R); diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index 957a1f5..a155f60 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -2,6 +2,7 @@ #include "cps/CodeGen.h" #include "cps/ExceptionHandler.h" #include <cstdio> +#include <cstdarg> using namespace llvm; using namespace cps; @@ -19,16 +20,26 @@ static bool isReservedRuntimeName(const std::string &Name) { "__gxx_personality_seh0", "__gxx_personality_sj0", "_Unwind_Resume", "_ZTIi", }; for (const char *R : Reserved) { - if (Name == R) return true; + if (sameIdentifier(Name, R)) return true; } return false; } +void FunctionGen::reportError(const char *Fmt, ...) { + va_list Args; + va_start(Args, Fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, Fmt, Args); + if (DiagnosticLine) fprintf(stderr, " at line %d", DiagnosticLine); + fprintf(stderr, "\n"); + va_end(Args); + HadError = true; +} + Type *FunctionGen::getLLVMType(const std::string &TypeName) { Type *Resolved = Types.getLLVMType(TypeName); if (!Resolved) { - fprintf(stderr, "error: Unknown type %s\n", TypeName.c_str()); - HadError = true; + reportError("Unknown type %s", TypeName.c_str()); return Type::getInt64Ty(Context); } return Resolved; @@ -38,12 +49,10 @@ void FunctionGen::createArgumentAllocas(Function *F, const std::vector<ParamDecl Function::arg_iterator AI = F->arg_begin(); for (const ParamDecl &P : Params) { if (Types.lookupEnumConstant(P.Name)) { - fprintf(stderr, "error: parameter '%s' collides with an enum value\n", P.Name.c_str()); - HadError = true; + reportError("parameter '%s' collides with an enum value", P.Name.c_str()); } if (Types.resolve(P.Name)) { - fprintf(stderr, "error: parameter '%s' collides with a type name\n", P.Name.c_str()); - HadError = true; + reportError("parameter '%s' collides with a type name", P.Name.c_str()); } Value *ArgVal = &(*AI); ++AI; @@ -88,39 +97,35 @@ const FuncSig *FunctionGen::getSignature(const std::string &Name) const { Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { if (isReservedRuntimeName(Proto->getName())) { - fprintf(stderr, "error: '%s' is a reserved runtime symbol and cannot be a FUNCTION/PROCEDURE name\n", + reportError("'%s' is a reserved runtime symbol and cannot be a FUNCTION/PROCEDURE name", Proto->getName().c_str()); - HadError = true; return nullptr; } if (CodeGen::isBuiltinName(Proto->getName())) { - fprintf(stderr, "error: '%s' is a built-in function and cannot be redefined\n", + reportError("'%s' is a built-in function and cannot be redefined", Proto->getName().c_str()); - HadError = true; return nullptr; } if (Types.lookupEnumConstant(Proto->getName())) { - fprintf(stderr, "error: '%s' is an enum value and cannot be a FUNCTION/PROCEDURE name\n", + reportError("'%s' is an enum value and cannot be a FUNCTION/PROCEDURE name", Proto->getName().c_str()); - HadError = true; return nullptr; } if (Types.resolve(Proto->getName())) { - fprintf(stderr, "error: '%s' is a type name and cannot be a FUNCTION/PROCEDURE name\n", + reportError("'%s' is a type name and cannot be a FUNCTION/PROCEDURE name", Proto->getName().c_str()); - HadError = true; return nullptr; } FuncSig Sig; + Sig.Name = Proto->getName(); Sig.ReturnTypeName = Proto->getReturnType(); std::vector<Type*> ArgTypes; for (const ParamDecl &P : Proto->getParams()) { const TypeInfo *Info = Types.resolve(P.TypeName); if (Info && Info->isVoid()) { - fprintf(stderr, "error: parameter %s cannot have void type\n", P.Name.c_str()); - HadError = true; + reportError("parameter %s cannot have void type", P.Name.c_str()); return nullptr; } ParamSig PS; @@ -148,11 +153,11 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { Type *RetType = getLLVMType(Proto->getReturnType()); FunctionType *FT = FunctionType::get(RetType, ArgTypes, false); - Function *F = Module.getFunction(Proto->getName()); + const FuncSig *Existing = getSignature(Proto->getName()); + Function *F = Module.getFunction(Existing ? Existing->Name : Proto->getName()); if (F && F->getFunctionType() != FT) { - fprintf(stderr, "error: Function %s conflicts with an existing declaration of a different type\n", + reportError("Function %s conflicts with an existing declaration of a different type", Proto->getName().c_str()); - HadError = true; return nullptr; } if (!F) { @@ -184,15 +189,14 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST, if (!TheFunction) return nullptr; if (!TheFunction->empty()) { - fprintf(stderr, "error: Function %s cannot be redefined.\n", Proto->getName().c_str()); - HadError = true; + reportError("Function %s cannot be redefined.", Proto->getName().c_str()); return nullptr; } BasicBlock *BB = BasicBlock::Create(Context, "entry", TheFunction); Builder.SetInsertPoint(BB); - std::map<std::string, SymbolInfo> OldSymbols = Symbols; + IdentifierMap<SymbolInfo> OldSymbols = Symbols; Symbols.clear(); for (const auto &[Name, Info] : OldSymbols) { if (Info.ConstantValue && Info.ScopeID == 0) Symbols.emplace(Name, Info); @@ -209,7 +213,7 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST, } if (!Builder.GetInsertBlock()->hasTerminator()) { - if (Proto->getReturnType() == "VOID") { + if (sameIdentifier(Proto->getReturnType(), "VOID")) { Builder.CreateRetVoid(); } else { Builder.CreateRet(Constant::getNullValue(TheFunction->getReturnType())); @@ -240,11 +244,13 @@ static Value *GenerateCall(llvm::Module &Module, } llvm::Value *FunctionGen::emitCallExpr(CallExprAST *Call, const std::vector<llvm::Value*> &Args) { - return GenerateCall(Module, Exceptions, Call->getCallee(), Args, HadError); + const FuncSig *Sig = getSignature(Call->getCallee()); + return GenerateCall(Module, Exceptions, Sig ? Sig->Name : Call->getCallee(), Args, HadError); } void FunctionGen::emitCallStmt(CallStmtAST *Call, const std::vector<llvm::Value*> &Args) { - GenerateCall(Module, Exceptions, Call->getCallee(), Args, HadError); + const FuncSig *Sig = getSignature(Call->getCallee()); + GenerateCall(Module, Exceptions, Sig ? Sig->Name : Call->getCallee(), Args, HadError); } void FunctionGen::emitReturn(ReturnStmtAST *Ret, llvm::Value *RetVal) { diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc index 8907cfa..3ea0670 100644 --- a/lib/CodeGen/StatementGen.cc +++ b/lib/CodeGen/StatementGen.cc @@ -9,6 +9,7 @@ using namespace llvm; using namespace cps; void CodeGen::emitStmt(StmtAST *Stmt) { + SaveAndRestore<int> Location(DiagnosticLine, Stmt && Stmt->getLine() ? Stmt->getLine() : DiagnosticLine); if (!Stmt) return; if (auto *FuncDef = dynamic_cast<FunctionDefAST*>(Stmt)) { diff --git a/lib/CodeGen/TypeCheckGen.cc b/lib/CodeGen/TypeCheckGen.cc index 654afc8..690d005 100644 --- a/lib/CodeGen/TypeCheckGen.cc +++ b/lib/CodeGen/TypeCheckGen.cc @@ -33,6 +33,7 @@ std::string opToText(int Op) { // LLVM level); builtin targets additionally reject user-kind sources, then // keep the existing representation coercions unchanged. Value *CodeGen::emitCoercedExpr(ExprAST *E, const TypeInfo *Target) { + SaveAndRestore<int> Location(DiagnosticLine, E && E->getLine() ? E->getLine() : DiagnosticLine); if (!E || !Target) return nullptr; // A whole-array reference evaluates to its raw data pointer, and @@ -94,7 +95,7 @@ Value *CodeGen::emitCoercedExpr(ExprAST *E, const TypeInfo *Target) { } return nullptr; } - if (Src->Name != Target->Name) { + if (!Src->sameType(Target)) { reportError("Cannot use a value of type %s where %s is expected", Src->Name.c_str(), Target->Name.c_str()); return nullptr; @@ -133,7 +134,7 @@ Value *CodeGen::emitUserKindBinaryOp(int Op, Value *L, const TypeInfo *LT, } if ((LT && LT->isPointer()) || (RT && RT->isPointer())) { - bool SameName = LT && RT && LT->isPointer() && RT->isPointer() && LT->Name == RT->Name; + bool SameName = LT && RT && LT->isPointer() && RT->isPointer() && LT->sameType(RT); if (SameName && (Op == tok_eq || Op == tok_ne)) { return Op == tok_eq ? Builder->CreateICmpEQ(L, R, "ptr_eq") : Builder->CreateICmpNE(L, R, "ptr_ne"); @@ -144,7 +145,7 @@ Value *CodeGen::emitUserKindBinaryOp(int Op, Value *L, const TypeInfo *LT, } // At least one enum operand from here on. - bool BothSameEnum = LT && RT && LT->isEnum() && RT->isEnum() && LT->Name == RT->Name; + bool BothSameEnum = LT && RT && LT->isEnum() && RT->isEnum() && LT->sameType(RT); switch (Op) { case tok_eq: case tok_ne: case '<': case '>': case tok_le: case tok_ge: { diff --git a/lib/CodeGen/TypeSystem.cc b/lib/CodeGen/TypeSystem.cc index a837c9a..f4620dc 100644 --- a/lib/CodeGen/TypeSystem.cc +++ b/lib/CodeGen/TypeSystem.cc @@ -12,12 +12,12 @@ bool TypeInfo::sameType(const TypeInfo *Other) const { if (!Other) return false; if (isC() || Other->isC()) return isC() && Other->isC() && CIdentity == Other->CIdentity; - return Name == Other->Name; + return sameIdentifier(Name, Other->Name); } const RecordFieldInfo *RecordPayload::findField(const std::string &Name) const { for (const auto &F : Fields) { - if (F.first == Name) return &F.second; + if (sameIdentifier(F.first, Name)) return &F.second; } return nullptr; } @@ -172,7 +172,7 @@ bool TypeSystem::defineEnum(const std::string &Name, for (size_t I = 0; I < Values.size(); ++I) { const std::string &V = Values[I]; for (size_t J = 0; J < I; ++J) { - if (Values[J] == V) { + if (sameIdentifier(Values[J], V)) { Err = "Duplicate value '" + V + "' in enum " + Name; return false; } diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc index 59247cf..9203db1 100644 --- a/lib/Lexer/Lexer.cc +++ b/lib/Lexer/Lexer.cc @@ -1,5 +1,7 @@ #include "cps/Lexer.h" #include <algorithm> +#include <charconv> +#include <limits> #include <cctype> #include <cstdio> #include <cstdlib> @@ -104,7 +106,6 @@ int Lexer::readToken() { if (IdentifierStr == "THROW") return tok_throw; if (IdentifierStr == "WHILE") return tok_while; - if (IdentifierStr == "DO") return tok_do; if (IdentifierStr == "ENDWHILE") return tok_endwhile; if (IdentifierStr == "REPEAT") return tok_repeat; @@ -175,7 +176,13 @@ int Lexer::readToken() { return tok_number_real; } - NumVal = strtoll(NumStr.c_str(), nullptr, 10); + auto Parsed = std::from_chars(NumStr.data(), NumStr.data() + NumStr.size(), NumVal); + if (Parsed.ec != std::errc{} || + NumVal > uint64_t(std::numeric_limits<int64_t>::max()) + 1) { + fprintf(stderr, "error: Integer literal is outside the i64 range at line %d\n", TokenLine); + HadError = true; + NumVal = 0; + } return tok_number_int; } 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; |
