diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-17 09:09:03 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-17 09:09:03 +0000 |
| commit | dc645a36aaade7087ade574cefe69ce7bb29753e (patch) | |
| tree | d10a4f3ab8947c014f79b940d4658e9ff9730e9d | |
| parent | 5097edca0619007eb4237e52fcc07f0e0b4b99e2 (diff) | |
refactor(diag): file-qualified diagnostic locations
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | include/cps/Diagnostics.h | 44 | ||||
| -rw-r--r-- | lib/CodeGen/ArithmeticHandler.cc | 9 | ||||
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 3 | ||||
| -rw-r--r-- | lib/CodeGen/ConstantGen.cc | 3 | ||||
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 9 | ||||
| -rw-r--r-- | lib/Lexer/Lexer.cc | 9 | ||||
| -rw-r--r-- | lib/Parser/Parser.cc | 19 | ||||
| -rw-r--r-- | lib/Parser/ParserControlFlow.cc | 35 | ||||
| -rw-r--r-- | lib/Parser/ParserExpression.cc | 25 | ||||
| -rw-r--r-- | lib/Parser/ParserFile.cc | 15 | ||||
| -rw-r--r-- | lib/Parser/ParserFunction.cc | 47 | ||||
| -rw-r--r-- | lib/Parser/ParserType.cc | 55 |
12 files changed, 164 insertions, 109 deletions
diff --git a/include/cps/Diagnostics.h b/include/cps/Diagnostics.h new file mode 100644 index 0000000..6f26292 --- /dev/null +++ b/include/cps/Diagnostics.h @@ -0,0 +1,44 @@ +#pragma once +#include <cstdarg> +#include <cstdio> +#include <string> +#include <vector> + +namespace cps { +// Empty for single-source builds to preserve existing diagnostic text. +inline std::string DiagnosticSource; +inline std::string lineSuffix(int Line) { + return " at line " + std::to_string(Line) + + (DiagnosticSource.empty() ? "" : " in " + DiagnosticSource); +} +inline void sourceDiagnostic(int Line, const char *Format, ...) { + va_list Args, Copy; + va_start(Args, Format); + va_copy(Copy, Args); + int Size = std::vsnprintf(nullptr, 0, Format, Copy); + va_end(Copy); + if (Size < 0) { va_end(Args); return; } + std::vector<char> Buffer(Size + 1); + std::vsnprintf(Buffer.data(), Buffer.size(), Format, Args); + va_end(Args); + std::string Message(Buffer.data(), Size); + if (!DiagnosticSource.empty()) { + auto At = Message.find("at line "); + if (At != std::string::npos) { + auto End = Message.find_first_not_of("0123456789", At + 8); + Message.insert(End == std::string::npos ? Message.size() : End, + " in " + DiagnosticSource); + } else { + auto Old = Message.find("(line "); + if (Old != std::string::npos) { + auto End = Message.find(')', Old); + Message.replace(Old, End - Old + 1, lineSuffix(Line).substr(1)); + } else { + auto End = Message.find_last_not_of("\n"); + Message.insert(End == std::string::npos ? 0 : End + 1, lineSuffix(Line)); + } + } + } + std::fputs(Message.c_str(), stderr); +} +} diff --git a/lib/CodeGen/ArithmeticHandler.cc b/lib/CodeGen/ArithmeticHandler.cc index cd4e7b3..255da57 100644 --- a/lib/CodeGen/ArithmeticHandler.cc +++ b/lib/CodeGen/ArithmeticHandler.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/ArithmeticHandler.h" #include "cps/Lexer.h" #include "cps/RuntimeCheck.h" @@ -28,7 +29,7 @@ Value *ArithmeticHandler::emitBinaryOp(int Op, Value *LHS, Value *RHS, int Line) if (LVal->getType()->isIntegerTy(64)) LVal = Builder.CreateSIToFP(LVal, Type::getDoubleTy(Context)); if (RVal->getType()->isIntegerTy(64)) RVal = Builder.CreateSIToFP(RVal, Type::getDoubleTy(Context)); if (!LVal->getType()->isDoubleTy() || !RVal->getType()->isDoubleTy()) { - fprintf(stderr, "error: '/' requires numeric operands (line %d).\n", Line); + cps::sourceDiagnostic(Line, "error: '/' requires numeric operands (line %d).\n", Line); HadError = true; return nullptr; } @@ -39,7 +40,7 @@ Value *ArithmeticHandler::emitBinaryOp(int Op, Value *LHS, Value *RHS, int Line) if (Op == tok_div || Op == tok_mod) { if (!LIsInt || !RIsInt) { - fprintf(stderr, "error: DIV and MOD operators require INTEGER operands (line %d).\n", Line); + cps::sourceDiagnostic(Line, "error: DIV and MOD operators require INTEGER operands (line %d).\n", Line); HadError = true; return nullptr; } @@ -96,7 +97,7 @@ Value *ArithmeticHandler::emitBinaryOp(int Op, Value *LHS, Value *RHS, int Line) R = widenSmallInt(Builder, Context, R); } if (L->getType() != R->getType()) { - fprintf(stderr, "error: Mismatched operand types for binary operator (line %d).\n", Line); + cps::sourceDiagnostic(Line, "error: Mismatched operand types for binary operator (line %d).\n", Line); HadError = true; return nullptr; } @@ -114,7 +115,7 @@ Value *ArithmeticHandler::emitBinaryOp(int Op, Value *LHS, Value *RHS, int Line) } } - fprintf(stderr, "error: Unsupported operand types for binary operator (line %d).\n", Line); + cps::sourceDiagnostic(Line, "error: Unsupported operand types for binary operator (line %d).\n", Line); HadError = true; return nullptr; } diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 0107910..d3459ef 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/CodeGen.h" #include "cps/ArrayHandler.h" #include "cps/FileHandler.h" @@ -25,7 +26,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); + if (DiagnosticLine) fprintf(stderr, "%s", lineSuffix(DiagnosticLine).c_str()); fprintf(stderr, "\n"); va_end(Args); HadError = true; diff --git a/lib/CodeGen/ConstantGen.cc b/lib/CodeGen/ConstantGen.cc index 58913e4..632502d 100644 --- a/lib/CodeGen/ConstantGen.cc +++ b/lib/CodeGen/ConstantGen.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/CodeGen.h" #include <cstdio> @@ -21,7 +22,7 @@ void CodeGen::warnMemberShadow(const std::string &Name, int Line) const { const TypeInfo *Class = resolveType(CurrentClass); const RecordPayload *Record = Class ? Class->asRecord() : nullptr; if (Record && Record->findField(Name)) { - fprintf(stderr, "warning: Declaration of %s shadows a field of class %s at line %d\n", + cps::sourceDiagnostic(Line, "warning: Declaration of %s shadows a field of class %s at line %d\n", Name.c_str(), CurrentClass.c_str(), Line); } } diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index 59e9bbe..b66b55a 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/FunctionGen.h" #include "cps/CodeGen.h" #include "cps/ExceptionHandler.h" @@ -30,7 +31,7 @@ void FunctionGen::reportError(const char *Fmt, ...) { va_start(Args, Fmt); fprintf(stderr, "error: "); vfprintf(stderr, Fmt, Args); - if (DiagnosticLine) fprintf(stderr, " at line %d", DiagnosticLine); + if (DiagnosticLine) fprintf(stderr, "%s", lineSuffix(DiagnosticLine).c_str()); fprintf(stderr, "\n"); va_end(Args); HadError = true; @@ -258,10 +259,10 @@ static Value *GenerateCall(llvm::Module &Module, ExceptionHandler &Exceptions, const std::string &CalleeName, const std::vector<llvm::Value*> &Args, - bool &HadError) { + bool &HadError, int DiagnosticLine) { Function *CalleeF = Module.getFunction(CalleeName); if (!CalleeF) { - fprintf(stderr, "error: Call to undefined function %s\n", CalleeName.c_str()); + sourceDiagnostic(DiagnosticLine, "error: Call to undefined function %s\n", CalleeName.c_str()); HadError = true; return nullptr; } @@ -275,7 +276,7 @@ static Value *GenerateCall(llvm::Module &Module, llvm::Value *FunctionGen::emitCall(const std::string &Callee, const std::vector<llvm::Value*> &Args) { const FuncSig *Sig = getSignature(Callee); - return GenerateCall(Module, Exceptions, Sig ? Sig->Name : Callee, Args, HadError); + return GenerateCall(Module, Exceptions, Sig ? Sig->Name : Callee, Args, HadError, DiagnosticLine); } void FunctionGen::emitReturn(ReturnStmtAST *Ret, llvm::Value *RetVal) { diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc index 61785c7..acdedd0 100644 --- a/lib/Lexer/Lexer.cc +++ b/lib/Lexer/Lexer.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/Lexer.h" #include <algorithm> #include <charconv> @@ -29,7 +30,7 @@ int Lexer::readToken() { if (LastChar == '"') { LastChar = Input.get(); } else { - fprintf(stderr, "error: Unterminated string literal at line %d\n", CurrentLine); + cps::sourceDiagnostic(CurrentLine, "error: Unterminated string literal at line %d\n", CurrentLine); HadError = true; } @@ -39,7 +40,7 @@ int Lexer::readToken() { if (LastChar == '\'') { int CharCode = Input.get(); if (CharCode == EOF || CharCode == '\n') { - fprintf(stderr, "error: Unterminated char literal at line %d\n", CurrentLine); + cps::sourceDiagnostic(CurrentLine, "error: Unterminated char literal at line %d\n", CurrentLine); HadError = true; CharVal = '?'; StringVal.assign(1, CharVal); @@ -50,7 +51,7 @@ int Lexer::readToken() { int ClosingQuote = Input.get(); if (ClosingQuote != '\'') { - fprintf(stderr, "error: CHAR literal must contain exactly one character (line %d)\n", CurrentLine); + cps::sourceDiagnostic(CurrentLine, "error: CHAR literal must contain exactly one character (line %d)\n", CurrentLine); HadError = true; while (ClosingQuote != EOF && ClosingQuote != '\n' && ClosingQuote != '\'') { ClosingQuote = Input.get(); @@ -181,7 +182,7 @@ int Lexer::readToken() { 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); + cps::sourceDiagnostic(CurrentLine, "error: Integer literal is outside the i64 range at line %d\n", TokenLine); HadError = true; NumVal = 0; } diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc index a7e7edf..826bc89 100644 --- a/lib/Parser/Parser.cc +++ b/lib/Parser/Parser.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/Parser.h" #include "cps/FunctionAST.h" #include <cstdio> @@ -98,7 +99,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_identifier) { - fprintf(stderr, "error: DELETE requires an object designator at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: DELETE requires an object designator at line %d\n", Line); return nullptr; } std::string Name = Lex.IdentifierStr; @@ -110,7 +111,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { } if (CurTok == tok_case) return ParseCaseStmt(); if (CurTok == tok_endcase || CurTok == tok_otherwise) { - fprintf(stderr, "error: Unexpected CASE terminator at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Unexpected CASE terminator at line %d\n", Lex.getLine()); getNextToken(); return nullptr; } @@ -124,7 +125,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { else if (CurTok == tok_input) { getNextToken(); if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected variable name after INPUT at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected variable name after INPUT at line %d\n", Lex.getLine()); return nullptr; } std::string Name = Lex.IdentifierStr; @@ -165,7 +166,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { return std::make_unique<ThrowStmtAST>(); } else if (CurTok == tok_catch || CurTok == tok_endtry) { - fprintf(stderr, "error: Unexpected %s without matching TRY at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Unexpected %s without matching TRY at line %d\n", CurTok == tok_catch ? "CATCH" : "ENDTRY", Lex.getLine()); getNextToken(); return nullptr; @@ -207,22 +208,22 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { return ParseTypeDecl(); } else if (CurTok == tok_define) { - fprintf(stderr, "error: DEFINE (SET literals) is not implemented at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: DEFINE (SET literals) is not implemented at line %d\n", Lex.getLine()); getNextToken(); return nullptr; } else if (CurTok == tok_endtype) { - fprintf(stderr, "error: ENDTYPE without matching TYPE at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: ENDTYPE without matching TYPE at line %d\n", Lex.getLine()); getNextToken(); return nullptr; } else if (CurTok == tok_endclass) { - fprintf(stderr, "error: ENDCLASS without matching CLASS at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: ENDCLASS without matching CLASS at line %d\n", Lex.getLine()); getNextToken(); return nullptr; } - fprintf(stderr, "error: Unexpected token at line %d when expecting a statement\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Unexpected token at line %d when expecting a statement\n", Lex.getLine()); getNextToken(); // guarantee progress so error recovery cannot loop forever return nullptr; } @@ -252,7 +253,7 @@ std::unique_ptr<StmtAST> Parser::ParseAssignStmt() { } if (CurTok != tok_assign) { - fprintf(stderr, "error: Expected '<-' after identifier '%s' at line %d\n", Name.c_str(), Line); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected '<-' after identifier '%s' at line %d\n", Name.c_str(), Line); return nullptr; } getNextToken(); diff --git a/lib/Parser/ParserControlFlow.cc b/lib/Parser/ParserControlFlow.cc index 1cbedcd..10dd512 100644 --- a/lib/Parser/ParserControlFlow.cc +++ b/lib/Parser/ParserControlFlow.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/Parser.h" #include "cps/FunctionAST.h" #include <cstdio> @@ -8,13 +9,13 @@ 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()); + cps::sourceDiagnostic(Lex.getLine(), "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()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ENDTRY after CATCH at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -27,7 +28,7 @@ std::unique_ptr<StmtAST> Parser::ParseIfStmt() { if (!Cond) return nullptr; if (CurTok != tok_then) { - fprintf(stderr, "error: expected THEN at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: expected THEN at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -41,7 +42,7 @@ std::unique_ptr<StmtAST> Parser::ParseIfStmt() { } if (CurTok != tok_endif) { - fprintf(stderr, "error: expected ENDIF at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDIF at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -59,7 +60,7 @@ std::unique_ptr<StmtAST> Parser::ParseWhileStmt() { std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_endwhile}); if (CurTok != tok_endwhile) { - fprintf(stderr, "error: expected ENDWHILE\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDWHILE\n"); return nullptr; } getNextToken(); @@ -73,7 +74,7 @@ std::unique_ptr<StmtAST> Parser::ParseRepeatStmt() { std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_until}); if (CurTok != tok_until) { - fprintf(stderr, "error: expected UNTIL\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: expected UNTIL\n"); return nullptr; } getNextToken(); @@ -87,14 +88,14 @@ std::unique_ptr<StmtAST> Parser::ParseRepeatStmt() { std::unique_ptr<StmtAST> Parser::ParseForStmt() { getNextToken(); if (CurTok != tok_identifier) { - fprintf(stderr, "error: expected identifier after FOR\n"); + cps::sourceDiagnostic(Lex.getLine(), "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"); + cps::sourceDiagnostic(Lex.getLine(), "error: expected '<-' in FOR loop\n"); return nullptr; } getNextToken(); @@ -103,7 +104,7 @@ std::unique_ptr<StmtAST> Parser::ParseForStmt() { if (!Start) return nullptr; if (CurTok != tok_to) { - fprintf(stderr, "error: expected TO in FOR loop\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: expected TO in FOR loop\n"); return nullptr; } getNextToken(); @@ -121,18 +122,18 @@ std::unique_ptr<StmtAST> Parser::ParseForStmt() { std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_next}); if (CurTok != tok_next) { - fprintf(stderr, "error: expected NEXT\n"); + cps::sourceDiagnostic(Lex.getLine(), "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()); + cps::sourceDiagnostic(Lex.getLine(), "error: expected identifier after NEXT (e.g., NEXT %s)\n", VarName.c_str()); return nullptr; } if (!sameIdentifier(Lex.IdentifierStr, VarName)) { - fprintf(stderr, "error: NEXT identifier '%s' does not match FOR variable '%s'\n", + cps::sourceDiagnostic(Lex.getLine(), "error: NEXT identifier '%s' does not match FOR variable '%s'\n", Lex.IdentifierStr.c_str(), VarName.c_str()); return nullptr; } @@ -177,12 +178,12 @@ bool Parser::atCaseBoundary() { std::unique_ptr<StmtAST> Parser::ParseCaseStmt() { getNextToken(); if (CurTok != tok_of) { - fprintf(stderr, "error: Expected OF after CASE at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected OF after CASE at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected identifier after CASE OF at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected identifier after CASE OF at line %d\n", Lex.getLine()); return nullptr; } std::string Selector = Lex.IdentifierStr; @@ -191,7 +192,7 @@ std::unique_ptr<StmtAST> Parser::ParseCaseStmt() { bool SeenOtherwise = false; while (CurTok != tok_endcase && CurTok != tok_eof) { if (SeenOtherwise || !isCaseLabel()) { - fprintf(stderr, "error: Expected CASE label on a new line (OTHERWISE must be last) at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected CASE label on a new line (OTHERWISE must be last) at line %d\n", Lex.getLine()); return nullptr; } CaseBranch Branch; @@ -212,7 +213,7 @@ std::unique_ptr<StmtAST> Parser::ParseCaseStmt() { if (!Branch.Lower) return nullptr; } if (CurTok != tok_colon) { - fprintf(stderr, "error: Expected ':' after CASE label at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' after CASE label at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -220,7 +221,7 @@ std::unique_ptr<StmtAST> Parser::ParseCaseStmt() { Branches.push_back(std::move(Branch)); } if (CurTok != tok_endcase || Branches.empty()) { - fprintf(stderr, "error: Expected nonempty CASE and ENDCASE at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected nonempty CASE and ENDCASE at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc index ee3e193..a4f4fcc 100644 --- a/lib/Parser/ParserExpression.cc +++ b/lib/Parser/ParserExpression.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/Parser.h" #include "cps/FunctionAST.h" #include <cstdio> @@ -17,7 +18,7 @@ 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()); + cps::sourceDiagnostic(Lex.getLine(), "error: Integer literal is outside the i64 range at line %d\n", Lex.getLine()); getNextToken(); return false; } @@ -49,7 +50,7 @@ std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { 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", + cps::sourceDiagnostic(Lex.getLine(), "error: record/array/pointer access on a function result is not supported at line %d\n", Lex.getLine()); return nullptr; } @@ -74,7 +75,7 @@ std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { std::unique_ptr<MemberCallExprAST> Parser::ParseMemberCall( const std::string &Name, std::vector<DesignatorAccess> Accesses, int Line) { if (Accesses.empty() || Accesses.back().Kind != AccessKind::Field) { - fprintf(stderr, "error: Expected a method name after '.' at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected a method name after '.' at line %d\n", Line); return nullptr; } std::string Method = Accesses.back().FieldName; @@ -88,7 +89,7 @@ std::unique_ptr<MemberCallExprAST> Parser::ParseMemberCall( Args = std::move(*Parsed); } if (CurTok == '[' || CurTok == '.' || CurTok == '^') { - fprintf(stderr, "error: record/array/pointer access on a function result is not supported at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: record/array/pointer access on a function result is not supported at line %d\n", Lex.getLine()); return nullptr; } @@ -110,7 +111,7 @@ bool Parser::ParseDesignatorSuffix(std::vector<DesignatorAccess> &Out) { } else if (CurTok == '.') { getNextToken(); if (CurTok != tok_identifier && CurTok != tok_new && CurTok != tok_delete) { - fprintf(stderr, "error: Expected field name after '.' at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected field name after '.' at line %d\n", Lex.getLine()); return false; } DesignatorAccess A; @@ -141,7 +142,7 @@ std::unique_ptr<ExprAST> Parser::ParseParenExpr() { std::string TypeName = ParseTypeName(); if (TypeName.empty()) return nullptr; if (CurTok != ')') { - fprintf(stderr, "error: Expected ')' after cast type at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ')' after cast type at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -152,7 +153,7 @@ std::unique_ptr<ExprAST> Parser::ParseParenExpr() { auto V = ParseExpression(); if (!V) return nullptr; if (CurTok != ')') { - fprintf(stderr, "error: expected ')' at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: expected ')' at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -169,7 +170,7 @@ std::unique_ptr<ExprAST> Parser::ParsePrimary() { std::unique_ptr<ExprAST> Parser::ParsePrimaryImpl() { switch (CurTok) { case tok_new: - fprintf(stderr, "error: NEW is only allowed on the right of an assignment at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: NEW is only allowed on the right of an assignment at line %d\n", Lex.getLine()); return nullptr; case tok_identifier: return ParseIdentifierExpr(); case tok_number_int: return ParseNumberExpr(); @@ -194,7 +195,7 @@ std::unique_ptr<ExprAST> Parser::ParsePrimaryImpl() { } case '(': return ParseParenExpr(); default: - fprintf(stderr, "error: unknown token '%c' (%d) at line %d when expecting an expression\n", + cps::sourceDiagnostic(Lex.getLine(), "error: unknown token '%c' (%d) at line %d when expecting an expression\n", (char)CurTok, CurTok, Lex.getLine()); return nullptr; } @@ -220,14 +221,14 @@ std::unique_ptr<ExprAST> Parser::ParseUnaryImpl() { 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", + cps::sourceDiagnostic(Lex.getLine(), "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); + cps::sourceDiagnostic(Lex.getLine(), "error: cannot take the address of a function result at line %d\n", Line); return nullptr; } std::vector<DesignatorAccess> Accesses; @@ -294,7 +295,7 @@ std::optional<std::vector<std::unique_ptr<ExprAST>>> Parser::ParseExprList(char if (CurTok == CloseDelim) break; if (CurTok != ',') { - fprintf(stderr, "error: Expected ',' or '%c' at line %d\n", CloseDelim, Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or '%c' at line %d\n", CloseDelim, Lex.getLine()); return std::nullopt; } getNextToken(); diff --git a/lib/Parser/ParserFile.cc b/lib/Parser/ParserFile.cc index 9aa4979..99a939f 100644 --- a/lib/Parser/ParserFile.cc +++ b/lib/Parser/ParserFile.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/Parser.h" #include "cps/FileAST.h" #include <cstdio> @@ -13,7 +14,7 @@ std::unique_ptr<StmtAST> Parser::ParseOpenFile() { if (!FileName) return nullptr; if (CurTok != tok_for) { - fprintf(stderr, "error: Expected FOR after OPENFILE filename at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected FOR after OPENFILE filename at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); // eat FOR @@ -24,11 +25,11 @@ std::unique_ptr<StmtAST> Parser::ParseOpenFile() { case tok_write: Mode = FileMode::Write; break; case tok_append: Mode = FileMode::Append; break; case tok_random: - fprintf(stderr, "error: File mode RANDOM is not implemented (text files only) at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: File mode RANDOM is not implemented (text files only) at line %d\n", Lex.getLine()); return nullptr; default: - fprintf(stderr, "error: Expected file mode READ, WRITE or APPEND at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected file mode READ, WRITE or APPEND at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); // eat the mode keyword @@ -45,13 +46,13 @@ std::unique_ptr<StmtAST> Parser::ParseReadFile() { if (!FileName) return nullptr; if (CurTok != ',') { - fprintf(stderr, "error: Expected ',' after READFILE filename at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' after READFILE filename at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); // eat ',' if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected variable name after ',' in READFILE at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected variable name after ',' in READFILE at line %d\n", Lex.getLine()); return nullptr; } std::string VarName = Lex.IdentifierStr; @@ -61,7 +62,7 @@ std::unique_ptr<StmtAST> Parser::ParseReadFile() { // Consume the whole designator so it cannot replay as statements. std::vector<DesignatorAccess> Dummy; ParseDesignatorSuffix(Dummy); - fprintf(stderr, "error: READFILE target must be a plain STRING variable at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: READFILE target must be a plain STRING variable at line %d\n", Line); return nullptr; } @@ -77,7 +78,7 @@ std::unique_ptr<StmtAST> Parser::ParseWriteFile() { if (!FileName) return nullptr; if (CurTok != ',') { - fprintf(stderr, "error: Expected ',' after WRITEFILE filename at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' after WRITEFILE filename at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); // eat ',' diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc index e4e635e..fa46dcf 100644 --- a/lib/Parser/ParserFunction.cc +++ b/lib/Parser/ParserFunction.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/Parser.h" #include "cps/FunctionAST.h" #include <cstdio> @@ -13,7 +14,7 @@ bool Parser::ParseSignedIntBound(int64_t &Out) { getNextToken(); } if (CurTok != tok_number_int) { - fprintf(stderr, "error: Array parameter bounds must be integer literals at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Array parameter bounds must be integer literals at line %d\n", Lex.getLine()); return false; } @@ -35,7 +36,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef while (CurTok != ')') { if (CurTok == tok_byref) { if (!AllowByRef) { - fprintf(stderr, "error: BYREF parameters are not allowed in a FUNCTION (procedures only) at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: BYREF parameters are not allowed in a FUNCTION (procedures only) at line %d\n", Lex.getLine()); return std::nullopt; } @@ -47,7 +48,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef } if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected argument name at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected argument name at line %d\n", Lex.getLine()); return std::nullopt; } ParamDecl P; @@ -57,7 +58,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef getNextToken(); if (CurTok != tok_colon) { - fprintf(stderr, "error: Expected ':' after argument name at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' after argument name at line %d\n", Lex.getLine()); return std::nullopt; } getNextToken(); @@ -71,7 +72,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef int64_t Lo = 0, Hi = 0; if (!ParseSignedIntBound(Lo)) return std::nullopt; if (CurTok != tok_colon) { - fprintf(stderr, "error: Expected ':' between array parameter bounds at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' between array parameter bounds at line %d\n", Lex.getLine()); return std::nullopt; } @@ -80,7 +81,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef P.DeclaredBounds.emplace_back(Lo, Hi); if (CurTok == ']') break; if (CurTok != ',') { - fprintf(stderr, "error: Expected ',' or ']' in array parameter bounds at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ']' in array parameter bounds at line %d\n", Lex.getLine()); return std::nullopt; } @@ -92,7 +93,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef P.Rank = 1; // ARRAY OF T: bounds travel with the argument } if (CurTok != tok_of) { - fprintf(stderr, "error: Expected OF after ARRAY in parameter '%s' at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Expected OF after ARRAY in parameter '%s' at line %d\n", P.Name.c_str(), Lex.getLine()); return std::nullopt; } @@ -101,13 +102,13 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef P.TypeName = ParseTypeName(false); if (P.TypeName.empty()) { - fprintf(stderr, "error: Expected argument type for '%s'\n", P.Name.c_str()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected argument type for '%s'\n", P.Name.c_str()); return std::nullopt; } for (const ParamDecl &Prev : Params) { if (sameIdentifier(Prev.Name, P.Name)) { - fprintf(stderr, "error: Duplicate parameter name '%s' at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Duplicate parameter name '%s' at line %d\n", P.Name.c_str(), Lex.getLine()); return std::nullopt; } @@ -116,12 +117,12 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef if (CurTok == ')') break; if (CurTok != ',') { - fprintf(stderr, "error: Expected ',' or ')'\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ')'\n"); return std::nullopt; } getNextToken(); if (CurTok == ')') { - fprintf(stderr, "error: Expected another parameter after ',' at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected another parameter after ',' at line %d\n", Lex.getLine()); return std::nullopt; } } @@ -133,15 +134,15 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl int Line = Lex.getLine(); getNextToken(); if (CurTok == tok_delete || (CurTok == tok_identifier && sameIdentifier(Lex.IdentifierStr, "DELETE"))) { - fprintf(stderr, "error: destructor DELETE must be a PROCEDURE at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: destructor DELETE must be a PROCEDURE at line %d\n", Line); return nullptr; } if (CurTok == tok_new || (CurTok == tok_identifier && sameIdentifier(Lex.IdentifierStr, "NEW"))) { - fprintf(stderr, "error: constructor NEW must be a PROCEDURE at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: constructor NEW must be a PROCEDURE at line %d\n", Line); return nullptr; } if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected function name\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected function name\n"); return nullptr; } @@ -155,13 +156,13 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl if (CurTok == tok_returns) { getNextToken(); if (CurTok == tok_array) { - fprintf(stderr, "error: A FUNCTION cannot RETURN an array; use a BYREF PROCEDURE parameter instead at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: A FUNCTION cannot RETURN an array; use a BYREF PROCEDURE parameter instead at line %d\n", Lex.getLine()); return nullptr; } RetType = ParseTypeName(true); if (RetType.empty()) { - fprintf(stderr, "error: Expected return type for function '%s'\n", Name.c_str()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected return type for function '%s'\n", Name.c_str()); return nullptr; } } @@ -171,7 +172,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_endfunction}); if (CurTok != tok_endfunction) { - fprintf(stderr, "error: expected ENDFUNCTION\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDFUNCTION\n"); return nullptr; } getNextToken(); @@ -185,17 +186,17 @@ std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerC int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_identifier && CurTok != tok_new && CurTok != tok_delete) { - fprintf(stderr, "error: Expected procedure name\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected procedure name\n"); return nullptr; } std::string Name = CurTok == tok_new ? "NEW" : CurTok == tok_delete ? "DELETE" : Lex.IdentifierStr; if (OwnerClass.empty() && sameIdentifier(Name, "DELETE")) { - fprintf(stderr, "error: destructor DELETE is only allowed in a CLASS at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: destructor DELETE is only allowed in a CLASS at line %d\n", Line); return nullptr; } if (OwnerClass.empty() && sameIdentifier(Name, "NEW")) { - fprintf(stderr, "error: constructor NEW is only allowed in a CLASS at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: constructor NEW is only allowed in a CLASS at line %d\n", Line); return nullptr; } getNextToken(); @@ -203,7 +204,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerC auto Args = ParsePrototypeArgs(/*AllowByRef=*/true); if (!Args) return nullptr; if (sameIdentifier(Name, "DELETE") && !Args->empty()) { - fprintf(stderr, "error: destructor DELETE must have no parameters at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: destructor DELETE must have no parameters at line %d\n", Line); return nullptr; } auto Proto = std::make_unique<PrototypeAST>(Name, std::move(*Args), "VOID", false, OwnerClass, IsPublic); @@ -211,7 +212,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerC std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_endprocedure}); if (CurTok != tok_endprocedure) { - fprintf(stderr, "error: expected ENDPROCEDURE\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDPROCEDURE\n"); return nullptr; } getNextToken(); @@ -225,7 +226,7 @@ std::unique_ptr<StmtAST> Parser::ParseCallStmt() { int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected callee name after CALL\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected callee name after CALL\n"); return nullptr; } diff --git a/lib/Parser/ParserType.cc b/lib/Parser/ParserType.cc index dfeacf1..b67558f 100644 --- a/lib/Parser/ParserType.cc +++ b/lib/Parser/ParserType.cc @@ -1,3 +1,4 @@ +#include "cps/Diagnostics.h" #include "cps/Parser.h" #include "cps/TypeAST.h" #include <cstdio> @@ -22,7 +23,7 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { getNextToken(); // eat TYPE or CLASS if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected type name after %s at line %d\n", Keyword, Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected type name after %s at line %d\n", Keyword, Lex.getLine()); if (IsClass) ParseRecordBody("<unnamed>", Line, tok_endclass); return nullptr; } @@ -37,18 +38,18 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { if (CurTok == tok_c_type) { getNextToken(); if (CurTok != '(') { - fprintf(stderr, "error: Expected '(' after C_TYPE at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected '(' after C_TYPE at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); if (CurTok != tok_string_literal) { - fprintf(stderr, "error: C_TYPE requires a string literal at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: C_TYPE requires a string literal at line %d\n", Lex.getLine()); return nullptr; } std::string Expression = Lex.StringVal; getNextToken(); if (CurTok != ')') { - fprintf(stderr, "error: Expected ')' after C_TYPE string at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ')' after C_TYPE string at line %d\n", Lex.getLine()); return nullptr; } getNextToken(); @@ -58,7 +59,7 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { std::vector<std::string> Values; while (true) { if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected an enum value name in TYPE %s at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Expected an enum value name in TYPE %s at line %d\n", Name.c_str(), Lex.getLine()); return nullptr; } @@ -66,7 +67,7 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { getNextToken(); if (CurTok == ')') break; if (CurTok != ',') { - fprintf(stderr, "error: Expected ',' or ')' in TYPE %s at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ')' in TYPE %s at line %d\n", Name.c_str(), Lex.getLine()); return nullptr; } @@ -80,11 +81,11 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { if (Pointee.empty()) return nullptr; Decl = std::make_unique<PointerTypeDeclAST>(Name, Pointee); } else if (CurTok == tok_set) { - fprintf(stderr, "error: SET OF types are not implemented at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "error: SET OF types are not implemented at line %d\n", Lex.getLine()); getNextToken(); return nullptr; } else { - fprintf(stderr, "error: Expected '(', '^' or C_TYPE after '=' in TYPE %s at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Expected '(', '^' or C_TYPE after '=' in TYPE %s at line %d\n", Name.c_str(), Lex.getLine()); return nullptr; } @@ -99,7 +100,7 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { } if (!AtTopLevel) { - fprintf(stderr, "error: %s declarations are only allowed at top level at line %d\n", Keyword, Line); + cps::sourceDiagnostic(Lex.getLine(), "error: %s declarations are only allowed at top level at line %d\n", Keyword, Line); return nullptr; } TypeNames.insert(Name); @@ -136,7 +137,7 @@ std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody( } } else if (ParseRecordField(Fields, IsPublic)) continue; } else { - fprintf(stderr, "error: Expected %s or %s in %s %s at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Expected %s or %s in %s %s at line %d\n", IsClass ? "field, method, PUBLIC or PRIVATE" : "DECLARE", EndKeyword, Keyword, Name.c_str(), Lex.getLine()); } @@ -151,13 +152,13 @@ std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody( } } if (CurTok != EndToken) { - fprintf(stderr, "error: Expected %s in %s %s at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Expected %s in %s %s at line %d\n", EndKeyword, Keyword, Name.c_str(), Lex.getLine()); return std::nullopt; } getNextToken(); // eat body terminator if (Fields.empty() && (!Methods || Methods->empty()) && !HadFieldError) { - fprintf(stderr, "error: %s %s has no %s at line %d\n", Keyword, Name.c_str(), + cps::sourceDiagnostic(Lex.getLine(), "error: %s %s has no %s at line %d\n", Keyword, Name.c_str(), IsClass ? "members" : "fields", Line); return std::nullopt; } @@ -171,21 +172,21 @@ bool Parser::ParseRecordField(std::vector<RecordFieldDecl> &Out, bool IsPublic) : CurTok == tok_public ? "PUBLIC" : "PRIVATE"; 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()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected field name after %s at line %d\n", Introducer, Lex.getLine()); return false; } std::string FieldName = Lex.IdentifierStr; getNextToken(); if (CurTok != tok_colon) { - fprintf(stderr, "error: Expected ':' after field name %s at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' after field name %s at line %d\n", FieldName.c_str(), Lex.getLine()); return false; } getNextToken(); if (CurTok == tok_array) { - fprintf(stderr, "error: Array fields inside records are not implemented at line %d\n", + cps::sourceDiagnostic(Lex.getLine(), "error: Array fields inside records are not implemented at line %d\n", Lex.getLine()); return false; } @@ -228,14 +229,14 @@ std::string Parser::ParseTypeName(bool AllowVoid) { if (CurTok == tok_identifier) { std::string TypeName = Lex.IdentifierStr; if (!AllowVoid && sameIdentifier(TypeName, "VOID")) { - fprintf(stderr, "error: VOID is not allowed here\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: VOID is not allowed here\n"); return ""; } getNextToken(); return TypeName; } - fprintf(stderr, "error: Unknown type name\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: Unknown type name\n"); return ""; } @@ -243,14 +244,14 @@ std::string Parser::ParseTypeName(bool AllowVoid) { std::unique_ptr<StmtAST> Parser::ParseDeclare() { getNextToken(); if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected identifier after DECLARE at line %d\n", Lex.getLine()); + cps::sourceDiagnostic(Lex.getLine(), "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()); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' after variable name '%s' at line %d\n", Name.c_str(), Lex.getLine()); return nullptr; } getNextToken(); @@ -258,7 +259,7 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() { if (CurTok == tok_array) { getNextToken(); if (CurTok != '[') { - fprintf(stderr, "error: Expected '[' after ARRAY\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected '[' after ARRAY\n"); return nullptr; } getNextToken(); @@ -270,7 +271,7 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() { if (!Lower) return nullptr; if (CurTok != tok_colon) { - fprintf(stderr, "error: Expected ':' in array range (e.g. 1:10)\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' in array range (e.g. 1:10)\n"); return nullptr; } getNextToken(); @@ -285,13 +286,13 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() { getNextToken(); continue; } - fprintf(stderr, "error: Expected ',' or ']' in array dims\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ']' in array dims\n"); return nullptr; } getNextToken(); if (CurTok != tok_of) { - fprintf(stderr, "error: Expected OF after array dims\n"); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected OF after array dims\n"); return nullptr; } getNextToken(); @@ -324,13 +325,13 @@ std::unique_ptr<StmtAST> Parser::ParseConstant() { int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_identifier) { - fprintf(stderr, "error: Expected identifier after CONSTANT at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected identifier after CONSTANT at line %d\n", Line); return nullptr; } std::string Name = Lex.IdentifierStr; getNextToken(); if (CurTok != tok_eq) { - fprintf(stderr, "error: Expected '=' in CONSTANT declaration at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: Expected '=' in CONSTANT declaration at line %d\n", Line); return nullptr; } getNextToken(); @@ -340,7 +341,7 @@ std::unique_ptr<StmtAST> Parser::ParseConstant() { bool Literal = Numeric || CurTok == tok_true || CurTok == tok_false || CurTok == tok_string_literal || CurTok == tok_char_literal; if (!Literal || (Negative && !Numeric)) { - fprintf(stderr, "error: CONSTANT initializer must be a literal at line %d\n", Line); + cps::sourceDiagnostic(Lex.getLine(), "error: CONSTANT initializer must be a literal at line %d\n", Line); return nullptr; } std::unique_ptr<ExprAST> Value; @@ -356,7 +357,7 @@ std::unique_ptr<StmtAST> Parser::ParseConstant() { 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); + cps::sourceDiagnostic(Lex.getLine(), "error: CONSTANT initializer must be a literal, not an expression, at line %d\n", Line); return nullptr; } return std::make_unique<ConstantStmtAST>(std::move(Name), std::move(Value)); |
