From 0d88339f762a682a093a8c65566a7c5c73a5890c Mon Sep 17 00:00:00 2001 From: Ian Piumarta Date: Thu, 23 Jan 2025 13:43:59 +0900 Subject: [PATCH] handle for loops --- main.leg | 318 ++++++++++++++++++++++++++++++++++++++++++------------- test.txt | 1 + 2 files changed, 248 insertions(+), 71 deletions(-) diff --git a/main.leg b/main.leg index c057ad4..38c625f 100644 --- a/main.leg +++ b/main.leg @@ -1,6 +1,6 @@ # main.leg -- C parser + interpreter # -# Last edited: 2025-01-22 23:32:08 by piumarta on zora +# Last edited: 2025-01-23 13:43:27 by piumarta on zora %{ ; @@ -117,7 +117,7 @@ struct Dereference { type_t _type; oop rhs; }; struct Unary { type_t _type; unary_t operator; oop rhs; }; struct Binary { type_t _type; binary_t operator; oop lhs, rhs; }; struct Assign { type_t _type; oop lhs, rhs; }; -struct Cast { type_t _type; oop type, declarator, rhs; }; +struct Cast { type_t _type; oop type, rhs; }; struct While { type_t _type; oop condition, expression; }; struct For { type_t _type; oop initialiser, condition, update, body; }; struct If { type_t _type; oop condition, consequent, alternate; }; @@ -125,7 +125,9 @@ struct Return { type_t _type; oop value; }; struct Continue { type_t _type; }; struct Break { type_t _type; }; -struct Tbase { type_t _type; char *name; int size; }; +typedef enum { T_INT = 0, T_FLOAT, T_VOID, T_ETC } base_t; + +struct Tbase { type_t _type; char *name; int size; base_t type; }; struct Tpointer { type_t _type; oop target; }; struct Tarray { type_t _type; oop target; oop size; }; struct Tstruct { type_t _type; oop tag, members; }; @@ -142,41 +144,9 @@ struct VarDecls { type_t _type; oop type, declarations, variables; }; union Object { type_t _type; - struct Input Input; - struct Integer Integer; - struct Float Float; - struct Symbol Symbol; - struct Pair Pair; - struct String String; - struct Array Array; - struct Primitive Primitive; - struct Reference Reference; - struct Closure Closure; - struct Call Call; - struct Block Block; - struct Address Address; - struct Dereference Dereference; - struct Unary Unary; - struct Binary Binary; - struct Assign Assign; - struct Cast Cast; - struct For For; - struct While While; - struct If If; - struct Return Return; - struct Continue Continue; - struct Break Break; - struct Tbase Tbase; - struct Tpointer Tpointer; - struct Tarray Tarray; - struct Tstruct Tstruct; - struct Tfunction Tfunction; - struct Scope Scope; - struct TypeName TypeName; - struct Variable Variable; - struct Constant Constant; - struct Function Function; - struct VarDecls VarDecls; +# define _(X) struct X X; + _do_types(_) +# undef _ }; int opt_O = 0; // optimise (use VM) @@ -186,8 +156,9 @@ int opt_x = 0; // disable execution Object _nil = { ._type = Undefined }; #define nil (&_nil) -#define false (&_nil) -oop true = 0; + +oop false = 0; +oop true = 0; oop _new(size_t size, type_t type) { @@ -329,7 +300,7 @@ long integerValue(oop obj) case Float: return _floatValue(obj); default: break; } - fatal("cannot convert type %d to integer", getType(obj)); + fatal("cannot convert %s to integer", getTypeName(obj)); return 0; } @@ -615,7 +586,7 @@ oop newBinary(binary_t operator, oop lhs, oop rhs) } CTOR2(Assign, lhs, rhs); -CTOR3(Cast, type, declarator, rhs); +CTOR2(Cast, type, rhs); CTOR2(While, condition, expression); CTOR4(For, initialiser, condition, update, body); CTOR3(If, condition, consequent, alternate); @@ -626,11 +597,12 @@ CTOR0(Break); void println(oop obj); char *toString(oop obj); -oop newTbase(char *name, int size) +oop newTbase(char *name, int size, base_t type) { oop obj = new(Tbase); obj->Tbase.name = name; obj->Tbase.size = size; + obj->Tbase.type = type; return obj; } @@ -874,8 +846,7 @@ oop baseType(oop type) case Tpointer: return baseType(get(type, Tpointer,target)); case Tarray: return baseType(get(type, Tarray,target)); case Tfunction: return baseType(get(type, Tfunction,result)); - default: - fatal("cannot find base type of %s", getTypeName(type)); + default: fatal("cannot find base type of %s", getTypeName(type)); } return nil; } @@ -940,12 +911,19 @@ oop toStringOn(oop obj, oop str) char *chars = get(obj, String,elements); for (int i = 0, n = get(obj, String,size); i < n; ++i) { int c = chars[i]; - if (' ' <= c || c <= 126) String_append(str, c); + if ((' ' <= c) && (c <= 126)) String_append(str, c); else String_format(str, "\\x%02x", c); } String_append(str, '"'); break; } + case Cast: { + String_append(str, '('); + toStringOn(get(obj, Cast,type), str); + String_append(str, ')'); + toStringOn(get(obj, Cast,rhs), str); + break; + } case Unary: { char *name = 0; oop rhs = get(obj, Unary,rhs); @@ -963,7 +941,31 @@ oop toStringOn(oop obj, oop str) break; } case Binary: { - String_format(str, "%s", binaryName(get(obj, Binary,operator))); + char *name = 0; + char *lhs = toString(get(obj, Binary,lhs)); + char *rhs = toString(get(obj, Binary,rhs)); + switch (get(obj, Binary,operator)) { + case INDEX: String_format(str, "%s[%s]", lhs, rhs); return str; + case MUL: name = "*"; break; + case DIV: name = "/"; break; + case MOD: name = "%"; break; + case ADD: name = "+"; break; + case SUB: name = "-"; break; + case SHL: name = "<<"; break; + case SHR: name = ">>"; break; + case LT: name = "<"; break; + case LE: name = "<="; break; + case GE: name = ">"; break; + case GT: name = ">="; break; + case EQ: name = "=="; break; + case NE: name = "!="; break; + case BAND: name = "&"; break; + case BXOR: name = "^"; break; + case BOR: name = "|"; break; + case LAND: name = "&&"; break; + case LOR: name = "||"; break; + } + String_format(str, "%s %s %s", lhs, name, rhs); break; } case Assign: { @@ -972,6 +974,27 @@ oop toStringOn(oop obj, oop str) toStringOn(get(obj, Assign,rhs), str); break; } + case Call: { + toStringOn(get(obj, Call,function), str); + String_append(str, '('); + Array_do(get(obj, Call,arguments), arg) { + if (do_index) String_format(str, ", "); + toStringOn(arg, str); + } + String_append(str, ')'); + break; + } + case For: { + String_format(str, "for ("); + toStringOn(get(obj, For,initialiser), str); + String_format(str, "; "); + toStringOn(get(obj, For,condition), str); + String_format(str, "; "); + toStringOn(get(obj, For,update), str); + String_format(str, ") "); + toStringOn(get(obj, For,body), str); + break; + } case Tbase: String_format(str, "%s", get(obj, Tbase,name)); break; @@ -1167,7 +1190,6 @@ void printiln(oop obj, int indent) case Cast: { printf("CAST\n"); printiln(get(obj, Cast,type ), indent+1); - printiln(get(obj, Cast,declarator), indent+1); printiln(get(obj, Cast,rhs ), indent+1); break; } @@ -1496,7 +1518,7 @@ unary = MINUS r:unary { $$ = newUnary(NEG, r) } | postfix cast = LPAREN t:tname d:decltor - RPAREN r:unary { $$ = newCast(t, d, r) } + RPAREN r:unary { $$ = newCast(makeType(t, d), r) } postfix = v:value ( a:args { v = newCall(v, a) } | i:index { v = newBinary(INDEX, v, i) } @@ -1765,6 +1787,16 @@ void declarePrimitive(oop name, oop type, prim_t function) declare(name, newPrimitive(name, type, function)); } +oop incr(oop val, int amount) +{ + switch (getType(val)) { + case Integer: return newInteger(integerValue(val) + amount); + case Float: return newFloat ( floatValue(val) + amount); + default: fatal("cannot increment: %s", toString(val)); + } + return nil; +} + oop eval(oop exp, oop env) { if (opt_v > 2) { printf("EVAL "); println(exp); } @@ -1781,7 +1813,7 @@ oop eval(oop exp, oop env) case Variable: return get(value, Variable,value); case Function: return value; case Primitive: return value; - default: fatal("cannot convert to value: %s", toString(value)); + default: fatal("cannot eval: %s", toString(value)); } break; } @@ -1842,18 +1874,49 @@ oop eval(oop exp, oop env) break; } case Unary: { - oop rhs = eval(get(exp, Unary,rhs), env); - switch (get(exp, Unary,operator)) { - case NEG: return ( is(Float, rhs) - ? newFloat (-floatValue (rhs)) - : newInteger(-integerValue(rhs)) ); - case NOT: return isFalse(rhs) ? true : false; - case COM: return newInteger(~integerValue(rhs)); - case PREINC: assert(!"unimplemented"); - case PREDEC: assert(!"unimplemented"); - case POSTINC: assert(!"unimplemented"); - case POSTDEC: assert(!"unimplemented"); + unary_t op = get(exp, Unary,operator); + oop rhs = get(exp, Unary,rhs); + switch (op) { + case PREINC: + case PREDEC: + case POSTINC: + case POSTDEC: { + if (is(Symbol, rhs)) { + rhs = Scope_lookup(rhs); + switch (getType(rhs)) { + case Variable: { + oop val = get(rhs, Variable,value); + oop result = nil; + switch (op) { + case PREINC: val = incr(val, 1); result = val; break; + case PREDEC: val = incr(val, -1); result = val; break; + case POSTINC: result = val; val = incr(val, 1); break; + case POSTDEC: result = val; val = incr(val, -1); break; + default: assert("!this cannot happen"); + } + set(rhs, Variable,value, val); + return result; + } + default: break; + } + } + fatal("illegal increment operation: %s", toString(exp)); + } + case NEG: + case NOT: + case COM: { + rhs = eval(rhs, env); + switch (op) { + case NEG: return ( is(Float, rhs) + ? newFloat (-floatValue (rhs)) + : newInteger(-integerValue(rhs)) ); + case NOT: return isFalse(rhs) ? true : false; + case COM: return newInteger(~integerValue(rhs)); + default: break; + } + } } + assert("!this cannot happen"); break; } case Binary: { @@ -1947,7 +2010,44 @@ oop eval(oop exp, oop env) break; } case Cast: { - assert(!"unimplemented"); + oop lhs = get(exp, Cast,type); + oop rhs = eval(get(exp, Cast,rhs), nil); + switch (getType(rhs)) { + case Integer: + case Float: { + switch (getType(lhs)) { + case Tbase: { + switch (get(lhs, Tbase,type)) { + case T_INT: { + switch (get(lhs, Tbase,size)) { + case 1: return newInteger( (char)integerValue(rhs)); + case 2: return newInteger((short)integerValue(rhs)); + case 4: return newInteger( (int)integerValue(rhs)); + case 8: return rhs; + } + break; + } + case T_FLOAT: { + switch (get(lhs, Tbase,size)) { + case 4: return newFloat((float)floatValue(rhs)); + case 8: return newFloat(floatValue(rhs)); + } + break; + } + default: + break; + } + break; + } + default: + break; + } + break; + } + default: + break; + } + fatal("cannot convert '%s' to '%s'", toString(rhs), toString(lhs)); break; } case While: { @@ -1967,7 +2067,15 @@ oop eval(oop exp, oop env) return result; } case For: { - assert(!"unimplemented"); + oop init = get(exp, For,initialiser); + oop cond = get(exp, For,condition); + oop step = get(exp, For,update); + oop body = get(exp, For,body); + eval(init, nil); + while (integerValue(eval(cond, nil))) { + eval(body, nil); + eval(step, nil); + } return nil; } case If: { @@ -2610,6 +2718,19 @@ oop compile(oop exp) // 6*7 return program; } +int typeSize(oop type) +{ + switch (getType(type)) { + case Tbase: return get(type, Tbase,size); + case Tpointer: return 8; // fixme: make this a parameter + case Tstruct: assert(!"unimplemented"); + case Tarray: assert(!"unimplemented"); + case Tfunction: assert(!"unimplemented"); + default: assert(!"this cannot happen"); + } + return 0; +} + oop typeCheck(oop exp, oop fntype) { switch (getType(exp)) { @@ -2639,13 +2760,55 @@ oop typeCheck(oop exp, oop fntype) } return get(rhs, Tpointer,target); } + case Cast: { + oop lhs = get(exp, Cast,type); + oop rhs = typeCheck(get(exp, Cast,rhs), fntype); + switch (getType(lhs)) { + case Tbase: { // int, float, void, ... + if (get(lhs, Tbase,type) < T_VOID) { // int, float + switch (getType(rhs)) { + case Tbase: { + if (get(rhs, Tbase,type) < T_VOID) return lhs; + break; + } + case Tpointer: { + if (typeSize(lhs) != typeSize(rhs)) + fatal("casting pointer to integer of different size"); + return lhs; + default: + break; + } + } + } + break; + } + case Tpointer: { + switch (getType(rhs)) { + case Tbase: { + if (get(rhs, Tbase,type) < T_VOID) { + if (typeSize(lhs) == typeSize(rhs)) return lhs; + fatal("casting integer to pointer of different size"); + } + break; + } + case Tpointer: { + return lhs; + } + default: break; + } + } + default: break; + } + fatal("cannot convert '%s' to '%s'", toString(lhs), toString(rhs)); + return nil; + } case Unary: { oop rhs = typeCheck(get(exp, Unary,rhs), fntype); switch (get(exp, Unary,operator)) { case NEG: assert(!"unimplemented"); case NOT: assert(!"unimplemented"); case COM: assert(!"unimplemented"); - case PREINC: assert(!"unimplemented"); + case PREINC: return rhs; case PREDEC: assert(!"unimplemented"); case POSTINC: assert(!"unimplemented"); case POSTDEC: assert(!"unimplemented"); @@ -2670,7 +2833,7 @@ oop typeCheck(oop exp, oop fntype) case SUB: assert(!"unimplemented"); break; case SHL: assert(!"unimplemented"); break; case SHR: assert(!"unimplemented"); break; - case LT: assert(!"unimplemented"); break; + case LT: return t_int; case LE: assert(!"unimplemented"); break; case GE: assert(!"unimplemented"); break; case GT: assert(!"unimplemented"); break; @@ -2691,6 +2854,18 @@ oop typeCheck(oop exp, oop fntype) fatal("incompatible types assigning '%s' to '%s'", toString(rhs), toString(lhs)); return lhs; } + case For: { + oop init = get(exp, For,initialiser); + oop cond = get(exp, For,condition); + oop step = get(exp, For,update); + oop body = get(exp, For,body); + typeCheck(init, fntype); + cond = typeCheck(cond, fntype); + if (t_int != cond) fatal("for condition is not 'int'"); + typeCheck(step, fntype); + typeCheck(body, fntype); + return nil; + } case Primitive: { return get(exp, Primitive,type); } @@ -2866,14 +3041,15 @@ void replPath(char *path) int main(int argc, char **argv) { - true = newSymbol("true"); + false = newInteger(0); + true = newInteger(1); s_etc = newSymbol("..."); - t_etc = newTbase("...", 0); - t_void = newTbase("void", 1); - t_char = newTbase("char", 1); - t_int = newTbase("int", 4); - t_float = newTbase("float", 4); + t_etc = newTbase("...", 0, T_ETC); + t_void = newTbase("void", 1, T_VOID); + t_char = newTbase("char", 1, T_INT); + t_int = newTbase("int", 4, T_INT); + t_float = newTbase("float", 4, T_FLOAT); t_string = newTpointer(t_char); scopes = newArray(); diff --git a/test.txt b/test.txt index 3a94aa7..0de61f1 100755 --- a/test.txt +++ b/test.txt @@ -17,6 +17,7 @@ int main(int argc, char **argv) printf("x is %d %d\n", x, *p); x = 123; printf("x is %d %d\n", x, *p); + for (x = 0; x < 10; ++x) printf("%d\n", x); return 0; }