aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/ArithmeticHandler.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-07-26 15:45:40 +0000
committer_ov4 <ov4@ov4.org>2026-07-26 15:45:40 +0000
commit344206d57e834b2394cbe2ec0df50b04a8b3c171 (patch)
tree0eb282bc9878bf990496a5d840ca8492b3cfc508 /lib/CodeGen/ArithmeticHandler.cc
parentd1c47a328785ece9a8ffd9bbca3138818b8203b3 (diff)
feat: implement CIE 9.1 text file handling (OPENFILE/READFILE/WRITEFILE/CLOSEFILE/EOF)
Front end: OPENFILE/READFILE/WRITEFILE/CLOSEFILE plus reserved mode keywords READ/WRITE/APPEND (RANDOM reserved with a dedicated not-implemented error); statement nodes in new FileAST.h, parsing in new ParserFile.cc; EOF joins the Builtins table as the 12th builtin and CallExprAST now carries a line number for its runtime diagnostics. Runtime: new FileHandler (StringHandler-shaped leaf) lazily synthesizes internal __cps_file_* helper functions and a 16-slot open-file table keyed by filename content (strcmp — STRING '=' is pointer identity). EOF is an fgetc/ungetc peek; READFILE grows a malloc/realloc line buffer and strips a trailing CR; fopen uses text modes so mingw-w64 line translation works. File-free programs get byte-identical IR. All misuse (not open, wrong mode, reopen, fopen failure, read past EOF, table full) dies with the existing "[Fatal] line N:" pattern via a new RuntimeCheck::emitErrorAndExit overload taking runtime printf args. Also fixes a pre-existing ArithmeticHandler hole surfaced by adversarial review: mixed-width integer operands (i1 BOOLEAN / i8 CHAR vs i64) now widen via ZExt instead of emitting invalid IR, and remaining type mismatches get a clean diagnostic; -EOF(f) and -IS_NUM(x) compile. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/ArithmeticHandler.cc')
-rw-r--r--lib/CodeGen/ArithmeticHandler.cc60
1 files changed, 45 insertions, 15 deletions
diff --git a/lib/CodeGen/ArithmeticHandler.cc b/lib/CodeGen/ArithmeticHandler.cc
index bfee395..439e4b1 100644
--- a/lib/CodeGen/ArithmeticHandler.cc
+++ b/lib/CodeGen/ArithmeticHandler.cc
@@ -5,6 +5,16 @@
using namespace llvm;
using namespace cps;
+// Widen an i1 (BOOLEAN) or i8 (CHAR) operand to i64 with the same ZExt
+// coerceValueToType uses, so a mixed pair like EOF(f) - 1 cannot reach the
+// instruction builders with mismatched integer widths (invalid IR).
+static Value *widenSmallInt(IRBuilder<> &Builder, LLVMContext &Context, Value *V) {
+ Type *Ty = V->getType();
+ if (Ty->isIntegerTy() && Ty->getIntegerBitWidth() < 64)
+ return Builder.CreateZExt(V, Type::getInt64Ty(Context), "widetmp");
+ return V;
+}
+
Value *ArithmeticHandler::emitBinaryOp(int Op, Value *LHS, Value *RHS, int Line) {
bool LIsInt = LHS->getType()->isIntegerTy(64);
bool RIsInt = RHS->getType()->isIntegerTy(64);
@@ -12,11 +22,16 @@ Value *ArithmeticHandler::emitBinaryOp(int Op, Value *LHS, Value *RHS, int Line)
bool RIsDouble = RHS->getType()->isDoubleTy();
if (Op == '/') {
- Value *LVal = LHS;
- Value *RVal = RHS;
- if (LIsInt) LVal = Builder.CreateSIToFP(LHS, Type::getDoubleTy(Context));
- if (RIsInt) RVal = Builder.CreateSIToFP(RHS, Type::getDoubleTy(Context));
-
+ Value *LVal = widenSmallInt(Builder, Context, LHS);
+ Value *RVal = widenSmallInt(Builder, Context, RHS);
+ 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);
+ HadError = true;
+ return nullptr;
+ }
+
// TODO: DIV divide by 0 runtime check
return Builder.CreateFDiv(LVal, RVal, "divtmp");
}
@@ -68,17 +83,32 @@ Value *ArithmeticHandler::emitBinaryOp(int Op, Value *LHS, Value *RHS, int Line)
case tok_ge: return Builder.CreateFCmpOGE(LVal, RVal, "sgetmp");
}
} else {
+ // Same-type pairs (i64/i64, i8/i8 CHAR, i1/i1, ptr/ptr STRING) go
+ // through untouched; mixed integer widths are widened, anything else
+ // mismatched is a diagnostic instead of invalid IR.
+ Value *L = LHS;
+ Value *R = RHS;
+ if (L->getType() != R->getType() &&
+ L->getType()->isIntegerTy() && R->getType()->isIntegerTy()) {
+ L = widenSmallInt(Builder, Context, L);
+ R = widenSmallInt(Builder, Context, R);
+ }
+ if (L->getType() != R->getType()) {
+ fprintf(stderr, "Error: Mismatched operand types for binary operator (line %d).\n", Line);
+ HadError = true;
+ return nullptr;
+ }
switch (Op) {
- case '+': return Builder.CreateAdd(LHS, RHS, "addtmp");
- case '-': return Builder.CreateSub(LHS, RHS, "subtmp");
- case '*': return Builder.CreateMul(LHS, RHS, "multmp");
-
- case tok_eq: return Builder.CreateICmpEQ(LHS, RHS, "eqtmp");
- case tok_ne: return Builder.CreateICmpNE(LHS, RHS, "netmp");
- case '<': return Builder.CreateICmpSLT(LHS, RHS, "slttmp");
- case '>': return Builder.CreateICmpSGT(LHS, RHS, "sgttmp");
- case tok_le: return Builder.CreateICmpSLE(LHS, RHS, "sletmp");
- case tok_ge: return Builder.CreateICmpSGE(LHS, RHS, "sgetmp");
+ case '+': return Builder.CreateAdd(L, R, "addtmp");
+ case '-': return Builder.CreateSub(L, R, "subtmp");
+ case '*': return Builder.CreateMul(L, R, "multmp");
+
+ case tok_eq: return Builder.CreateICmpEQ(L, R, "eqtmp");
+ case tok_ne: return Builder.CreateICmpNE(L, R, "netmp");
+ case '<': return Builder.CreateICmpSLT(L, R, "slttmp");
+ case '>': return Builder.CreateICmpSGT(L, R, "sgttmp");
+ case tok_le: return Builder.CreateICmpSLE(L, R, "sletmp");
+ case tok_ge: return Builder.CreateICmpSGE(L, R, "sgetmp");
}
}