|
@ -1,6 +1,6 @@ |
|
|
# main.leg -- C parser + interpreter |
|
|
# main.leg -- C parser + interpreter |
|
|
# |
|
|
# |
|
|
# Last edited: 2025-01-26 11:37:20 by piumarta on zora |
|
|
|
|
|
|
|
|
# Last edited: 2025-01-26 12:12:15 by piumarta on zora |
|
|
|
|
|
|
|
|
%{ |
|
|
%{ |
|
|
; |
|
|
; |
|
@ -61,7 +61,8 @@ typedef union Object Object, *oop; |
|
|
_(Reference) _(Closure) _(Call) _(Block) \ |
|
|
_(Reference) _(Closure) _(Call) _(Block) \ |
|
|
_(Address) _(Dereference) _(Unary) _(Binary) _(Assign) _(Cast) \ |
|
|
_(Address) _(Dereference) _(Unary) _(Binary) _(Assign) _(Cast) \ |
|
|
_(While) _(For) _(If) _(Return) _(Continue) _(Break) \ |
|
|
_(While) _(For) _(If) _(Return) _(Continue) _(Break) \ |
|
|
_(Tbase) _(Tpointer) _(Tarray) _(Tstruct) _(Tfunction) \ |
|
|
|
|
|
|
|
|
_(Tvoid) _(Tchar) _(Tshort) _(Tint) _(Tlong) _(Tfloat) _(Tdouble) \ |
|
|
|
|
|
_(Tpointer) _(Tarray) _(Tstruct) _(Tfunction) _(Tetc) \ |
|
|
_(Scope) _(TypeName) _(Variable) _(Constant) _(Function) _(Primitive) \ |
|
|
_(Scope) _(TypeName) _(Variable) _(Constant) _(Function) _(Primitive) \ |
|
|
_(VarDecls) |
|
|
_(VarDecls) |
|
|
|
|
|
|
|
@ -127,11 +128,18 @@ struct Break { type_t _type; }; |
|
|
|
|
|
|
|
|
typedef enum { T_INT = 0, T_FLOAT, T_VOID, T_ETC } base_t; |
|
|
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 Tvoid { type_t _type; }; |
|
|
|
|
|
struct Tchar { type_t _type; }; |
|
|
|
|
|
struct Tshort { type_t _type; }; |
|
|
|
|
|
struct Tint { type_t _type; }; |
|
|
|
|
|
struct Tlong { type_t _type; }; |
|
|
|
|
|
struct Tfloat { type_t _type; }; |
|
|
|
|
|
struct Tdouble { type_t _type; }; |
|
|
struct Tpointer { type_t _type; oop target; }; |
|
|
struct Tpointer { type_t _type; oop target; }; |
|
|
struct Tarray { type_t _type; oop target; oop size; }; |
|
|
struct Tarray { type_t _type; oop target; oop size; }; |
|
|
struct Tstruct { type_t _type; oop tag, members; }; |
|
|
struct Tstruct { type_t _type; oop tag, members; }; |
|
|
struct Tfunction { type_t _type; oop result, parameters; }; |
|
|
struct Tfunction { type_t _type; oop result, parameters; }; |
|
|
|
|
|
struct Tetc { type_t _type; }; |
|
|
|
|
|
|
|
|
struct Scope { type_t _type; oop names, types, values; }; |
|
|
struct Scope { type_t _type; oop names, types, values; }; |
|
|
struct TypeName { type_t _type; oop name, type; }; |
|
|
struct TypeName { type_t _type; oop name, type; }; |
|
@ -597,21 +605,38 @@ CTOR1(Return, value); |
|
|
CTOR0(Continue); |
|
|
CTOR0(Continue); |
|
|
CTOR0(Break); |
|
|
CTOR0(Break); |
|
|
|
|
|
|
|
|
oop newTbase(char *name, int size, base_t type) |
|
|
|
|
|
|
|
|
CTOR0(Tvoid); |
|
|
|
|
|
CTOR0(Tchar); |
|
|
|
|
|
CTOR0(Tshort); |
|
|
|
|
|
CTOR0(Tint); |
|
|
|
|
|
CTOR0(Tlong); |
|
|
|
|
|
CTOR0(Tfloat); |
|
|
|
|
|
CTOR0(Tdouble); |
|
|
|
|
|
|
|
|
|
|
|
int isTypeName(oop obj) |
|
|
{ |
|
|
{ |
|
|
oop obj = new(Tbase); |
|
|
|
|
|
obj->Tbase.name = name; |
|
|
|
|
|
obj->Tbase.size = size; |
|
|
|
|
|
obj->Tbase.type = type; |
|
|
|
|
|
return obj; |
|
|
|
|
|
|
|
|
switch (getType(obj)) { |
|
|
|
|
|
case Tvoid: |
|
|
|
|
|
case Tchar: |
|
|
|
|
|
case Tshort: |
|
|
|
|
|
case Tint: |
|
|
|
|
|
case Tlong: |
|
|
|
|
|
case Tfloat: |
|
|
|
|
|
case Tdouble: |
|
|
|
|
|
case TypeName: return 1; |
|
|
|
|
|
default: break; |
|
|
|
|
|
} |
|
|
|
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
oop s_etc = 0; |
|
|
oop s_etc = 0; |
|
|
oop t_etc = 0; |
|
|
oop t_etc = 0; |
|
|
oop t_void = 0; |
|
|
oop t_void = 0; |
|
|
oop t_char = 0; |
|
|
oop t_char = 0; |
|
|
|
|
|
oop t_short = 0; |
|
|
oop t_int = 0; |
|
|
oop t_int = 0; |
|
|
oop t_float = 0; |
|
|
oop t_float = 0; |
|
|
|
|
|
oop t_double = 0; |
|
|
oop t_string = 0; |
|
|
oop t_string = 0; |
|
|
|
|
|
|
|
|
oop newTpointer(oop target) |
|
|
oop newTpointer(oop target) |
|
@ -674,6 +699,8 @@ oop newTfunction(oop result, oop parameters) |
|
|
return obj; |
|
|
return obj; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CTOR0(Tetc); |
|
|
|
|
|
|
|
|
oop newScope(void) |
|
|
oop newScope(void) |
|
|
{ |
|
|
{ |
|
|
oop obj = new(Scope); |
|
|
oop obj = new(Scope); |
|
@ -843,7 +870,13 @@ oop newVarDecls(oop type, oop decl) |
|
|
oop baseType(oop type) |
|
|
oop baseType(oop type) |
|
|
{ |
|
|
{ |
|
|
switch (getType(type)) { |
|
|
switch (getType(type)) { |
|
|
case Tbase: return type; |
|
|
|
|
|
|
|
|
case Tvoid: |
|
|
|
|
|
case Tchar: |
|
|
|
|
|
case Tshort: |
|
|
|
|
|
case Tint: |
|
|
|
|
|
case Tlong: |
|
|
|
|
|
case Tfloat: |
|
|
|
|
|
case Tdouble: return type; |
|
|
case Tpointer: return baseType(get(type, Tpointer,target)); |
|
|
case Tpointer: return baseType(get(type, Tpointer,target)); |
|
|
case Tarray: return baseType(get(type, Tarray,target)); |
|
|
case Tarray: return baseType(get(type, Tarray,target)); |
|
|
case Tfunction: return baseType(get(type, Tfunction,result)); |
|
|
case Tfunction: return baseType(get(type, Tfunction,result)); |
|
@ -857,9 +890,13 @@ oop toStringOn(oop obj, oop str); |
|
|
void declareStringOn(oop type, oop name, oop str) |
|
|
void declareStringOn(oop type, oop name, oop str) |
|
|
{ |
|
|
{ |
|
|
switch (getType(type)) { |
|
|
switch (getType(type)) { |
|
|
case Tbase: |
|
|
|
|
|
toStringOn(name, str); |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
case Tvoid: String_format(str, "void"); break; |
|
|
|
|
|
case Tchar: String_format(str, "char"); break; |
|
|
|
|
|
case Tshort: String_format(str, "short"); break; |
|
|
|
|
|
case Tint: String_format(str, "int"); break; |
|
|
|
|
|
case Tlong: String_format(str, "long"); break; |
|
|
|
|
|
case Tfloat: String_format(str, "float"); break; |
|
|
|
|
|
case Tdouble: String_format(str, "double"); break; |
|
|
case Tpointer: |
|
|
case Tpointer: |
|
|
String_append(str, '*'); |
|
|
String_append(str, '*'); |
|
|
declareStringOn(get(type, Tpointer,target), name, str); |
|
|
declareStringOn(get(type, Tpointer,target), name, str); |
|
@ -1019,13 +1056,17 @@ oop toStringOn(oop obj, oop str) |
|
|
toStringOn(get(obj, For,body), str); |
|
|
toStringOn(get(obj, For,body), str); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case Tbase: |
|
|
|
|
|
String_format(str, "%s", get(obj, Tbase,name)); |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
case Tvoid: String_format(str, "void"); break; |
|
|
|
|
|
case Tchar: String_format(str, "char"); break; |
|
|
|
|
|
case Tshort: String_format(str, "short"); break; |
|
|
|
|
|
case Tint: String_format(str, "int"); break; |
|
|
|
|
|
case Tlong: String_format(str, "long"); break; |
|
|
|
|
|
case Tfloat: String_format(str, "float"); break; |
|
|
|
|
|
case Tdouble: String_format(str, "double"); break; |
|
|
case Tpointer: { |
|
|
case Tpointer: { |
|
|
oop target = get(obj, Tpointer,target); |
|
|
oop target = get(obj, Tpointer,target); |
|
|
toStringOn(target, str); |
|
|
toStringOn(target, str); |
|
|
if (is(Tbase, target)) String_append(str, ' '); |
|
|
|
|
|
|
|
|
if (isTypeName(target)) String_append(str, ' '); |
|
|
String_append(str, '*'); |
|
|
String_append(str, '*'); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -1256,10 +1297,14 @@ void printiln(oop obj, int indent) |
|
|
printf("BREAK\n"); |
|
|
printf("BREAK\n"); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case Tbase: { |
|
|
|
|
|
printf("<%s:%d>\n", get(obj, Tbase,name), get(obj, Tbase,size)); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
case Tvoid: printf("<void:1>"); break; |
|
|
|
|
|
case Tchar: printf("<char:1>"); break; |
|
|
|
|
|
case Tshort: printf("<short:2>"); break; |
|
|
|
|
|
case Tint: printf("<int:4>"); break; |
|
|
|
|
|
case Tlong: printf("<long:8>"); break; |
|
|
|
|
|
case Tfloat: printf("<float:4>"); break; |
|
|
|
|
|
case Tdouble: printf("<double:8>"); break; |
|
|
|
|
|
case Tetc: printf("<...>"); break; |
|
|
case Tpointer: { |
|
|
case Tpointer: { |
|
|
printf("Tpointer\n"); |
|
|
printf("Tpointer\n"); |
|
|
printiln(get(obj, Tpointer,target), indent+1); |
|
|
printiln(get(obj, Tpointer,target), indent+1); |
|
@ -2071,31 +2116,13 @@ oop eval(oop exp, oop env) |
|
|
case Integer: |
|
|
case Integer: |
|
|
case Float: { |
|
|
case Float: { |
|
|
switch (getType(lhs)) { |
|
|
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; |
|
|
|
|
|
|
|
|
case Tchar: return newInteger( (char)integerValue(rhs)); |
|
|
|
|
|
case Tshort: return newInteger( (short)integerValue(rhs)); |
|
|
|
|
|
case Tint: return newInteger( ( int)integerValue(rhs)); |
|
|
|
|
|
case Tlong: return newInteger( (long)integerValue(rhs)); |
|
|
|
|
|
case Tfloat: return newInteger( (float)floatValue(rhs)); |
|
|
|
|
|
case Tdouble: return newInteger((double)floatValue(rhs)); |
|
|
|
|
|
default: break; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -2153,11 +2180,18 @@ oop eval(oop exp, oop env) |
|
|
nlrReturn(NLR_BREAK, nil); |
|
|
nlrReturn(NLR_BREAK, nil); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case Tbase: assert(!"unimplemented"); break; |
|
|
|
|
|
|
|
|
case Tvoid: assert(!"unimplemented"); break; |
|
|
|
|
|
case Tchar: assert(!"unimplemented"); break; |
|
|
|
|
|
case Tshort: assert(!"unimplemented"); break; |
|
|
|
|
|
case Tint: assert(!"unimplemented"); break; |
|
|
|
|
|
case Tlong: assert(!"unimplemented"); break; |
|
|
|
|
|
case Tfloat: assert(!"unimplemented"); break; |
|
|
|
|
|
case Tdouble: assert(!"unimplemented"); break; |
|
|
case Tpointer: assert(!"unimplemented"); break; |
|
|
case Tpointer: assert(!"unimplemented"); break; |
|
|
case Tarray: assert(!"unimplemented"); break; |
|
|
case Tarray: assert(!"unimplemented"); break; |
|
|
case Tstruct: assert(!"unimplemented"); break; |
|
|
case Tstruct: assert(!"unimplemented"); break; |
|
|
case Tfunction: assert(!"unimplemented"); break; |
|
|
case Tfunction: assert(!"unimplemented"); break; |
|
|
|
|
|
case Tetc: assert(!"unimplemented"); break; |
|
|
case VarDecls: { |
|
|
case VarDecls: { |
|
|
oop vars = get(exp, VarDecls,variables); |
|
|
oop vars = get(exp, VarDecls,variables); |
|
|
Array_do(vars, var) { |
|
|
Array_do(vars, var) { |
|
@ -2212,11 +2246,18 @@ oop preval(oop exp) |
|
|
case Return: break; |
|
|
case Return: break; |
|
|
case Continue: break; |
|
|
case Continue: break; |
|
|
case Break: break; |
|
|
case Break: break; |
|
|
case Tbase: break; |
|
|
|
|
|
|
|
|
case Tvoid: break; |
|
|
|
|
|
case Tchar: break; |
|
|
|
|
|
case Tshort: break; |
|
|
|
|
|
case Tint: break; |
|
|
|
|
|
case Tlong: break; |
|
|
|
|
|
case Tfloat: break; |
|
|
|
|
|
case Tdouble: break; |
|
|
case Tpointer: break; |
|
|
case Tpointer: break; |
|
|
case Tarray: break; |
|
|
case Tarray: break; |
|
|
case Tstruct: break; |
|
|
case Tstruct: break; |
|
|
case Tfunction: break; |
|
|
case Tfunction: break; |
|
|
|
|
|
case Tetc: break; |
|
|
case VarDecls: { |
|
|
case VarDecls: { |
|
|
oop vars = get(exp, VarDecls,variables); |
|
|
oop vars = get(exp, VarDecls,variables); |
|
|
Array_do(vars, var) { |
|
|
Array_do(vars, var) { |
|
@ -2744,11 +2785,18 @@ void compileOn(oop exp, oop program, oop cs, oop bs) |
|
|
Array_append(bs, newInteger(L1)); |
|
|
Array_append(bs, newInteger(L1)); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
case Tbase: assert(!"unimplemented"); return; |
|
|
|
|
|
|
|
|
case Tvoid: assert(!"unimplemented"); return; |
|
|
|
|
|
case Tchar: assert(!"unimplemented"); return; |
|
|
|
|
|
case Tshort: assert(!"unimplemented"); return; |
|
|
|
|
|
case Tint: assert(!"unimplemented"); return; |
|
|
|
|
|
case Tlong: assert(!"unimplemented"); return; |
|
|
|
|
|
case Tfloat: assert(!"unimplemented"); return; |
|
|
|
|
|
case Tdouble: assert(!"unimplemented"); return; |
|
|
case Tpointer: assert(!"unimplemented"); return; |
|
|
case Tpointer: assert(!"unimplemented"); return; |
|
|
case Tarray: assert(!"unimplemented"); return; |
|
|
case Tarray: assert(!"unimplemented"); return; |
|
|
case Tstruct: assert(!"unimplemented"); return; |
|
|
case Tstruct: assert(!"unimplemented"); return; |
|
|
case Tfunction: assert(!"unimplemented"); return; |
|
|
case Tfunction: assert(!"unimplemented"); return; |
|
|
|
|
|
case Tetc: assert(!"unimplemented"); return; |
|
|
case VarDecls: assert(!"unimplemented"); return; |
|
|
case VarDecls: assert(!"unimplemented"); return; |
|
|
case Scope: assert(!"this cannot happen"); return; |
|
|
case Scope: assert(!"this cannot happen"); return; |
|
|
case TypeName: assert(!"unimplemented"); return; |
|
|
case TypeName: assert(!"unimplemented"); return; |
|
@ -2785,7 +2833,13 @@ oop compile(oop exp) // 6*7 |
|
|
int typeSize(oop type) |
|
|
int typeSize(oop type) |
|
|
{ |
|
|
{ |
|
|
switch (getType(type)) { |
|
|
switch (getType(type)) { |
|
|
case Tbase: return get(type, Tbase,size); |
|
|
|
|
|
|
|
|
case Tvoid: return 1; |
|
|
|
|
|
case Tchar: return 1; |
|
|
|
|
|
case Tshort: return 2; |
|
|
|
|
|
case Tint: return 4; |
|
|
|
|
|
case Tlong: return 8; |
|
|
|
|
|
case Tfloat: return 4; |
|
|
|
|
|
case Tdouble: return 8; |
|
|
case Tpointer: return 8; // fixme: make this a parameter |
|
|
case Tpointer: return 8; // fixme: make this a parameter |
|
|
case Tstruct: assert(!"unimplemented"); |
|
|
case Tstruct: assert(!"unimplemented"); |
|
|
case Tarray: assert(!"unimplemented"); |
|
|
case Tarray: assert(!"unimplemented"); |
|
@ -2827,39 +2881,32 @@ oop typeCheck(oop exp, oop fntype) |
|
|
case Cast: { |
|
|
case Cast: { |
|
|
oop lhs = get(exp, Cast,type); |
|
|
oop lhs = get(exp, Cast,type); |
|
|
oop rhs = typeCheck(get(exp, Cast,rhs), fntype); |
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
type_t lht = getType(lhs), rht = getType(rhs); |
|
|
|
|
|
switch (lht) { |
|
|
|
|
|
case Tlong: if (Tpointer == rht) return lhs; |
|
|
|
|
|
case Tchar: |
|
|
|
|
|
case Tshort: |
|
|
|
|
|
case Tint: |
|
|
|
|
|
case Tfloat: |
|
|
|
|
|
case Tdouble: { |
|
|
|
|
|
switch (rht) { |
|
|
|
|
|
case Tchar: |
|
|
|
|
|
case Tshort: |
|
|
|
|
|
case Tint: |
|
|
|
|
|
case Tlong: |
|
|
|
|
|
case Tfloat: |
|
|
|
|
|
case Tdouble: return lhs; |
|
|
|
|
|
default: break; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case Tpointer: { |
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
switch (rht) { |
|
|
|
|
|
case Tpointer: |
|
|
|
|
|
case Tlong: return lhs; |
|
|
default: break; |
|
|
default: break; |
|
|
} |
|
|
} |
|
|
|
|
|
break; |
|
|
} |
|
|
} |
|
|
default: break; |
|
|
default: break; |
|
|
} |
|
|
} |
|
@ -3161,12 +3208,14 @@ int main(int argc, char **argv) |
|
|
_do_primitives(_); |
|
|
_do_primitives(_); |
|
|
# undef _ |
|
|
# undef _ |
|
|
|
|
|
|
|
|
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_void = newTvoid(); |
|
|
|
|
|
t_char = newTchar(); |
|
|
|
|
|
t_short = newTshort(); |
|
|
|
|
|
t_int = newTint(); |
|
|
|
|
|
t_float = newTfloat(); |
|
|
|
|
|
t_double = newTdouble(); |
|
|
t_string = newTpointer(t_char); |
|
|
t_string = newTpointer(t_char); |
|
|
|
|
|
t_etc = newTetc(); |
|
|
|
|
|
|
|
|
scopes = newArray(); |
|
|
scopes = newArray(); |
|
|
|
|
|
|
|
|