aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-17 05:08:42 +0000
committer_ov4 <ov4@ov4.org>2026-10-17 05:08:42 +0000
commita6b8afcfb61e1d321405fe8713beaec2aa6320a2 (patch)
treea621462bd6f858d1e78495e8c850a2e7321f4809 /lib
parent5c3d4d059ae70ea72b52e89940746d61c1d962db (diff)
feat(input): support array elements and member targets
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/CTypeGen.cc6
-rw-r--r--lib/CodeGen/StatementGen.cc29
-rw-r--r--lib/Parser/Parser.cc19
3 files changed, 24 insertions, 30 deletions
diff --git a/lib/CodeGen/CTypeGen.cc b/lib/CodeGen/CTypeGen.cc
index 80a7d3b..7623103 100644
--- a/lib/CodeGen/CTypeGen.cc
+++ b/lib/CodeGen/CTypeGen.cc
@@ -177,7 +177,7 @@ void CodeGen::emitCOutput(Value *Val, const TypeInfo *Info, bool AppendNewline)
Builder->CreateCall(PrintfFunc, {Fmt, Val});
}
-void CodeGen::emitCInput(const SymbolInfo *Symbol, const TypeInfo *Info) {
+void CodeGen::emitCInput(Value *Addr, const TypeInfo *Info) {
if (Info->Kind != TypeKind::CScalar || Info->isVoid()) {
reportError("INPUT is not supported for C pointer or void type %s", Info->Name.c_str());
return;
@@ -191,9 +191,9 @@ void CodeGen::emitCInput(const SymbolInfo *Symbol, const TypeInfo *Info) {
Builder->CreateCall(ScanfFunc, {Fmt, Temp});
Value *Input = Builder->CreateLoad(NativeInt->LLVMType, Temp);
Value *Bool = convertNumericValue(Input, NativeInt, Info);
- Builder->CreateStore(Bool, Symbol->Storage);
+ Builder->CreateStore(Bool, Addr);
return;
}
Value *Fmt = Builder->CreateGlobalString(Info->CInputFormat, "fmt_c_input", 0, TheModule.get());
- Builder->CreateCall(ScanfFunc, {Fmt, Symbol->Storage});
+ Builder->CreateCall(ScanfFunc, {Fmt, Addr});
}
diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc
index 3ea0670..2c80437 100644
--- a/lib/CodeGen/StatementGen.cc
+++ b/lib/CodeGen/StatementGen.cc
@@ -121,29 +121,20 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
}
if (auto *In = dynamic_cast<InputStmtAST*>(Stmt)) {
- const SymbolInfo *Info = getSymbolInfo(In->getName());
- if (!Info) {
- reportError("Unknown variable name %s", In->getName().c_str());
- return;
- }
- if (!requireWritable(*Info, In->getName())) return;
- if (Info->IsArray) {
- reportError("INPUT for entire array %s is not supported", In->getName().c_str());
- return;
- }
-
- const TypeInfo *TypeInfo = resolveType(Info->TypeName);
+ LValueInfo Target;
+ if (!emitLValue(In->getTarget(), Target)) return;
+ const TypeInfo *TypeInfo = resolveType(Target.TypeName);
if (!TypeInfo) {
- reportError("Unknown type for INPUT %s", In->getName().c_str());
+ reportError("Unknown type for INPUT %s", Target.TypeName.c_str());
return;
}
std::vector<Value*> Args;
if (TypeInfo->isC()) {
- emitCInput(Info, TypeInfo);
+ emitCInput(Target.Addr, TypeInfo);
} else if (TypeInfo->isReal()) {
Args.push_back(ScanfFloatFormatStr);
- Args.push_back(Info->Storage);
+ Args.push_back(Target.Addr);
Builder->CreateCall(ScanfFunc, Args);
} else if (TypeInfo->isBoolean()) {
AllocaInst *TempInt = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), "tmp_bool_input");
@@ -153,21 +144,21 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), TempInt);
Value *BoolVal = Builder->CreateICmpNE(Val, ConstantInt::get(*TheContext, APInt(64, 0)), "bool_cast");
- Builder->CreateStore(BoolVal, Info->Storage);
+ Builder->CreateStore(BoolVal, Target.Addr);
} else if (TypeInfo->isString()) {
Value *Mem = Builder->CreateCall(MallocFunc, ConstantInt::get(*TheContext, APInt(64, 1024)), "input_str");
Args.push_back(ScanfStringFormatStr);
Args.push_back(Mem);
Builder->CreateCall(ScanfFunc, Args);
- Builder->CreateStore(Mem, Info->Storage);
+ Builder->CreateStore(Mem, Target.Addr);
} else if (TypeInfo->isChar()) {
Value *CharFmt = Builder->CreateGlobalString(" %c", "fmt_in_char", 0, TheModule.get());
Args.push_back(CharFmt);
- Args.push_back(Info->Storage);
+ Args.push_back(Target.Addr);
Builder->CreateCall(ScanfFunc, Args);
} else if (TypeInfo->Kind == TypeKind::Integer) {
Args.push_back(ScanfFormatStr);
- Args.push_back(Info->Storage);
+ Args.push_back(Target.Addr);
Builder->CreateCall(ScanfFunc, Args);
} else {
// Enum/Record/Pointer and any future kind: scanf'ing raw bytes
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc
index f2fcbc8..d4d04d2 100644
--- a/lib/Parser/Parser.cc
+++ b/lib/Parser/Parser.cc
@@ -116,14 +116,17 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() {
std::string Name = Lex.IdentifierStr;
int Line = Lex.getLine();
getNextToken();
- if (CurTok == '[' || CurTok == '.' || CurTok == '^') {
- // Consume the whole designator so it cannot replay as statements.
- std::vector<DesignatorAccess> Dummy;
- ParseDesignatorSuffix(Dummy);
- fprintf(stderr, "error: INPUT target must be a plain variable at line %d\n", Line);
- return nullptr;
- }
- return std::make_unique<InputStmtAST>(Name);
+ std::vector<DesignatorAccess> Accesses;
+ if (!ParseDesignatorSuffix(Accesses)) return nullptr;
+ std::unique_ptr<ExprAST> Target;
+ if (Accesses.empty())
+ Target = std::make_unique<VariableExprAST>(Name);
+ else if (Accesses.size() == 1 && Accesses[0].Kind == AccessKind::Index)
+ Target = std::make_unique<ArrayAccessExprAST>(Name, std::move(Accesses[0].Indices), Line);
+ else
+ Target = std::make_unique<DesignatorExprAST>(Name, std::move(Accesses), Line);
+ Target->setLine(Line);
+ return std::make_unique<InputStmtAST>(std::move(Target));
}
else if (CurTok == tok_output) {
getNextToken();