Add array accessing
This commit is contained in:
parent
2e86c2b9e5
commit
b9a553b107
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
||||||
FILES = *.c */*.c
|
FILES = *.c */*.c
|
||||||
LIBRARIES = -lpthread
|
LIBRARIES = -lpthread
|
||||||
INCLUDES = -I. -I./parser/ -I./compiler/ -I./vm/ -I./tokenizer/ -I./misc/
|
INCLUDES = -I. -I./parser/ -I./compiler/ -I./vm/ -I./tokenizer/ -I./misc/
|
||||||
CFLAGS = -std=c99 -g
|
CFLAGS = -std=c99 -g -Wall
|
||||||
OUTFILE = jack-compiler
|
OUTFILE = jack-compiler
|
||||||
|
|
||||||
main: ${FILES}
|
main: ${FILES}
|
||||||
|
|
|
@ -26,11 +26,11 @@ SUBROUTDEC* getsubroutdec(SCOPE* s, const char* name);
|
||||||
// Scope adding
|
// Scope adding
|
||||||
VAR* mkvar(char* type, char* name, bool primitive, DEBUGINFO* debug, MEMSEGMENT seg, int i);
|
VAR* mkvar(char* type, char* name, bool primitive, DEBUGINFO* debug, MEMSEGMENT seg, int i);
|
||||||
void addvar(SCOPE* s, VAR** dest, VAR* v);
|
void addvar(SCOPE* s, VAR** dest, VAR* v);
|
||||||
void addlocalvar(SCOPE* s, VARDEC* v, int i);
|
void addlocalvar(SCOPE* s, VARDEC* v, int* i);
|
||||||
void addstaticvar(COMPILER* c, SCOPE* s, CLASSVARDEC* v);
|
void addstaticvar(COMPILER* c, SCOPE* s, CLASSVARDEC* v);
|
||||||
void addfield(SCOPE* s, CLASSVARDEC* v, int i);
|
void addfield(SCOPE* s, CLASSVARDEC* v, int* i);
|
||||||
void addclassvardec(COMPILER* c, SCOPE* s, CLASSVARDEC* v, int* i);
|
void addclassvardec(COMPILER* c, SCOPE* s, CLASSVARDEC* v, int* i);
|
||||||
void addparameter(SCOPE* s, PARAMETER* p, int i);
|
void addparameter(SCOPE* s, PARAMETER* p, int* i);
|
||||||
|
|
||||||
// Error messages
|
// Error messages
|
||||||
void doubledeclaration(const char* name, DEBUGINFO* d1, DEBUGINFO* d2) {
|
void doubledeclaration(const char* name, DEBUGINFO* d1, DEBUGINFO* d2) {
|
||||||
|
@ -223,32 +223,33 @@ void addvar(SCOPE* s, VAR** dest, VAR* v) {
|
||||||
*dest = v;
|
*dest = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addlocalvar(SCOPE* s, VARDEC* v, int i) {
|
void addlocalvar(SCOPE* s, VARDEC* v, int* i) {
|
||||||
STRINGLIST* currname = v->names;
|
STRINGLIST* currname = v->names;
|
||||||
while(currname != NULL) {
|
while(currname != NULL) {
|
||||||
addvar(s, &(s->localvars), mkvar(v->type, currname->content, v->primitive, v->debug, local, i));
|
addvar(s, &(s->localvars), mkvar(v->type, currname->content, v->primitive, v->debug, local, *i));
|
||||||
currname = currname->next;
|
currname = currname->next;
|
||||||
|
(*i)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addstaticvar(COMPILER* c, SCOPE* s, CLASSVARDEC* v) {
|
void addstaticvar(COMPILER* c, SCOPE* s, CLASSVARDEC* v) {
|
||||||
pthread_mutex_lock(&(c->staticmutex));
|
|
||||||
static int count = 0;
|
|
||||||
int i = count;
|
|
||||||
count++;
|
|
||||||
pthread_mutex_unlock(&(c->staticmutex));
|
|
||||||
STRINGLIST* currname = v->base->names;
|
STRINGLIST* currname = v->base->names;
|
||||||
|
pthread_mutex_lock(&(c->staticmutex));
|
||||||
|
static int i = 0;
|
||||||
while(currname != NULL) {
|
while(currname != NULL) {
|
||||||
addvar(s, &(s->staticvars), mkvar(v->base->type, currname->content, v->base->primitive, v->base->debug, staticseg, i));
|
addvar(s, &(s->staticvars), mkvar(v->base->type, currname->content, v->base->primitive, v->base->debug, staticseg, i));
|
||||||
currname = currname->next;
|
currname = currname->next;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&(c->staticmutex));
|
||||||
}
|
}
|
||||||
|
|
||||||
void addfield(SCOPE* s, CLASSVARDEC* v, int i) {
|
void addfield(SCOPE* s, CLASSVARDEC* v, int* i) {
|
||||||
STRINGLIST* currname = v->base->names;
|
STRINGLIST* currname = v->base->names;
|
||||||
while(currname != NULL) {
|
while(currname != NULL) {
|
||||||
addvar(s, &(s->fields), mkvar(v->base->type, currname->content, v->base->primitive, v->base->debug, fieldseg, i));
|
addvar(s, &(s->fields), mkvar(v->base->type, currname->content, v->base->primitive, v->base->debug, fieldseg, *i));
|
||||||
currname = currname->next;
|
currname = currname->next;
|
||||||
|
(*i)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,13 +257,13 @@ void addclassvardec(COMPILER* c, SCOPE* s, CLASSVARDEC* v, int* i) {
|
||||||
if(v->type == stat)
|
if(v->type == stat)
|
||||||
addstaticvar(c, s, v);
|
addstaticvar(c, s, v);
|
||||||
else {
|
else {
|
||||||
addfield(s, v, *i);
|
addfield(s, v, i);
|
||||||
*i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addparameter(SCOPE* s, PARAMETER* p, int i) {
|
void addparameter(SCOPE* s, PARAMETER* p, int* i) {
|
||||||
addvar(s, &(s->parameters), mkvar(p->type, p->name, p->primitive, p->debug, arg, i));
|
addvar(s, &(s->parameters), mkvar(p->type, p->name, p->primitive, p->debug, arg, *i));
|
||||||
|
(*i)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group adding
|
// Group adding
|
||||||
|
@ -277,8 +278,7 @@ void addclassvardecs(COMPILER* c, SCOPE* s, CLASSVARDEC* classvardecs) {
|
||||||
void addlocalvars(SCOPE* s, VARDEC* localvars) {
|
void addlocalvars(SCOPE* s, VARDEC* localvars) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(localvars != NULL) {
|
while(localvars != NULL) {
|
||||||
addlocalvar(s, localvars, i);
|
addlocalvar(s, localvars, &i);
|
||||||
i++;
|
|
||||||
localvars = localvars->next;
|
localvars = localvars->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,8 +286,7 @@ void addlocalvars(SCOPE* s, VARDEC* localvars) {
|
||||||
void addparameters(SCOPE* s, PARAMETER* params) {
|
void addparameters(SCOPE* s, PARAMETER* params) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(params != NULL) {
|
while(params != NULL) {
|
||||||
addparameter(s, params, i);
|
addparameter(s, params, &i);
|
||||||
i++;
|
|
||||||
params = params->next;
|
params = params->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,15 +85,13 @@ LINE* mathopln(char op) {
|
||||||
char* tokens[] = { "call", "Math.divide", "2" };
|
char* tokens[] = { "call", "Math.divide", "2" };
|
||||||
return mksimpleln(tokens, strcount(tokens));
|
return mksimpleln(tokens, strcount(tokens));
|
||||||
}
|
}
|
||||||
if(op == '*') {
|
|
||||||
char* tokens[] = { "call", "Math.multiply", "2" };
|
char* tokens[] = { "call", "Math.multiply", "2" };
|
||||||
return mksimpleln(tokens, strcount(tokens));
|
return mksimpleln(tokens, strcount(tokens));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* pushconstant(int n) {
|
LINE* pushconstant(int n) {
|
||||||
char* tokens[] = { "push", "constant", itoa(n) };
|
char* tokens[] = { "push", "constant", itoa(n) };
|
||||||
return mklnblk(mksimpleln(tokens, strcount(tokens)));
|
return mksimpleln(tokens, strcount(tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* pushunaryopterm(SCOPE* s, TERM* t) {
|
LINEBLOCK* pushunaryopterm(SCOPE* s, TERM* t) {
|
||||||
|
@ -107,47 +105,77 @@ LINEBLOCK* pushunaryopterm(SCOPE* s, TERM* t) {
|
||||||
return blk;
|
return blk;
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* opvarraw(SCOPE* s, char* op, VAR* v) {
|
LINE* opvarraw(SCOPE* s, char* op, VAR* v) {
|
||||||
char* tokens[] = { op, v->memsegment, itoa(v->index) };
|
char* tokens[] = { op, v->memsegment, itoa(v->index) };
|
||||||
return mklnblk(mksimpleln(tokens, strcount(tokens)));
|
return mksimpleln(tokens, strcount(tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* opvar(SCOPE* s, char* op, const char* name) {
|
LINE* opvar(SCOPE* s, char* op, const char* name) {
|
||||||
VAR* v = getvar(s, name);
|
VAR* v = getvar(s, name);
|
||||||
return opvarraw(s, op, v);
|
return opvarraw(s, op, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* pushvarraw(SCOPE*s, VAR* v) {
|
LINE* pushvarraw(SCOPE*s, VAR* v) {
|
||||||
return opvarraw(s, "push", v);
|
return opvarraw(s, "push", v);
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* pushvar(SCOPE* s, const char* name) {
|
LINE* pushvar(SCOPE* s, const char* name) {
|
||||||
return opvar(s, "push", name);
|
return opvar(s, "push", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* popvar(SCOPE* s, const char* name) {
|
LINE* popvar(SCOPE* s, const char* name) {
|
||||||
return opvar(s, "pop", name);
|
return opvar(s, "pop", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* pushfalse() {
|
LINE* pushfalse() {
|
||||||
return pushconstant(0);
|
return pushconstant(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* pushtrue() {
|
LINEBLOCK* pushtrue() {
|
||||||
LINEBLOCK* blk = pushfalse();
|
LINEBLOCK* blk = mklnblk(pushfalse());
|
||||||
appendln(blk, onetoken("not"));
|
appendln(blk, onetoken("not"));
|
||||||
return blk;
|
return blk;
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* pushthis() {
|
LINE* pushthisadd() {
|
||||||
char* pushthis[] = { "push", "pointer", "0" };
|
char* pushthisadd[] = { "push", "pointer", "0" };
|
||||||
return mklnblk(mksimpleln(pushthis, strcount(pushthis)));
|
return mksimpleln(pushthisadd, strcount(pushthisadd));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* popthatadd() {
|
||||||
|
char* popthatadd[] = { "pop", "pointer", "1" };
|
||||||
|
return mksimpleln(popthatadd, strcount(popthatadd));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushthatadd() {
|
||||||
|
char* pushthatadd[] = { "push", "pointer", "1" };
|
||||||
|
return mksimpleln(pushthatadd, strcount(pushthatadd));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* popthat() {
|
||||||
|
char* popthat[] = { "pop", "that", "0" };
|
||||||
|
return mksimpleln(popthat, strcount(popthat));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushthat() {
|
||||||
|
char* pushthat[] = { "push", "that", "0" };
|
||||||
|
return mksimpleln(pushthat, strcount(pushthat));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushtemp() {
|
||||||
|
char* pushtemp[] = { "push", "temp", "0" };
|
||||||
|
return mksimpleln(pushtemp, strcount(pushtemp));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* poptemp() {
|
||||||
|
char* poptemp[] = { "pop", "temp", "0" };
|
||||||
|
return mksimpleln(poptemp, strcount(poptemp));
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* compilekeywordconst(SCOPE* s, TERM* t) {
|
LINEBLOCK* compilekeywordconst(SCOPE* s, TERM* t) {
|
||||||
if(!strcmp(t->string, "true")) return pushtrue();
|
if(!strcmp(t->string, "true")) return pushtrue();
|
||||||
if(!strcmp(t->string, "false")) return pushfalse();
|
if(!strcmp(t->string, "false")) return mklnblk(pushfalse());
|
||||||
if(!strcmp(t->string, "this")) return pushthis();
|
if(!strcmp(t->string, "this")) return mklnblk(pushthisadd());
|
||||||
eprintf("Unsupported keyword '%s'\n", t->string);
|
eprintf("Unsupported keyword '%s'\n", t->string);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -185,16 +213,31 @@ LINEBLOCK* compilestrconst(char* str) {
|
||||||
appendlnbefore(blk, mksimpleln(mknew, strcount(mknew)));
|
appendlnbefore(blk, mksimpleln(mknew, strcount(mknew)));
|
||||||
appendlnbefore(blk, mksimpleln(strsize, strcount(strsize)));
|
appendlnbefore(blk, mksimpleln(strsize, strcount(strsize)));
|
||||||
free(strsize[2]);
|
free(strsize[2]);
|
||||||
|
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilearrayitem(SCOPE* s, TERM* t) {
|
||||||
|
LINEBLOCK* blk = compileexpression(s, t->array->exp);
|
||||||
|
appendln(blk, pushvar(s, t->array->name));
|
||||||
|
|
||||||
|
appendln(blk, onetoken("add"));
|
||||||
|
|
||||||
|
appendln(blk, popthatadd());
|
||||||
|
appendln(blk, pushthat());
|
||||||
|
|
||||||
|
return blk;
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* compileterm(SCOPE* s, TERM* t) {
|
LINEBLOCK* compileterm(SCOPE* s, TERM* t) {
|
||||||
if(t->type == intconstant) return pushconstant(t->integer);
|
if(t->type == intconstant) return mklnblk(pushconstant(t->integer));
|
||||||
if(t->type == unaryopterm) return pushunaryopterm(s, t);
|
if(t->type == unaryopterm) return pushunaryopterm(s, t);
|
||||||
if(t->type == innerexpression) return compileexpression(s, t->expression);
|
if(t->type == innerexpression) return compileexpression(s, t->expression);
|
||||||
if(t->type == varname) return pushvar(s, t->string);
|
if(t->type == varname) return mklnblk(pushvar(s, t->string));
|
||||||
if(t->type == subroutcall) return compilesubroutcall(s, t->call);
|
if(t->type == subroutcall) return compilesubroutcall(s, t->call);
|
||||||
if(t->type == keywordconstant) return compilekeywordconst(s, t);
|
if(t->type == keywordconstant) return compilekeywordconst(s, t);
|
||||||
if(t->type == stringconstant) return compilestrconst(t->string);
|
if(t->type == stringconstant) return compilestrconst(t->string);
|
||||||
|
return compilearrayitem(s, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* compileexpression(SCOPE* s, TERM* e) {
|
LINEBLOCK* compileexpression(SCOPE* s, TERM* e) {
|
||||||
|
@ -248,16 +291,15 @@ LINEBLOCK* compilesubroutcall(SCOPE* s, SUBROUTCALL* call) {
|
||||||
|
|
||||||
if(d->subroutclass == method) {
|
if(d->subroutclass == method) {
|
||||||
if(call->parentname == NULL)
|
if(call->parentname == NULL)
|
||||||
blk = mergelnblks(pushthis(), blk);
|
appendlnbefore(blk, pushthisadd());
|
||||||
else
|
else
|
||||||
blk = mergelnblks(pushvarraw(s, v), blk);
|
appendlnbefore(blk, pushvarraw(s, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
// void functions always return 0
|
// void functions always return 0
|
||||||
// therefore must be thrown away
|
// therefore must be thrown away
|
||||||
if(!strcmp(d->type, "void")) {
|
if(!strcmp(d->type, "void")) {
|
||||||
char* tokens[] = { "pop", "temp", "0" };
|
appendln(blk, poptemp());
|
||||||
appendln(blk, mksimpleln(tokens, sizeof(tokens) / sizeof(char*)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return blk;
|
return blk;
|
||||||
|
@ -316,7 +358,6 @@ LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st) {
|
||||||
appendln(blk, mksimpleln(endlabelln, strcount(endlabelln)));
|
appendln(blk, mksimpleln(endlabelln, strcount(endlabelln)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return blk;
|
return blk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,9 +392,20 @@ LINEBLOCK* compilewhile(COMPILER* c, SCOPE* s, CONDSTATEMENT* w) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l) {
|
LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l) {
|
||||||
// missing array ind
|
|
||||||
LINEBLOCK* blk = compileexpression(s, l->expression);
|
LINEBLOCK* blk = compileexpression(s, l->expression);
|
||||||
blk = mergelnblks(blk, popvar(s, l->varname));
|
|
||||||
|
if(l->arrayind != NULL) {
|
||||||
|
appendlnbefore(blk, onetoken("add"));
|
||||||
|
appendlnbefore(blk, pushvar(s, l->varname));
|
||||||
|
blk = mergelnblks(compileexpression(s, l->arrayind), blk);
|
||||||
|
|
||||||
|
appendln(blk, poptemp());
|
||||||
|
appendln(blk, popthatadd());
|
||||||
|
appendln(blk, pushtemp());
|
||||||
|
appendln(blk, popthat());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
appendln(blk, popvar(s, l->varname));
|
||||||
return blk;
|
return blk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
main.c
2
main.c
|
@ -135,6 +135,6 @@ int main(int argc, char* argv[]) {
|
||||||
currunit = currunit->next;
|
currunit = currunit->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeos();
|
//freeos();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,11 +78,12 @@ bool isdotjack(char* f, int len) {
|
||||||
bool isdir(char* f, int len) {
|
bool isdir(char* f, int len) {
|
||||||
bool readsmt = false;
|
bool readsmt = false;
|
||||||
for(int i = len-1; i >= 0; i--) {
|
for(int i = len-1; i >= 0; i--) {
|
||||||
if(f[i] == '.')
|
if(f[i] == '.') {
|
||||||
if(readsmt)
|
if(readsmt)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if(f[i] == '/')
|
if(f[i] == '/')
|
||||||
return 1;
|
return 1;
|
||||||
readsmt = true;
|
readsmt = true;
|
||||||
|
|
|
@ -14,7 +14,7 @@ CLASS* addclass(const char* name) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLASS* adddec(CLASS* c, SUBROUTCLASS subroutclass, char* type, const char* name) {
|
void adddec(CLASS* c, SUBROUTCLASS subroutclass, char* type, const char* name) {
|
||||||
SUBROUTDEC* dec = (SUBROUTDEC*)malloc(sizeof(SUBROUTDEC));
|
SUBROUTDEC* dec = (SUBROUTDEC*)malloc(sizeof(SUBROUTDEC));
|
||||||
dec->class = c;
|
dec->class = c;
|
||||||
dec->subroutclass = subroutclass;
|
dec->subroutclass = subroutclass;
|
||||||
|
@ -151,5 +151,5 @@ SUBROUTDEC* getossubroutdec(SUBROUTCALL* call) {
|
||||||
CLASS* c = getosclass(call->parentname);
|
CLASS* c = getosclass(call->parentname);
|
||||||
if(c == NULL)
|
if(c == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
getsubroutdecinclass(c, call->name);
|
return getsubroutdecinclass(c, call->name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,10 +99,11 @@ TERM* parsecalltermnullified(PARSER* p) {
|
||||||
|
|
||||||
TERM* parsearrayterm(PARSER* p) {
|
TERM* parsearrayterm(PARSER* p) {
|
||||||
TERM* t = mkterm(arrayitem);
|
TERM* t = mkterm(arrayitem);
|
||||||
t->string = p->current->token;
|
t->array = (ARRAY*)malloc(sizeof(ARRAY));
|
||||||
|
t->array->name = p->current->token;
|
||||||
next(p);
|
next(p);
|
||||||
checkcontent(p, "[");
|
checkcontent(p, "[");
|
||||||
t->arrayexp = parseexpression(p);
|
t->array->exp = parseexpression(p);
|
||||||
checkcontent(p, "]");
|
checkcontent(p, "]");
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,11 @@ typedef enum {
|
||||||
varname, intconstant, stringconstant, keywordconstant, arrayitem, subroutcall, innerexpression, unaryopterm
|
varname, intconstant, stringconstant, keywordconstant, arrayitem, subroutcall, innerexpression, unaryopterm
|
||||||
} TERMTYPE;
|
} TERMTYPE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* name;
|
||||||
|
struct term* exp;
|
||||||
|
} ARRAY;
|
||||||
|
|
||||||
typedef struct term {
|
typedef struct term {
|
||||||
TERMTYPE type;
|
TERMTYPE type;
|
||||||
union {
|
union {
|
||||||
|
@ -127,8 +132,8 @@ typedef struct term {
|
||||||
int integer;
|
int integer;
|
||||||
struct subroutcall* call;
|
struct subroutcall* call;
|
||||||
struct term* expression;
|
struct term* expression;
|
||||||
|
ARRAY* array;
|
||||||
};
|
};
|
||||||
struct term* arrayexp;
|
|
||||||
char op;
|
char op;
|
||||||
char unaryop;
|
char unaryop;
|
||||||
struct term* next;
|
struct term* next;
|
||||||
|
|
Loading…
Reference in New Issue