Browse Source

handle for loops

master
Ian Piumarta 5 months ago
parent
commit
0d88339f76
2 changed files with 248 additions and 71 deletions
  1. +247
    -71
      main.leg
  2. +1
    -0
      test.txt

+ 247
- 71
main.leg View File

@ -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();

+ 1
- 0
test.txt View File

@ -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;
}

Loading…
Cancel
Save