diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-17 15:02:01 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-17 15:02:01 +0000 |
| commit | a29cb23c5517fd4f8f5524fdf38b67ff5fe4a902 (patch) | |
| tree | a3bfa1a30a16c03f420cbe706fd42143d653064d /lib/Parser | |
| parent | 4a34e970fb224be7640883f6b0dfa602157759f4 (diff) | |
feat(parser): parse EXTERN "C" declarations and INCLUDE_OBJ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/Parser')
| -rw-r--r-- | lib/Parser/Parser.cc | 24 | ||||
| -rw-r--r-- | lib/Parser/ParserFunction.cc | 89 |
2 files changed, 107 insertions, 6 deletions
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc index f7817ec..f22e3c6 100644 --- a/lib/Parser/Parser.cc +++ b/lib/Parser/Parser.cc @@ -47,6 +47,7 @@ void Parser::syncToStatementStart() { while (CurTok != tok_eof) { switch (CurTok) { case tok_include: case tok_global: case tok_endglobal: + case tok_include_obj: case tok_extern: case tok_delete: case tok_constant: case tok_declare: case tok_identifier: case tok_input: case tok_output: case tok_case: case tok_endcase: case tok_otherwise: case tok_if: case tok_while: case tok_repeat: case tok_for: @@ -96,21 +97,32 @@ std::unique_ptr<StmtAST> Parser::ParseStatement() { } std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { - if (CurTok == tok_include || CurTok == tok_global) { - bool Include = CurTok == tok_include; + if (CurTok == tok_extern) { + if (BlockDepth != 1) { + sourceDiagnostic(Lex.getLine(), "error: EXTERN is only allowed at top level at line %d\n", Lex.getLine()); + getNextToken(); + return nullptr; + } + return ParseExternDecl(); + } + if (CurTok == tok_include || CurTok == tok_include_obj || CurTok == tok_global) { + const char *Keyword = CurTok == tok_include ? "INCLUDE" : CurTok == tok_include_obj ? "INCLUDE_OBJ" : "GLOBAL"; + bool Object = CurTok == tok_include_obj; + bool Include = Object || CurTok == tok_include; int Line = Lex.getLine(); getNextToken(); if (BlockDepth != 1) { - sourceDiagnostic(Line, "error: %s is only allowed at top level at line %d\n", - Include ? "INCLUDE" : "GLOBAL", Line); + sourceDiagnostic(Line, "error: %s is only allowed at top level at line %d\n", Keyword, Line); return nullptr; } if (Include) { if (CurTok != tok_string_literal) { - sourceDiagnostic(Line, "error: INCLUDE requires a string literal at line %d\n", Line); + sourceDiagnostic(Line, "error: %s requires a string literal at line %d\n", Keyword, Line); return nullptr; } - auto Stmt = std::make_unique<IncludeStmtAST>(Lex.StringVal); + std::unique_ptr<StmtAST> Stmt; + if (Object) Stmt = std::make_unique<IncludeObjStmtAST>(Lex.StringVal); + else Stmt = std::make_unique<IncludeStmtAST>(Lex.StringVal); getNextToken(); return Stmt; } diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc index 3df324c..7686f51 100644 --- a/lib/Parser/ParserFunction.cc +++ b/lib/Parser/ParserFunction.cc @@ -222,6 +222,95 @@ std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerC return Def; } +// EXTERN "C" EXTERN_FUNCTION <name>(<type>, ... [, ...]) RETURNS <type> +// EXTERN "C" EXTERN_PROCEDURE <name>(<type>, ... [, ...]) +// Parameters are unnamed; a trailing ... makes the prototype variadic. +std::unique_ptr<StmtAST> Parser::ParseExternDecl() { + int Line = Lex.getLine(); + getNextToken(); + if (CurTok != tok_string_literal || Lex.StringVal != "C") { + cps::sourceDiagnostic(Lex.getLine(), "error: EXTERN must be followed by \"C\" at line %d\n", Lex.getLine()); + return nullptr; + } + getNextToken(); + if (CurTok != tok_extern_function && CurTok != tok_extern_procedure) { + cps::sourceDiagnostic(Lex.getLine(), "error: Expected EXTERN_FUNCTION or EXTERN_PROCEDURE after EXTERN \"C\" at line %d\n", + Lex.getLine()); + return nullptr; + } + bool IsFunction = CurTok == tok_extern_function; + getNextToken(); + if (CurTok != tok_identifier) { + cps::sourceDiagnostic(Lex.getLine(), "error: Expected C function name at line %d\n", Lex.getLine()); + return nullptr; + } + std::string Name = Lex.IdentifierStr; + getNextToken(); + + std::vector<ParamDecl> Params; + bool IsVariadic = false; + if (CurTok != '(') { + cps::sourceDiagnostic(Lex.getLine(), "error: Expected '(' after C function name '%s' at line %d\n", + Name.c_str(), Lex.getLine()); + return nullptr; + } + getNextToken(); + while (CurTok != ')') { + if (CurTok == tok_ellipsis) { + IsVariadic = true; + getNextToken(); + if (CurTok != ')') { + cps::sourceDiagnostic(Lex.getLine(), "error: '...' must be the last parameter at line %d\n", Lex.getLine()); + return nullptr; + } + break; + } + if (CurTok == tok_byref || CurTok == tok_byval) { + cps::sourceDiagnostic(Lex.getLine(), "error: EXTERN parameters cannot be BYREF or BYVAL; use a C pointer type at line %d\n", + Lex.getLine()); + return nullptr; + } + ParamDecl P; + P.Line = Lex.getLine(); + P.TypeName = ParseTypeName(false); + if (P.TypeName.empty()) return nullptr; + P.Name = "arg" + std::to_string(Params.size() + 1); + Params.push_back(std::move(P)); + if (CurTok == ')') break; + if (CurTok != ',') { + cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ')' at line %d\n", Lex.getLine()); + return nullptr; + } + getNextToken(); + if (CurTok == ')') { + cps::sourceDiagnostic(Lex.getLine(), "error: Expected another parameter after ',' at line %d\n", Lex.getLine()); + return nullptr; + } + } + getNextToken(); + + std::string RetType = "VOID"; + if (CurTok == tok_returns) { + if (!IsFunction) { + cps::sourceDiagnostic(Lex.getLine(), "error: EXTERN_PROCEDURE cannot have RETURNS at line %d\n", Lex.getLine()); + return nullptr; + } + getNextToken(); + RetType = ParseTypeName(false); + if (RetType.empty()) return nullptr; + } else if (IsFunction) { + cps::sourceDiagnostic(Lex.getLine(), "error: EXTERN_FUNCTION '%s' requires RETURNS at line %d\n", + Name.c_str(), Line); + return nullptr; + } + + auto Proto = std::make_unique<PrototypeAST>(Name, std::move(Params), RetType, /*IsExternal=*/true); + Proto->setVariadic(IsVariadic); + auto Decl = std::make_unique<ExternDeclAST>(std::move(Proto)); + Decl->setLine(Line); + return Decl; +} + std::unique_ptr<StmtAST> Parser::ParseCallStmt() { int Line = Lex.getLine(); getNextToken(); |
