|
|
@ -1,6 +1,6 @@ |
|
|
|
# main.leg -- C parser + interpreter |
|
|
|
# |
|
|
|
# Last edited: 2025-02-01 15:04:48 by piumarta on xubuntu |
|
|
|
# Last edited: 2025-02-03 10:47:46 by piumarta on xubuntu |
|
|
|
|
|
|
|
%{ |
|
|
|
; |
|
|
@ -60,16 +60,17 @@ typedef union Object Object, *oop; |
|
|
|
|
|
|
|
#define YYSTYPE oop |
|
|
|
|
|
|
|
#define _do_types(_) \ |
|
|
|
_(Undefined) _(Input) _(Integer) _(Float) _(Array) _(Symbol) _(Pair) _(String) _(List) \ |
|
|
|
_(Pointer) _(Struct) \ |
|
|
|
_(Memory) _(Reference) _(Closure) _(Call) _(Block) \ |
|
|
|
_(Addressof) _(Dereference) _(Sizeof) _(Unary) \ |
|
|
|
_(Binary) _(Index) _(Member) _(Assign) _(Cast) \ |
|
|
|
_(While) _(For) _(If) _(Return) _(Continue) _(Break) \ |
|
|
|
_(Tvoid) _(Tchar) _(Tshort) _(Tint) _(Tlong) _(Tfloat) _(Tdouble) \ |
|
|
|
_(Tpointer) _(Tarray) _(Tstruct) _(Tfunction) _(Tetc) \ |
|
|
|
_(Scope) _(TypeName) _(Variable) _(Constant) _(Function) _(Primitive) \ |
|
|
|
#define _do_types(_) \ |
|
|
|
_(Undefined) _(Input) _(Token )_(Integer) _(Float) _(Array) _(Symbol) _(Pair) \ |
|
|
|
_(String) _(List) \ |
|
|
|
_(Pointer) _(Struct) \ |
|
|
|
_(Memory) _(Reference) _(Closure) _(Call) _(Block) \ |
|
|
|
_(Addressof) _(Dereference) _(Sizeof) _(Unary) \ |
|
|
|
_(Binary) _(Index) _(Member) _(Assign) _(Cast) \ |
|
|
|
_(While) _(For) _(If) _(Return) _(Continue) _(Break) \ |
|
|
|
_(Tvoid) _(Tchar) _(Tshort) _(Tint) _(Tlong) _(Tfloat) _(Tdouble) \ |
|
|
|
_(Tpointer) _(Tarray) _(Tstruct) _(Tfunction) _(Tetc) \ |
|
|
|
_(Scope) _(TypeName) _(Variable) _(Constant) _(Function) _(Primitive) \ |
|
|
|
_(VarDecls) _(TypeDecls) |
|
|
|
|
|
|
|
#define _do_unaries(_) \ |
|
|
@ -116,7 +117,8 @@ typedef oop (* prim_t)(int nargs, oop *arguments, oop environment); |
|
|
|
typedef oop (*cvt_t)(oop input); |
|
|
|
|
|
|
|
struct Undefined { type_t _type; }; |
|
|
|
struct Input { type_t _type; char *name; FILE *file; oop next; }; |
|
|
|
struct Input { type_t _type; char *name; int line; FILE *file; oop next; }; |
|
|
|
struct Token { type_t _type; char *text; char *file; int line; }; |
|
|
|
struct Integer { type_t _type; long value; }; |
|
|
|
struct Float { type_t _type; double value; }; |
|
|
|
struct Pointer { type_t _type; oop type, base; int offset; }; |
|
|
@ -138,7 +140,7 @@ struct Unary { type_t _type; unary_t operator; oop rhs; }; |
|
|
|
struct Binary { type_t _type; binary_t operator; oop lhs, rhs; }; |
|
|
|
struct Index { type_t _type; oop lhs, rhs; }; |
|
|
|
struct Member { type_t _type; oop lhs, name; }; |
|
|
|
struct Assign { type_t _type; oop lhs, rhs; }; |
|
|
|
struct Assign { type_t _type; oop token, lhs, rhs; }; |
|
|
|
struct Cast { type_t _type; oop type, rhs; cvt_t converter; }; |
|
|
|
struct While { type_t _type; oop condition, expression; }; |
|
|
|
struct For { type_t _type; oop initialiser, condition, update, body; }; |
|
|
@ -669,7 +671,7 @@ oop newBinary(binary_t operator, oop lhs, oop rhs) |
|
|
|
|
|
|
|
CTOR2(Index, lhs, rhs); |
|
|
|
CTOR2(Member, lhs, name); |
|
|
|
CTOR2(Assign, lhs, rhs); |
|
|
|
CTOR3(Assign, token, lhs, rhs); |
|
|
|
|
|
|
|
oop newCast(oop type, oop rhs) |
|
|
|
{ |
|
|
@ -1063,6 +1065,10 @@ oop toStringOn(oop obj, oop str) |
|
|
|
case Undefined: |
|
|
|
String_appendAll(str, "<NIL>", 5); |
|
|
|
break; |
|
|
|
case Token: { |
|
|
|
String_format(str, "%s:%d: ", get(obj, Token,file), get(obj, Token,line)); |
|
|
|
break; |
|
|
|
} |
|
|
|
case Integer: |
|
|
|
String_format(str, "%d", _integerValue(obj)); |
|
|
|
break; |
|
|
@ -1346,6 +1352,12 @@ char *toString(oop obj) |
|
|
|
return get(str, String,elements); |
|
|
|
} |
|
|
|
|
|
|
|
char *tokloc(oop token) |
|
|
|
{ |
|
|
|
if (Token == getType(token)) return toString(token); |
|
|
|
return ""; |
|
|
|
} |
|
|
|
|
|
|
|
void printiln(oop obj, int indent) |
|
|
|
{ |
|
|
|
printf("%*s", indent*2, ""); |
|
|
@ -1636,19 +1648,23 @@ oop pushInput(char *name, FILE *file) |
|
|
|
{ |
|
|
|
oop obj = new(Input); |
|
|
|
obj->Input.name = STRDUP(name); |
|
|
|
obj->Input.line = 1; |
|
|
|
obj->Input.file = file; |
|
|
|
obj->Input.next = input; |
|
|
|
return input = obj; |
|
|
|
input = obj; |
|
|
|
return input; |
|
|
|
} |
|
|
|
|
|
|
|
void popInput(void) |
|
|
|
{ |
|
|
|
if (!input) return; |
|
|
|
FILE *file = get(input, Input,file); |
|
|
|
oop obj = input; |
|
|
|
input = get(obj, Input,next); |
|
|
|
FREE(get(obj, Input,name)); |
|
|
|
fclose(get(obj, Input,file)); |
|
|
|
FREE(obj); |
|
|
|
if (file) { |
|
|
|
fclose(file); |
|
|
|
set(obj, Input,file, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
FILE *sysOpen(char *path) |
|
|
@ -1669,13 +1685,13 @@ FILE *usrOpen(char *path) |
|
|
|
|
|
|
|
int getChar(char *buf) |
|
|
|
{ |
|
|
|
while (input) { |
|
|
|
if (input && get(input, Input,file)) { |
|
|
|
int c = getc(get(input, Input,file)); |
|
|
|
if (c != EOF) { |
|
|
|
*buf = c; |
|
|
|
if ('\n' == c) get(input, Input,line) += 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
popInput(); |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
@ -1684,31 +1700,68 @@ int getChar(char *buf) |
|
|
|
|
|
|
|
YYSTYPE yysval = 0; |
|
|
|
|
|
|
|
int errorLine = 0; |
|
|
|
|
|
|
|
void expected(oop where, char *what) |
|
|
|
{ |
|
|
|
fatal("%s expected near: %.*s", what, get(where, String,size), get(where, String,elements)); |
|
|
|
fatal("%s:%d: %s expected near: %.*s", |
|
|
|
get(input, Input,name), errorLine, |
|
|
|
what, get(where, String,size), get(where, String,elements)); |
|
|
|
} |
|
|
|
|
|
|
|
oop eval(oop exp); |
|
|
|
oop preval(oop exp); |
|
|
|
|
|
|
|
int lineNo = 1; |
|
|
|
|
|
|
|
oop newToken(char *text) |
|
|
|
{ |
|
|
|
oop obj = new(Token); |
|
|
|
obj->Token.text = text; |
|
|
|
assert(input); |
|
|
|
obj->Token.file = get(input, Input,name); |
|
|
|
obj->Token.line = lineNo; |
|
|
|
return obj; |
|
|
|
} |
|
|
|
|
|
|
|
oop names = 0; |
|
|
|
oop lines = 0; |
|
|
|
|
|
|
|
void startInput(char *name) |
|
|
|
{ |
|
|
|
if (!names) names = newList(); |
|
|
|
if (!lines) lines = newList(); |
|
|
|
List_append(names, newStringWith(name)); |
|
|
|
List_append(lines, newInteger(lineNo)); |
|
|
|
lineNo = 1; |
|
|
|
} |
|
|
|
|
|
|
|
void endInput(void) |
|
|
|
{ |
|
|
|
if (List_size(lines)) { |
|
|
|
lineNo = _integerValue(List_popLast(lines)); |
|
|
|
List_popLast(names); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
%} |
|
|
|
|
|
|
|
start = - ( interp { yysval = 0 } |
|
|
|
| include { yysval = 0 } |
|
|
|
| x:tldecl { yysval = x } |
|
|
|
| !. { yysval = 0 } |
|
|
|
| e:error { expected(e, "declaration") } |
|
|
|
start = - ( interp { yysval = 0 } |
|
|
|
| include { yysval = 0 } |
|
|
|
| x:tldecl { yysval = x } |
|
|
|
| !. @{ popInput() } { yysval = 0; endInput() } |
|
|
|
| e:error { expected(e, "declaration") } |
|
|
|
) |
|
|
|
|
|
|
|
error = < (![\n\r] .)* > { $$ = newStringWith(yytext) } |
|
|
|
error = @{ errorLine = get(input, Input,line) } |
|
|
|
< (![\n\r] .)* > { $$ = newStringWith(yytext) } |
|
|
|
|
|
|
|
interp = HASH PLING (![\n\r] .)* |
|
|
|
interp = "#!" (!eol .)* eol |
|
|
|
|
|
|
|
include = HASH INCLUDE ( |
|
|
|
'<' < [a-zA-Z0-9_.]* > '>' @{ pushInput(yytext, sysOpen(yytext)) } |
|
|
|
| '"' < [a-zA-Z0-9_.]* > '"' @{ pushInput(yytext, usrOpen(yytext)) } |
|
|
|
) |
|
|
|
) { startInput(yytext) } |
|
|
|
|
|
|
|
tldecl = typedec | fundefn | primdef | vardecl |
|
|
|
|
|
|
@ -1742,10 +1795,10 @@ members = LBRACE l:mkList ( v:vardecl { List_append(l, v) } |
|
|
|
| e:error { expected(e, "struct/union member specification") } |
|
|
|
) { $$ = l } |
|
|
|
|
|
|
|
inidecl = d:decltor ( ASSIGN ( e:initor { $$ = newAssign(d, e) } |
|
|
|
| e:error { expected(e, "variable initialiser") } |
|
|
|
) |
|
|
|
| { $$ = d } |
|
|
|
inidecl = d:decltor ( a:ASSIGN ( e:initor { $$ = newAssign(a, d, e) } |
|
|
|
| e:error { expected(e, "variable initialiser") } |
|
|
|
) |
|
|
|
| { $$ = d } |
|
|
|
) |
|
|
|
|
|
|
|
decltor = STAR d:decltor { $$ = newTpointer(d) } |
|
|
@ -1813,7 +1866,7 @@ expropt = expr | { $$ = nil } |
|
|
|
|
|
|
|
expr = assign |
|
|
|
|
|
|
|
assign = l:unary ASSIGN x:expr { $$ = newAssign(l, x) } |
|
|
|
assign = l:unary a:ASSIGN x:expr { $$ = newAssign(a, l, x) } |
|
|
|
| logor |
|
|
|
|
|
|
|
logor = l:logand ( BARBAR r:logand { l = newBinary(LOR, l, r) } |
|
|
@ -1943,9 +1996,11 @@ alpha = [a-zA-Z_] |
|
|
|
alnum = [a-zA-Z_0-9] |
|
|
|
|
|
|
|
- = blank* |
|
|
|
blank = [ \t\n\r] | comment |
|
|
|
comment = "//" < (![\n\r] .)* > |
|
|
|
| "/*" (!"*/" .)* "*/" |
|
|
|
blank = space | eol | comment |
|
|
|
space = [ \t] |
|
|
|
eol = ( '\n' '\r'? | '\r' '\n'? ) { lineNo += 1 } |
|
|
|
comment = "//" (!eol .)* eol |
|
|
|
| "/*" (!"*/" (eol | .))* "*/" |
|
|
|
|
|
|
|
INCLUDE = "include" ![_a-zA-Z0-9] - |
|
|
|
EXTERN = "extern" ![_a-zA-Z0-9] - |
|
|
@ -1975,7 +2030,7 @@ DOT = "." !"." - |
|
|
|
ARROW = "->" - |
|
|
|
ETC = "..." - |
|
|
|
HASH = "#" - |
|
|
|
ASSIGN = "=" !"=" - |
|
|
|
ASSIGN = < "=" !"=" > { $$ = newToken(yytext) } - |
|
|
|
PLUS = "+" !"+" - |
|
|
|
PPLUS = "++" - |
|
|
|
MINUS = "-" !"-" - |
|
|
@ -2240,6 +2295,7 @@ int toBoolean(oop arg) |
|
|
|
switch (getType(arg)) { |
|
|
|
case Integer: return !!_integerValue(arg); |
|
|
|
case Float: return !! integerValue(arg); |
|
|
|
case String: return 1; |
|
|
|
case Reference: return 1; |
|
|
|
case Pointer: { |
|
|
|
oop base = get(arg, Pointer,base); |
|
|
@ -2472,7 +2528,7 @@ oop prim_sqrtf(int argc, oop *argv, oop env) // array |
|
|
|
{ |
|
|
|
if (argc != 1) fatal("sqrtf: wrong number of arguments"); |
|
|
|
oop arg = argv[0]; |
|
|
|
if (!is(Float, arg)) fatal("sqrtf: argument is not an integer"); |
|
|
|
if (!is(Float, arg)) fatal("sqrtf: argument is not a float"); |
|
|
|
return newFloat(sqrtf(_floatValue(arg))); |
|
|
|
} |
|
|
|
|
|
|
@ -2843,10 +2899,12 @@ oop typeCheck(oop exp, oop fntype) |
|
|
|
oop decls = get(exp, VarDecls,variables); |
|
|
|
oop vars = newList(); |
|
|
|
List_do(decls, decl) { |
|
|
|
oop init = nil; |
|
|
|
oop init = nil; |
|
|
|
oop assign = nil; |
|
|
|
if (is(Assign, decl)) { |
|
|
|
init = get(decl, Assign,rhs); |
|
|
|
decl = get(decl, Assign,lhs); |
|
|
|
assign = get(decl, Assign,token); |
|
|
|
init = get(decl, Assign,rhs); |
|
|
|
decl = get(decl, Assign,lhs); |
|
|
|
} |
|
|
|
oop varname = makeName(decl); |
|
|
|
oop vartype = makeType(base, decl); |
|
|
@ -2943,8 +3001,10 @@ oop typeCheck(oop exp, oop fntype) |
|
|
|
break; |
|
|
|
cvt_t cvt = converter(getType(initype), getType(vartype)); |
|
|
|
if (!cvt) { |
|
|
|
fatal("initialising '%s': cannot convert '%s' to '%s'", |
|
|
|
toString(varname), toString(initype), toString(vartype)); |
|
|
|
fatal("%sinitialising '%s': cannot convert '%s' to '%s'", |
|
|
|
tokloc(assign), |
|
|
|
toString(varname), toString(initype), toString(vartype) |
|
|
|
); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
@ -3561,8 +3621,6 @@ oop eval(oop exp) |
|
|
|
} |
|
|
|
default: break; |
|
|
|
} |
|
|
|
println(lhs); |
|
|
|
fatal("cannot take address"); |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
@ -4486,7 +4544,7 @@ void compileOn(oop exp, oop program, oop cs, oop bs) |
|
|
|
return; |
|
|
|
} |
|
|
|
case Break: { |
|
|
|
if (nil == bs) fatal("continue outside loop"); |
|
|
|
if (nil == bs) fatal("break outside loop"); |
|
|
|
EMITio(iPUSH, nil); |
|
|
|
LABEL(L1); |
|
|
|
EMITio(iJMP, nil); |
|
|
@ -4585,6 +4643,8 @@ void replPath(char *path) |
|
|
|
|
|
|
|
int main(int argc, char **argv) |
|
|
|
{ |
|
|
|
setbuf(stdout, 0); |
|
|
|
|
|
|
|
false = newInteger(0); |
|
|
|
true = newInteger(1); |
|
|
|
s_etc = newSymbol("..."); |
|
|
|