diff options
| author | _ov4 <ov4@ov4.org> | 2026-07-26 15:45:40 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-07-26 15:45:40 +0000 |
| commit | 344206d57e834b2394cbe2ec0df50b04a8b3c171 (patch) | |
| tree | 0eb282bc9878bf990496a5d840ca8492b3cfc508 /lib/CodeGen/ArithmeticHandler.cc | |
| parent | d1c47a328785ece9a8ffd9bbca3138818b8203b3 (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.cc | 60 |
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"); } } |
