aboutsummaryrefslogtreecommitdiff
path: root/lib/Parser
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-17 15:02:01 +0000
committer_ov4 <ov4@ov4.org>2026-10-17 15:02:01 +0000
commita29cb23c5517fd4f8f5524fdf38b67ff5fe4a902 (patch)
treea3bfa1a30a16c03f420cbe706fd42143d653064d /lib/Parser
parent4a34e970fb224be7640883f6b0dfa602157759f4 (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.cc24
-rw-r--r--lib/Parser/ParserFunction.cc89
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();