URL
https://opencores.org/ocsvn/raptor64/raptor64/trunk
Subversion Repositories raptor64
Compare Revisions
- This comparison shows the changes necessary to convert path
/raptor64/trunk/software/c64/source
- from Rev 36 to Rev 37
- ↔ Reverse comparison
Rev 36 → Rev 37
/GenerateFunction.c
0,0 → 1,241
// ============================================================================ |
// (C) 2012 Robert Finch |
// All Rights Reserved. |
// robfinch<remove>@opencores.org |
// |
// C64 - Raptor64 'C' derived language compiler |
// - 64 bit CPU |
// |
// This source file is free software: you can redistribute it and/or modify |
// it under the terms of the GNU Lesser General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or |
// (at your option) any later version. |
// |
// This source file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public License |
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
// |
// ============================================================================ |
// |
#include <stdio.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
extern int breaklab; |
extern int contlab; |
extern int retlab; |
extern int throwlab; |
|
extern int lastsph; |
extern char *semaphores[20]; |
|
extern TYP stdfunc; |
|
void GenerateReturn(SYM *sym, Statement *stmt); |
|
|
// Generate a function body. |
// |
void GenerateFunction(SYM *sym, Statement *stmt) |
{ |
char buf[20]; |
char *bl; |
|
throwlab = retlab = contlab = breaklab = -1; |
lastsph = 0; |
memset(semaphores,0,sizeof(semaphores)); |
throwlab = nextlabel++; |
while( lc_auto & 7 ) /* round frame size to word */ |
++lc_auto; |
if (sym->IsInterrupt) { |
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(30*8)); |
GenerateDiadic(op_sm,0,make_indirect(30), make_mask(0x9FFFFFFE)); |
} |
if (!sym->IsNocall) { |
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(24)); |
// For a leaf routine don't bother to store the link register or exception link register. |
if (sym->IsLeaf) |
GenerateDiadic(op_sw,0,makereg(27),make_indirect(30)); |
else { |
GenerateDiadic(op_sm, 0, make_indirect(30), make_mask(0x98000000)); |
GenerateDiadic(op_lea,0,makereg(28),make_label(throwlab)); |
} |
GenerateDiadic(op_mov,0,makereg(27),makereg(30)); |
if (lc_auto) |
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(lc_auto)); |
} |
if (optimize) |
opt1(stmt); |
GenerateStatement(stmt); |
GenerateReturn(sym,0); |
// Generate code for the hidden default catch |
GenerateLabel(throwlab); |
if (sym->IsLeaf){ |
if (sym->DoesThrow) { |
GenerateDiadic(op_mov,0,makereg(31),makereg(28)); |
GenerateDiadic(op_bra,0,make_label(retlab),NULL); // goto regular return cleanup code |
} |
} |
else { |
GenerateDiadic(op_lw,0,makereg(31),make_indexed(16,27)); // load throw return address from stack into LR |
GenerateDiadic(op_sw,0,makereg(31),make_indirect(27)); // and store it back (so it can be loaded with the lm) |
GenerateDiadic(op_bra,0,make_label(retlab),NULL); // goto regular return cleanup code |
} |
} |
|
|
// Generate a return statement. |
// |
void GenerateReturn(SYM *sym, Statement *stmt) |
{ |
AMODE *ap; |
int nn; |
int lab1; |
|
if( stmt != NULL && stmt->exp != NULL ) |
{ |
initstack(); |
ap = GenerateExpression(stmt->exp,F_REG|F_IMMED,8); |
// Force return value into register 1 |
if( ap->preg != 1 ) { |
if (ap->mode == am_immed) |
GenerateTriadic(op_ori, 0, makereg(1),makereg(0),ap); |
else |
GenerateDiadic(op_mov, 0, makereg(1),ap); |
} |
} |
// Generate the return code only once. Branch to the return code for all returns. |
if( retlab == -1 ) |
{ |
retlab = nextlabel++; |
GenerateLabel(retlab); |
// Unlock any semaphores that may have been set |
for (nn = lastsph - 1; nn >= 0; nn--) |
GenerateDiadic(op_sb,0,makereg(0),make_string(semaphores[nn])); |
if (sym->IsNocall) // nothing to do for nocall convention |
return; |
// Restore registers used as register variables. |
if( save_mask != 0 ) { |
if (bitsset(save_mask) < 2) { |
for (nn = 31; nn >=1 ; nn--) |
if (save_mask & (1 << nn)) |
GenerateTriadic(op_lw,0,makereg(nn),make_indirect(30),NULL); |
} |
else |
GenerateTriadic(op_lm,0,make_indirect(30),make_mask(save_mask),NULL); |
} |
// Unlink the stack |
// For a leaf routine the link register and exception link register doesn't need to be saved/restored. |
GenerateDiadic(op_mov,0,makereg(30),makereg(27)); |
if (sym->IsLeaf) |
GenerateDiadic(op_lw,0,makereg(27),make_indirect(30)); |
else |
GenerateDiadic(op_lm,0,make_indirect(30),make_mask(0x98000000)); |
//if (isOscall) { |
// GenerateDiadic(op_move,0,makereg(0),make_string("_TCBregsave")); |
// gen_regrestore(); |
//} |
// Generate the return instruction. For the Pascal calling convention pop the parameters |
// from the stack. |
if (sym->IsInterrupt) { |
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(24)); |
GenerateDiadic(op_lm,0,make_indirect(30),make_mask(0x9FFFFFFE)); |
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(popcnt(0x9FFFFFFE)*8)); |
GenerateDiadic(op_iret,0,NULL,NULL); |
return; |
} |
if (sym->IsPascal) |
GenerateDiadic(op_ret,0,make_immed(24+sym->NumParms * 8),NULL); |
else |
GenerateDiadic(op_ret,0,make_immed(24),NULL); |
} |
// Just branch to the already generated stack cleanup code. |
else { |
GenerateDiadic(op_bra,0,make_label(retlab),0); |
} |
} |
|
// push the operand expression onto the stack. |
// |
static void GeneratePushParameter(ENODE *ep, int i, int n) |
{ |
AMODE *ap; |
ap = GenerateExpression(ep,F_REG,8); |
GenerateDiadic(op_sw,0,ap,make_indexed((n-i)*8-8,30)); |
ReleaseTempRegister(ap); |
} |
|
// push entire parameter list onto stack |
// |
static int GeneratePushParameterList(ENODE *plist) |
{ |
ENODE *st = plist; |
int i,n; |
// count the number of parameters |
for(n = 0; plist != NULL; n++ ) |
plist = plist->p[1]; |
// move stack pointer down by number of parameters |
if (st) |
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(n*8)); |
plist = st; |
for(i = 0; plist != NULL; i++ ) |
{ |
GeneratePushParameter(plist->p[0],i,n); |
plist = plist->p[1]; |
} |
return i; |
} |
|
AMODE *GenerateFunctionCall(ENODE *node, int flags) |
{ |
AMODE *ap, *result; |
SYM *sym; |
int i; |
int msk; |
|
msk = SaveTempRegs(); |
sym = NULL; |
i = GeneratePushParameterList(node->p[1]); |
// Call the function |
if( node->p[0]->nodetype == en_nacon ) { |
GenerateDiadic(op_call,0,make_offset(node->p[0]),NULL); |
sym = gsearch(node->p[0]->sp); |
} |
else |
{ |
ap = GenerateExpression(node->p[0],F_REG,8); |
ap->mode = am_ind; |
GenerateDiadic(op_jal,0,makereg(31),ap); |
ReleaseTempRegister(ap); |
} |
// Pop parameters off the stack |
if (i!=0) { |
if (sym) { |
if (!sym->IsPascal) |
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(i * 8)); |
} |
else |
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(i * 8)); |
} |
RestoreTempRegs(msk); |
result = GetTempRegister(); |
if( result->preg != 1 || (flags & F_REG) == 0 ) |
if (sym) { |
if (sym->tp->btp->type==bt_void) |
; |
else |
GenerateTriadic(op_or,0,result,makereg(1),makereg(0)); |
} |
else |
GenerateTriadic(op_or,0,result,makereg(1),makereg(0)); |
return result; |
} |
|
/ParseEnumDeclaration.c
0,0 → 1,88
#include <stdio.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
extern TABLE tagtable; |
extern TYP *head; |
extern TYP stdconst; |
|
void enumbody(TABLE *table); |
|
void ParseEnumDeclaration(TABLE *table) |
{ |
SYM *sp; |
TYP *tp; |
if( lastst == id) { |
if((sp = search(lastid,&tagtable)) == NULL) { |
sp = allocSYM(); |
sp->tp = allocTYP(); |
sp->tp->type = bt_enum; |
sp->tp->size = 2; |
sp->tp->lst.head = 0; |
sp->tp->btp = 0; |
sp->storage_class = sc_type; |
sp->name = litlate(lastid); |
sp->tp->sname = sp->name; |
NextToken(); |
if( lastst != begin) |
error(ERR_INCOMPLETE); |
else { |
insert(sp,&tagtable); |
NextToken(); |
ParseEnumerationList(table); |
} |
} |
else |
NextToken(); |
head = sp->tp; |
} |
else { |
tp = allocTYP(); // fix here |
tp->type = bt_short; |
if( lastst != begin) |
error(ERR_INCOMPLETE); |
else { |
NextToken(); |
ParseEnumerationList(table); |
} |
head = tp; |
} |
} |
|
void ParseEnumerationList(TABLE *table) |
{ |
int evalue; |
SYM *sp; |
evalue = 0; |
while(lastst == id) { |
sp = allocSYM(); |
sp->name = litlate(lastid); |
sp->storage_class = sc_const; |
sp->tp = &stdconst; |
insert(sp,table); |
NextToken(); |
if (lastst==assign) { |
NextToken(); |
sp->value.i = GetIntegerExpression(); |
evalue = sp->value.i+1; |
} |
else |
sp->value.i = evalue++; |
if( lastst == comma) |
NextToken(); |
else if(lastst != end) |
break; |
} |
needpunc(end); |
} |
|
/List.c
0,0 → 1,170
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
void ListTable(TABLE *t, int i); |
|
void put_typedef(int td) |
{ |
fprintf(list,td ? " 1 " : " - "); |
} |
|
void put_sc(int scl) |
{ switch(scl) { |
case sc_static: |
fprintf(list,"Static "); |
break; |
case sc_auto: |
fprintf(list,"Auto "); |
break; |
case sc_global: |
fprintf(list,"Global "); |
break; |
case sc_external: |
fprintf(list,"External "); |
break; |
case sc_type: |
fprintf(list,"Type "); |
break; |
case sc_const: |
fprintf(list,"Constant "); |
break; |
case sc_member: |
fprintf(list,"Member "); |
break; |
case sc_label: |
fprintf(list,"Label"); |
break; |
case sc_ulabel: |
fprintf(list,"Undefined label"); |
break; |
} |
} |
|
void put_ty(TYP *tp) |
{ if(tp == 0) |
return; |
switch(tp->type) { |
case bt_byte: |
fprintf(list,"Byte"); |
break; |
case bt_char: |
fprintf(list,"Char"); |
break; |
case bt_short: |
fprintf(list,"Short"); |
break; |
case bt_enum: |
fprintf(list,"enum "); |
goto ucont; |
case bt_long: |
fprintf(list,"Long"); |
break; |
case bt_unsigned: |
fprintf(list,"unsigned long"); |
break; |
case bt_float: |
fprintf(list,"Float"); |
break; |
case bt_double: |
fprintf(list,"Double"); |
break; |
case bt_pointer: |
if( tp->val_flag == 0) |
fprintf(list,"Pointer to "); |
else |
fprintf(list,"Array of "); |
put_ty(tp->btp); |
break; |
case bt_union: |
fprintf(list,"union "); |
goto ucont; |
case bt_struct: |
fprintf(list,"struct "); |
ucont: if(tp->sname == 0) |
fprintf(list,"<no name> "); |
else |
fprintf(list,"%s ",tp->sname); |
break; |
case bt_ifunc: |
case bt_func: |
fprintf(list,"Function returning "); |
put_ty(tp->btp); |
break; |
} |
} |
|
void list_var(SYM *sp, int i) |
{ int j; |
for(j = i; j; --j) |
fprintf(list," "); |
if (sp->name == NULL) |
fprintf(list,"%-10s =%06x ","<unnamed>",sp->value.u); |
else |
fprintf(list,"%-10s =%06x ",sp->name,sp->value.u); |
if( sp->storage_class == sc_external) |
fprintf(output,"\textern\t%s\n",sp->name); |
else if( sp->storage_class == sc_global ) |
fprintf(output,";\tglobal\t%s\n",sp->name); |
put_typedef(sp->storage_class==sc_typedef); |
put_sc(sp->storage_class); |
put_ty(sp->tp); |
fprintf(list,"\n"); |
if(sp->tp == 0) |
return; |
if((sp->tp->type == bt_struct || sp->tp->type == bt_union) && |
sp->storage_class == sc_type) |
ListTable(&(sp->tp->lst),i+1); |
} |
|
void ListTable(TABLE *t, int i) |
{ |
SYM *sp; |
int nn; |
|
if (t==&gsyms[0]) { |
for (nn = 0; nn < 257; nn++) { |
t = &gsyms[nn]; |
sp = t->head; |
while(sp != NULL) { |
list_var(sp,i); |
sp = sp->next; |
} |
} |
} |
else { |
sp = t->head; |
while(sp != NULL) { |
list_var(sp,i); |
sp = sp->next; |
} |
} |
} |
|
|
|
/ParseExpressions.c
0,0 → 1,1145
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
TYP stdint = { bt_long, bt_long, 0, FALSE, FALSE, FALSE, 0,0,8, {0, 0}, 0, 0 }; |
TYP stduint = { bt_long, bt_long, 0, TRUE, FALSE, FALSE, 0,0,8, {0, 0}, 0, 0 }; |
TYP stdlong = { bt_long, bt_long, 0, FALSE, FALSE, FALSE, 0,0,8, {0, 0}, 0, 0 }; |
TYP stdulong = { bt_long, bt_long, 0, TRUE, FALSE, FALSE, 0,0,8, {0, 0}, 0, 0 }; |
TYP stdshort = { bt_short, bt_short, 0, FALSE, FALSE, FALSE, 0,0,4, {0, 0}, 0, 0 }; |
TYP stdushort = { bt_short, bt_short, 0, TRUE, FALSE, FALSE, 0,0,4, {0, 0}, 0, 0 }; |
TYP stdchar = {bt_char, bt_char, 0, FALSE, FALSE, FALSE, 0,0,2, {0, 0}, 0, 0 }; |
TYP stduchar = {bt_char, bt_char, 0, TRUE, FALSE, FALSE, 0,0,2, {0, 0}, 0, 0 }; |
TYP stdbyte = {bt_byte, bt_byte, 0, FALSE, FALSE, FALSE, 0,0,1, {0, 0}, 0, 0 }; |
TYP stdubyte = {bt_byte, bt_byte, 0, TRUE, FALSE, FALSE, 0,0,1, {0, 0}, 0, 0 }; |
TYP stdstring = {bt_pointer, bt_pointer, 1, FALSE, FALSE, FALSE, 0,0,4, {0, 0}, &stdchar, 0}; |
TYP stdfunc = {bt_func, bt_func, 1, FALSE, FALSE, FALSE, 0,0,0, {0, 0}, &stdint, 0}; |
extern TYP *head; /* shared with ParseSpecifier */ |
extern TYP *tail; |
|
/* |
* expression evaluation |
* |
* this set of routines builds a parse tree for an expression. |
* no code is generated for the expressions during the build, |
* this is the job of the codegen module. for most purposes |
* expression() is the routine to call. it will allow all of |
* the C operators. for the case where the comma operator is |
* not valid (function parameters for instance) call NonCommaExpression(). |
* |
* each of the routines returns a pointer to a describing type |
* structure. each routine also takes one parameter which is a |
* pointer to an expression node by reference (address of pointer). |
* the completed expression is returned in this pointer. all |
* routines return either a pointer to a valid type or NULL if |
* the hierarchy of the next operator is too low or the next |
* symbol is not part of an expression. |
*/ |
|
TYP *expression(); /* forward ParseSpecifieraration */ |
TYP *NonCommaExpression(); /* forward ParseSpecifieraration */ |
TYP *ParseUnaryExpression(); /* forward ParseSpecifieraration */ |
|
/* |
* build an expression node with a node type of nt and values |
* v1 and v2. |
*/ |
ENODE *makenode(int nt, ENODE *v1, ENODE *v2) |
{ |
ENODE *ep; |
ep = (ENODE *)xalloc(sizeof(ENODE)); |
ep->nodetype = nt; |
ep->constflag = FALSE; |
ep->etype = bt_void; |
ep->esize = -1; |
ep->p[0] = v1; |
ep->p[1] = v2; |
return ep; |
} |
|
ENODE *makesnode(int nt, char *v1) |
{ |
ENODE *ep; |
ep = (ENODE *)xalloc(sizeof(ENODE)); |
ep->nodetype = nt; |
ep->constflag = FALSE; |
ep->etype = bt_void; |
ep->esize = -1; |
ep->sp = v1; |
return ep; |
} |
|
ENODE *makenodei(int nt, ENODE *v1, __int64 i) |
{ |
ENODE *ep; |
ep = (ENODE *)xalloc(sizeof(ENODE)); |
ep->nodetype = nt; |
ep->constflag = FALSE; |
ep->etype = bt_void; |
ep->esize = -1; |
ep->i = i; |
ep->p[0] = v1; |
ep->p[1] = NULL; |
return ep; |
} |
|
ENODE *makeinode(int nt, __int64 v1) |
{ |
ENODE *ep; |
ep = (ENODE *)xalloc(sizeof(ENODE)); |
ep->nodetype = nt; |
ep->constflag = TRUE; |
ep->etype = bt_void; |
ep->esize = -1; |
ep->i = v1; |
return ep; |
} |
|
void PromoteConstFlag(ENODE *ep) |
{ |
ep->constflag = ep->p[0]->constflag && ep->p[1]->constflag; |
} |
|
/* |
* build the proper dereference operation for a node using the |
* type pointer tp. |
*/ |
TYP *deref(ENODE **node, TYP *tp) |
{ |
switch( tp->type ) { |
case bt_byte: |
if (tp->isUnsigned) |
*node = makenode(en_ub_ref,*node,NULL); |
else |
*node = makenode(en_b_ref,*node,NULL); |
(*node)->esize = tp->size; |
(*node)->etype = tp->type; |
tp = &stdint; |
break; |
case bt_char: |
case bt_enum: |
if (tp->isUnsigned) |
*node = makenode(en_uc_ref,*node,NULL); |
else |
*node = makenode(en_c_ref,*node,NULL); |
(*node)->esize = tp->size; |
(*node)->etype = tp->type; |
tp = &stdchar; |
break; |
case bt_short: |
*node = makenode(en_h_ref,*node,NULL); |
(*node)->esize = tp->size; |
(*node)->etype = tp->type; |
tp = &stdint; |
break; |
case bt_long: |
case bt_pointer: |
case bt_unsigned: |
(*node)->esize = tp->size; |
(*node)->etype = tp->type; |
*node = makenode(en_w_ref,*node,NULL); |
break; |
case bt_bitfield: |
if (tp->isUnsigned){ |
if (tp->size==1) |
*node = makenode(en_ubfieldref, *node, NULL); |
else if (tp->size==2) |
*node = makenode(en_ucfieldref, *node, NULL); |
else if (tp->size==4) |
*node = makenode(en_uhfieldref, *node, NULL); |
else |
*node = makenode(en_wfieldref, *node, NULL); |
} |
else { |
if (tp->size==1) |
*node = makenode(en_bfieldref, *node, NULL); |
else if (tp->size==2) |
*node = makenode(en_cfieldref, *node, NULL); |
else if (tp->size==4) |
*node = makenode(en_hfieldref, *node, NULL); |
else |
*node = makenode(en_wfieldref, *node, NULL); |
} |
(*node)->bit_width = tp->bit_width; |
(*node)->bit_offset = tp->bit_offset; |
/* |
* maybe it should be 'unsigned' |
*/ |
(*node)->etype = stdint.type; |
(*node)->esize = tp->size; |
tp = &stdint; |
break; |
default: |
error(ERR_DEREF); |
break; |
} |
return tp; |
} |
|
/* |
* nameref will build an expression tree that references an |
* identifier. if the identifier is not in the global or |
* local symbol table then a look-ahead to the next character |
* is done and if it indicates a function call the identifier |
* is coerced to an external function name. non-value references |
* generate an additional level of indirection. |
*/ |
TYP *nameref(ENODE **node) |
{ |
SYM *sp; |
TYP *tp; |
sp = gsearch(lastid); |
if( sp == NULL ) { |
while( isspace(lastch) ) |
getch(); |
if( lastch == '(') { |
++global_flag; |
sp = allocSYM(); |
sp->tp = &stdfunc; |
sp->name = litlate(lastid); |
sp->storage_class = sc_external; |
insert(sp,&gsyms); |
--global_flag; |
tp = &stdfunc; |
*node = makesnode(en_nacon,sp->name); |
(*node)->constflag = TRUE; |
} |
else { |
tp = NULL; |
error(ERR_UNDEFINED); |
} |
} |
else { |
if( (tp = sp->tp) == NULL ) { |
error(ERR_UNDEFINED); |
return NULL; /* guard against untyped entries */ |
} |
switch( sp->storage_class ) { |
case sc_static: |
*node = makeinode(en_labcon,sp->value.i); |
(*node)->constflag = TRUE; |
break; |
case sc_global: |
case sc_external: |
*node = makesnode(en_nacon,sp->name); |
(*node)->constflag = TRUE; |
break; |
case sc_const: |
*node = makeinode(en_icon,sp->value.i); |
(*node)->constflag = TRUE; |
break; |
default: /* auto and any errors */ |
if( sp->storage_class != sc_auto) |
error(ERR_ILLCLASS); |
*node = makeinode(en_autocon,sp->value.i); |
break; |
} |
if( tp->val_flag == FALSE) |
tp = deref(node,tp); |
} |
NextToken(); |
return tp; |
} |
|
/* |
* ArgumentList will build a list of parameter expressions in |
* a function call and return a pointer to the last expression |
* parsed. since parameters are generally pushed from right |
* to left we get just what we asked for... |
*/ |
ENODE *ArgumentList() |
{ |
struct ENODE *ep1, *ep2; |
ep1 = 0; |
while( lastst != closepa) |
{ |
NonCommaExpression(&ep2); /* evaluate a parameter */ |
ep1 = makenode(en_void,ep2,ep1); |
if( lastst != comma) |
break; |
NextToken(); |
} |
return ep1; |
} |
|
/* |
* return 1 if st in set of [ kw_char, kw_short, kw_long, kw_int, |
* kw_float, kw_double, kw_struct, kw_union ] |
*/ |
static int IsIntrinsicType(int st) |
{ |
return st == kw_byte || st==kw_char || st == kw_short || st == kw_int || st==kw_void || |
st == kw_long || st == kw_float || st == kw_double || st==kw_enum || |
st == kw_struct || st == kw_union || st== kw_unsigned || st==kw_signed; |
} |
|
int IsBeginningOfTypecast(int st) |
{ |
SYM *sp; |
if (st==id) { |
sp = search(lastid,&gsyms[0]); |
if (sp) |
return sp->storage_class==sc_typedef; |
return FALSE; |
} |
else |
return IsIntrinsicType(st); |
} |
|
/* |
* primary will parse a primary expression and set the node pointer |
* returning the type of the expression parsed. primary expressions |
* are any of: |
* id |
* constant |
* string |
* ( expression ) |
* primary[ expression ] |
* primary.id |
* primary->id |
* primary( parameter list ) |
*/ |
TYP *ParsePrimaryExpression(ENODE **node) |
{ |
ENODE *pnode, *qnode, *rnode, *snode; |
SYM *sp; |
TYP *tptr; |
switch( lastst ) { |
|
case id: |
tptr = nameref(&pnode); |
break; |
case iconst: |
tptr = &stdint; |
pnode = makeinode(en_icon,ival); |
pnode->constflag = TRUE; |
NextToken(); |
break; |
case sconst: |
tptr = &stdstring; |
pnode = makenode(en_labcon,stringlit(laststr),NULL); |
pnode->constflag = TRUE; |
NextToken(); |
break; |
|
case openpa: |
NextToken(); |
if( !IsBeginningOfTypecast(lastst) ) { |
tptr = expression(&pnode); |
needpunc(closepa); |
} |
else { /* cast operator */ |
ParseSpecifier(0); /* do cast ParseSpecifieraration */ |
ParseDeclarationPrefix(FALSE); |
tptr = head; |
needpunc(closepa); |
if( ParseUnaryExpression(&pnode) == NULL ) { |
error(ERR_IDEXPECT); |
tptr = NULL; |
} |
} |
break; |
|
default: |
return NULL; |
} |
for(;;) { |
switch( lastst ) { |
case openbr: /* build a subscript reference */ |
if (tptr==NULL) { |
error(ERR_UNDEFINED); |
goto fini; |
} |
if( tptr->type != bt_pointer ) |
error(ERR_NOPOINTER); |
else |
tptr = tptr->btp; |
NextToken(); |
qnode = makeinode(en_icon,tptr->size); |
qnode->constflag = TRUE; |
expression(&rnode); |
/* |
* we could check the type of the expression here... |
*/ |
qnode = makenode(en_mulu,qnode,rnode); |
qnode->constflag = rnode->constflag && qnode->p[0]->constflag; |
pnode = makenode(en_add,qnode,pnode); |
pnode->constflag = qnode->constflag && pnode->p[1]->constflag; |
////snode = makenode(en_mul,qnode,rnode); |
////snode->constflag = rnode->constflag && snode->p[0]->constflag; |
////pnode = makenode(en_add,snode,pnode); |
////pnode->constflag = snode->constflag && pnode->p[1]->constflag; |
if( tptr->val_flag == FALSE ) |
tptr = deref(&pnode,tptr); |
needpunc(closebr); |
break; |
|
case pointsto: |
if (tptr==NULL) { |
error(ERR_UNDEFINED); |
goto fini; |
} |
if( tptr->type != bt_pointer ) |
error(ERR_NOPOINTER); |
else |
tptr = tptr->btp; |
if( tptr->val_flag == FALSE ) |
pnode = makenode(en_w_ref,pnode,NULL); |
/* |
* fall through to dot operation |
*/ |
case dot: |
NextToken(); /* past -> or . */ |
if( lastst != id ) |
error(ERR_IDEXPECT); |
else { |
sp = search(lastid,&tptr->lst); |
if( sp == NULL ) |
error(ERR_NOMEMBER); |
else { |
tptr = sp->tp; |
qnode = makeinode(en_icon,sp->value.i); |
qnode->constflag = TRUE; |
pnode = makenode(en_add,pnode,qnode); |
pnode->constflag = pnode->p[0]->constflag; |
if( tptr->val_flag == FALSE ) |
tptr = deref(&pnode,tptr); |
} |
NextToken(); /* past id */ |
} |
break; |
|
case openpa: /* function reference */ |
NextToken(); |
if( tptr->type != bt_func && tptr->type != bt_ifunc ) |
error(ERR_NOFUNC); |
else |
tptr = tptr->btp; |
currentFn->IsLeaf = FALSE; |
pnode = makenode(en_fcall,pnode,ArgumentList()); |
needpunc(closepa); |
break; |
|
default: |
goto fini; |
} |
} |
fini: *node = pnode; |
return tptr; |
} |
|
/* |
* this function returns true if the node passed is an IsLValue. |
* this can be qualified by the fact that an IsLValue must have |
* one of the dereference operators as it's top node. |
*/ |
int IsLValue(ENODE *node) |
{ |
switch( node->nodetype ) { |
case en_b_ref: |
case en_c_ref: |
case en_h_ref: |
case en_w_ref: |
case en_ub_ref: |
case en_uc_ref: |
case en_uh_ref: |
case en_uw_ref: |
case en_wfieldref: |
case en_uwfieldref: |
case en_bfieldref: |
case en_ubfieldref: |
case en_cfieldref: |
case en_ucfieldref: |
case en_hfieldref: |
case en_uhfieldref: |
return TRUE; |
case en_cbc: |
case en_cbh: |
case en_cbw: |
case en_cch: |
case en_ccw: |
case en_chw: |
return IsLValue(node->p[0]); |
} |
return FALSE; |
} |
|
/* |
* ParseUnaryExpression evaluates unary expressions and returns the type of the |
* expression evaluated. unary expressions are any of: |
* |
* primary |
* primary++ |
* primary-- |
* !unary |
* ~unary |
* ++unary |
* --unary |
* -unary |
* *unary |
* &unary |
* (typecast)unary |
* sizeof(typecast) |
* typenum(typecast) |
* |
*/ |
TYP *ParseUnaryExpression(ENODE **node) |
{ |
TYP *tp, *tp1; |
ENODE *ep1, *ep2; |
int flag; |
__int64 i; |
|
flag = 0; |
switch( lastst ) { |
case autodec: |
flag = 1; |
/* fall through to common increment */ |
case autoinc: |
NextToken(); |
tp = ParseUnaryExpression(&ep1); |
if( tp == NULL ) { |
error(ERR_IDEXPECT); |
return NULL; |
} |
if( IsLValue(ep1)) { |
if( tp->type == bt_pointer ) |
ep2 = makeinode(en_icon,tp->btp->size); |
else |
ep2 = makeinode(en_icon,1); |
ep2->constflag = TRUE; |
ep1 = makenode(flag ? en_assub : en_asadd,ep1,ep2); |
} |
else |
error(ERR_LVALUE); |
break; |
|
case minus: |
NextToken(); |
tp = ParseUnaryExpression(&ep1); |
if( tp == NULL ) { |
error(ERR_IDEXPECT); |
return NULL; |
} |
ep1 = makenode(en_uminus,ep1,NULL); |
ep1->constflag = ep1->p[0]->constflag; |
break; |
|
case not: |
NextToken(); |
tp = ParseUnaryExpression(&ep1); |
if( tp == NULL ) { |
error(ERR_IDEXPECT); |
return NULL; |
} |
ep1 = makenode(en_not,ep1,NULL); |
ep1->constflag = ep1->p[0]->constflag; |
break; |
|
case compl: |
NextToken(); |
tp = ParseUnaryExpression(&ep1); |
if( tp == NULL ) { |
error(ERR_IDEXPECT); |
return 0; |
} |
ep1 = makenode(en_compl,ep1,NULL); |
ep1->constflag = ep1->p[0]->constflag; |
break; |
|
case star: |
NextToken(); |
tp = ParseUnaryExpression(&ep1); |
if( tp == NULL ) { |
error(ERR_IDEXPECT); |
return NULL; |
} |
if( tp->btp == NULL ) |
error(ERR_DEREF); |
else |
tp = tp->btp; |
if( tp->val_flag == FALSE ) |
tp = deref(&ep1,tp); |
break; |
|
case and: |
NextToken(); |
tp = ParseUnaryExpression(&ep1); |
if( tp == NULL ) { |
error(ERR_IDEXPECT); |
return NULL; |
} |
if( IsLValue(ep1)) |
ep1 = ep1->p[0]; |
tp1 = allocTYP(); |
tp1->size = 8; |
tp1->type = bt_pointer; |
tp1->btp = tp; |
tp1->val_flag = FALSE; |
tp1->lst.head = NULL; |
tp1->sname = NULL; |
tp = tp1; |
break; |
|
case kw_sizeof: |
NextToken(); |
needpunc(openpa); |
tp = head; |
tp1 = tail; |
ParseSpecifier(0); |
ParseDeclarationPrefix(FALSE); |
if( head != NULL ) |
ep1 = makeinode(en_icon,head->size); |
else { |
error(ERR_IDEXPECT); |
ep1 = makeinode(en_icon,1); |
} |
head = tp; |
tail = tp1; |
ep1->constflag = TRUE; |
tp = &stdint; |
needpunc(closepa); |
break; |
|
case kw_typenum: |
NextToken(); |
needpunc(openpa); |
tp = head; |
tp1 = tail; |
ParseSpecifier(0); |
ParseDeclarationPrefix(FALSE); |
if( head != NULL ) |
ep1 = makeinode(en_icon,GetTypeHash(head)); |
else { |
error(ERR_IDEXPECT); |
ep1 = makeinode(en_icon,1); |
} |
head = tp; |
tail = tp1; |
ep1->constflag = TRUE; |
tp = &stdint; |
needpunc(closepa); |
break; |
|
default: |
tp = ParsePrimaryExpression(&ep1); |
if( tp != NULL ) { |
if( tp->type == bt_pointer ) |
i = tp->btp->size; |
else |
i = 1; |
if( lastst == autoinc) { |
if( IsLValue(ep1) ) |
ep1 = makenodei(en_ainc,ep1,i); |
else |
error(ERR_LVALUE); |
NextToken(); |
} |
else if( lastst == autodec ) { |
if( IsLValue(ep1) ) |
ep1 = makenodei(en_adec,ep1,i); |
else |
error(ERR_LVALUE); |
NextToken(); |
} |
} |
break; |
} |
*node = ep1; |
return tp; |
} |
|
/* |
* forcefit will coerce the nodes passed into compatable |
* types and return the type of the resulting expression. |
*/ |
TYP *forcefit(ENODE **node1,TYP *tp1,ENODE **node2,TYP *tp2) |
{ |
switch( tp1->type ) { |
case bt_char: |
case bt_uchar: |
if (tp2->type == bt_long) { |
if (tp1->isUnsigned) |
return &stdulong; |
else |
return &stdlong; |
} |
if (tp2->type == bt_short) { |
if (tp1->isUnsigned) |
return &stdushort; |
else |
return &stdshort; |
} |
if (tp2->type == bt_pointer) |
return tp2; |
return tp1; // char |
case bt_short: |
case bt_ushort: |
if (tp2->type == bt_long) { |
if (tp1->isUnsigned) |
return &stdulong; |
else |
return &stdlong; |
} |
if (tp2->type == bt_pointer) |
return tp2; |
return tp1; |
case bt_long: |
case bt_ulong: |
if( tp2->type == bt_pointer ) |
return tp2; |
return tp1; |
case bt_pointer: |
if( isscalar(tp2) || tp2->type == bt_pointer) |
return tp1; |
break; |
case bt_unsigned: |
if( tp2->type == bt_pointer ) |
return tp2; |
else if( isscalar(tp2) ) |
return tp1; |
break; |
} |
error( ERR_MISMATCH ); |
return tp1; |
} |
|
/* |
* this function returns true when the type of the argument is |
* one of char, short, unsigned, or long. |
*/ |
int isscalar(TYP *tp) |
{ |
return |
tp->type == bt_byte || |
tp->type == bt_char || |
tp->type == bt_short || |
tp->type == bt_long || |
tp->type == bt_uchar || |
tp->type == bt_ushort || |
tp->type == bt_ulong || |
tp->type == bt_unsigned; |
} |
|
/* |
* multops parses the multiply priority operators. the syntax of |
* this group is: |
* |
* unary |
* multop * unary |
* multop / unary |
* multop % unary |
*/ |
TYP *multops(struct ENODE **node) |
{ |
struct ENODE *ep1, *ep2; |
TYP *tp1, *tp2; |
int oper; |
tp1 = ParseUnaryExpression(&ep1); |
if( tp1 == 0 ) |
return 0; |
while( lastst == star || lastst == divide || lastst == modop ) { |
oper = lastst; |
NextToken(); /* move on to next unary op */ |
tp2 = ParseUnaryExpression(&ep2); |
if( tp2 == 0 ) { |
error(ERR_IDEXPECT); |
*node = ep1; |
return tp1; |
} |
tp1 = forcefit(&ep1,tp1,&ep2,tp2); |
switch( oper ) { |
case star: |
if( tp1->isUnsigned ) |
ep1 = makenode(en_mulu,ep1,ep2); |
else |
ep1 = makenode(en_mul,ep1,ep2); |
break; |
case divide: |
if( tp1->isUnsigned ) |
ep1 = makenode(en_udiv,ep1,ep2); |
else |
ep1 = makenode(en_div,ep1,ep2); |
break; |
case modop: |
if( tp1->isUnsigned ) |
ep1 = makenode(en_umod,ep1,ep2); |
else |
ep1 = makenode(en_mod,ep1,ep2); |
break; |
} |
PromoteConstFlag(ep1); |
} |
*node = ep1; |
return tp1; |
} |
|
/* |
* addops handles the addition and subtraction operators. |
*/ |
TYP *addops(ENODE **node) |
{ |
ENODE *ep1, *ep2, *ep3; |
TYP *tp1, *tp2; |
int oper; |
|
tp1 = multops(&ep1); |
if( tp1 == NULL ) |
return NULL; |
while( lastst == plus || lastst == minus ) { |
oper = (lastst == plus); |
NextToken(); |
tp2 = multops(&ep2); |
if( tp2 == 0 ) { |
error(ERR_IDEXPECT); |
*node = ep1; |
return tp1; |
} |
if( tp1->type == bt_pointer ) { |
tp2 = forcefit(0,&stdint,&ep2,tp2); |
ep3 = makeinode(en_icon,tp1->btp->size); |
ep3->constflag = TRUE; |
ep2 = makenode(en_mulu,ep3,ep2); |
ep2->constflag = ep2->p[1]->constflag; |
} |
else if( tp2->type == bt_pointer ) { |
tp1 = forcefit(0,&stdint,&ep1,tp1); |
ep3 = makeinode(en_icon,tp2->btp->size); |
ep3->constflag = TRUE; |
ep1 = makenode(en_mulu,ep3,ep1); |
ep1->constflag = ep1->p[1]->constflag; |
} |
tp1 = forcefit(&ep1,tp1,&ep2,tp2); |
ep1 = makenode( oper ? en_add : en_sub,ep1,ep2); |
PromoteConstFlag(ep1); |
} |
*node = ep1; |
return tp1; |
} |
|
/* |
* shiftop handles the shift operators << and >>. |
*/ |
TYP *shiftop(ENODE **node) |
{ |
struct ENODE *ep1, *ep2; |
TYP *tp1, *tp2; |
int oper; |
tp1 = addops(&ep1); |
if( tp1 == 0) |
return 0; |
while( lastst == lshift || lastst == rshift) { |
oper = (lastst == lshift); |
NextToken(); |
tp2 = addops(&ep2); |
if( tp2 == 0 ) |
error(ERR_IDEXPECT); |
else { |
tp1 = forcefit(&ep1,tp1,&ep2,tp2); |
if (tp1->isUnsigned) |
ep1 = makenode(oper ? en_shl : en_shru,ep1,ep2); |
else |
ep1 = makenode(oper ? en_shl : en_shr,ep1,ep2); |
PromoteConstFlag(ep1); |
} |
} |
*node = ep1; |
return tp1; |
} |
|
/* |
* relation handles the relational operators < <= > and >=. |
*/ |
TYP *relation(ENODE **node) |
{ struct ENODE *ep1, *ep2; |
TYP *tp1, *tp2; |
int nt; |
tp1 = shiftop(&ep1); |
if( tp1 == 0 ) |
return 0; |
for(;;) { |
switch( lastst ) { |
|
case lt: |
if( tp1->isUnsigned ) |
nt = en_ult; |
else |
nt = en_lt; |
break; |
case gt: |
if( tp1->isUnsigned ) |
nt = en_ugt; |
else |
nt = en_gt; |
break; |
case leq: |
if( tp1->isUnsigned ) |
nt = en_ule; |
else |
nt = en_le; |
break; |
case geq: |
if( tp1->isUnsigned ) |
nt = en_uge; |
else |
nt = en_ge; |
break; |
default: |
goto fini; |
} |
NextToken(); |
tp2 = shiftop(&ep2); |
if( tp2 == 0 ) |
error(ERR_IDEXPECT); |
else { |
tp1 = forcefit(&ep1,tp1,&ep2,tp2); |
ep1 = makenode(nt,ep1,ep2); |
PromoteConstFlag(ep1); |
} |
} |
fini: *node = ep1; |
return tp1; |
} |
|
/* |
* equalops handles the equality and inequality operators. |
*/ |
TYP *equalops(ENODE **node) |
{ |
ENODE *ep1, *ep2; |
TYP *tp1, *tp2; |
int oper; |
tp1 = relation(&ep1); |
if( tp1 == NULL ) |
return NULL; |
while( lastst == eq || lastst == neq ) { |
oper = (lastst == eq); |
NextToken(); |
tp2 = relation(&ep2); |
if( tp2 == NULL ) |
error(ERR_IDEXPECT); |
else { |
tp1 = forcefit(&ep1,tp1,&ep2,tp2); |
ep1 = makenode( oper ? en_eq : en_ne,ep1,ep2); |
PromoteConstFlag(ep1); |
} |
} |
*node = ep1; |
return tp1; |
} |
|
/* |
* binop is a common routine to handle all of the legwork and |
* error checking for bitand, bitor, bitxor, andop, and orop. |
*/ |
TYP *binop(ENODE **node, TYP *(*xfunc)(),int nt, int sy) |
{ |
ENODE *ep1, *ep2; |
TYP *tp1, *tp2; |
tp1 = (*xfunc)(&ep1); |
if( tp1 == 0 ) |
return 0; |
while( lastst == sy ) { |
NextToken(); |
tp2 = (*xfunc)(&ep2); |
if( tp2 == 0 ) |
error(ERR_IDEXPECT); |
else { |
tp1 = forcefit(&ep1,tp1,&ep2,tp2); |
ep1 = makenode(nt,ep1,ep2); |
PromoteConstFlag(ep1); |
} |
} |
*node = ep1; |
return tp1; |
} |
|
TYP *bitand(ENODE **node) |
/* |
* the bitwise and operator... |
*/ |
{ return binop(node,equalops,en_and,and); |
} |
|
TYP *bitxor(ENODE **node) |
{ return binop(node,bitand,en_xor,uparrow); |
} |
|
TYP *bitor(ENODE **node) |
{ return binop(node,bitxor,en_or,or); |
} |
|
TYP *andop(ENODE **node) |
{ return binop(node,bitor,en_land,land); |
} |
|
TYP *orop(ENODE **node) |
{ |
return binop(node,andop,en_lor,lor); |
} |
|
/* |
* this routine processes the hook operator. |
*/ |
TYP *conditional(ENODE **node) |
{ |
TYP *tp1, *tp2, *tp3; |
struct ENODE *ep1, *ep2, *ep3; |
tp1 = orop(&ep1); /* get condition */ |
if( tp1 == NULL ) |
return NULL; |
if( lastst == hook ) { |
NextToken(); |
if( (tp2 = conditional(&ep2)) == NULL) { |
error(ERR_IDEXPECT); |
goto cexit; |
} |
needpunc(colon); |
if( (tp3 = conditional(&ep3)) == NULL) { |
error(ERR_IDEXPECT); |
goto cexit; |
} |
tp1 = forcefit(&ep2,tp2,&ep3,tp3); |
ep2 = makenode(en_void,ep2,ep3); |
ep1 = makenode(en_cond,ep1,ep2); |
} |
cexit: *node = ep1; |
return tp1; |
} |
|
/* |
* asnop handles the assignment operators. currently only the |
* simple assignment is implemented. |
*/ |
TYP *asnop(ENODE **node) |
{ struct ENODE *ep1, *ep2, *ep3; |
TYP *tp1, *tp2; |
int op; |
tp1 = conditional(&ep1); |
if( tp1 == 0 ) |
return 0; |
for(;;) { |
switch( lastst ) { |
case assign: |
op = en_assign; |
ascomm: NextToken(); |
tp2 = asnop(&ep2); |
ascomm2: if( tp2 == 0 || !IsLValue(ep1) ) |
error(ERR_LVALUE); |
else { |
tp1 = forcefit(&ep1,tp1,&ep2,tp2); |
ep1 = makenode(op,ep1,ep2); |
} |
break; |
case asplus: |
op = en_asadd; |
ascomm3: tp2 = asnop(&ep2); |
if( tp1->type == bt_pointer ) { |
ep3 = makeinode(en_icon,tp1->btp->size); |
ep2 = makenode(en_mul,ep2,ep3); |
} |
goto ascomm; |
case asminus: |
op = en_assub; |
goto ascomm3; |
case astimes: |
op = en_asmul; |
goto ascomm; |
case asdivide: |
op = en_asdiv; |
goto ascomm; |
case asmodop: |
op = en_asmod; |
goto ascomm; |
case aslshift: |
op = en_aslsh; |
goto ascomm; |
case asrshift: |
op = en_asrsh; |
goto ascomm; |
case asand: |
op = en_asand; |
goto ascomm; |
case asor: |
op = en_asor; |
goto ascomm; |
default: |
goto asexit; |
} |
} |
asexit: *node = ep1; |
return tp1; |
} |
|
/* |
* evaluate an expression where the comma operator is not legal. |
*/ |
TYP *NonCommaExpression(ENODE **node) |
{ |
TYP *tp; |
tp = asnop(node); |
if( tp == NULL ) |
*node = NULL; |
return tp; |
} |
|
/* |
* evaluate the comma operator. comma operators are kept as |
* void nodes. |
*/ |
TYP *commaop(ENODE **node) |
{ |
TYP *tp1; |
ENODE *ep1, *ep2; |
tp1 = asnop(&ep1); |
if( tp1 == NULL ) |
return NULL; |
if( lastst == comma ) { |
tp1 = commaop(&ep2); |
if( tp1 == NULL ) { |
error(ERR_IDEXPECT); |
goto coexit; |
} |
ep1 = makenode(en_void,ep1,ep2); |
} |
coexit: *node = ep1; |
return tp1; |
} |
|
/* |
* evaluate an expression where all operators are legal. |
*/ |
TYP *expression(ENODE **node) |
{ |
TYP *tp; |
tp = commaop(node); |
if( tp == NULL ) |
*node = NULL; |
return tp; |
} |
/Gen.h
0,0 → 1,57
/* |
* code generation structures and constants |
*/ |
|
#define F_REG 1 /* register direct mode allowed */ |
#define F_MEM 4 /* memory alterable modes allowed */ |
#define F_IMMED 8 /* immediate mode allowed */ |
#define F_ALT 7 /* alterable modes */ |
#define F_DALT 5 /* data alterable modes */ |
#define F_ALL 15 /* all modes allowed */ |
#define F_VOL 16 /* need volitile operand */ |
#define F_NOVALUE 32 /* dont need result value */ |
#define F_IMMED18 64 // 18-bit immediate constant |
|
/* addressing mode structure */ |
|
typedef struct amode { |
unsigned int mode : 4; |
unsigned int preg : 6; |
unsigned int sreg : 6; |
unsigned int tempflag : 1; |
int deep; /* stack depth on allocation */ |
struct enode *offset; |
} AMODE; |
|
/* output code structure */ |
|
struct ocode { |
struct ocode *fwd, *back; |
short opcode; |
short length; |
AMODE *oper1, *oper2, *oper3; |
}; |
|
enum e_op { |
op_move, op_add, op_addu, op_addi, op_sub, op_subi, op_mov, |
op_muls, op_mulsi, op_mulu, op_divs, op_divsi, op_divu, op_and, op_andi, |
op_or, op_ori, op_xor, op_xori, op_asr, op_shl, op_shr, op_shru, |
op_shli, op_shri, op_shrui, |
op_jmp, op_mului, op_mod, op_modu, |
op_tas, op_bmi, op_subu, op_lwr, op_swc, op_loop, op_iret, |
op_sext32,op_sext16,op_sext8, op_dw, op_cache, |
op_subui, op_addui, op_sei, |
op_sw, op_sh, op_sc, op_sb, |
op_call, op_jal, op_beqi, op_bnei, |
op_lw, op_lh, op_lc, op_lb, op_ret, op_sm, op_lm, |
op_rts, op_bra, op_bf, op_beq, op_bne, op_blt, op_ble, op_bgt, op_bge, |
op_bgtu, op_bgeu, op_bltu, op_bleu, op_bnr, |
op_bhi, op_bhs, op_blo, op_bls, op_tst, op_ext, op_lea, op_swap, |
op_neg, op_not, op_cmp, op_clr, op_link, op_unlk, op_label, op_ilabel, |
op_pea, op_cmpi, op_dc, op_asm, op_stop, op_empty }; |
|
enum e_am { |
am_reg, am_ind, am_ainc, am_adec, am_indx, am_indx2, |
am_direct, am_immed, am_mask, am_none, am_indx3 |
}; |
|
/NextToken.c
0,0 → 1,570
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
extern char *errtext(int); |
|
int errno[80]; |
int numerrs; |
char inpline[132]; |
int total_errors = 0; |
char *lptr; /* shared with preproc */ |
FILE *inclfile[10]; /* shared with preproc */ |
int inclline[10]; /* shared with preproc */ |
int incldepth; /* shared with preproc */ |
char *linstack[20]; /* stack for substitutions */ |
char chstack[20]; /* place to save lastch */ |
int lstackptr = 0; /* substitution stack pointer */ |
|
int isalnum(char c) |
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || |
(c >= '0' && c <= '9'); |
} |
|
int isidch(char c) { return isalnum(c) || c == '_' || c == '$'; } |
int isspace(char c) { return c == ' ' || c == '\t' || c == '\n'; } |
int isdigit(char c) { return (c >= '0' && c <= '9'); } |
|
void initsym() |
{ |
lptr = inpline; |
inpline[0] = 0; |
numerrs = 0; |
total_errors = 0; |
lineno = 0; |
} |
|
int getline(int listflag) |
{ |
int rv; |
|
if(lineno > 0 && listflag) { |
fprintf(list,"%6d\t%s",lineno,inpline); |
while(numerrs--) |
fprintf(list," *** error %d: %s\n",errno[numerrs],errtext(errno[numerrs])); |
numerrs = 0; |
} |
++lineno; |
rv = (fgets(inpline,131,input) == NULL); |
if( rv && incldepth > 0 ) { |
fclose(input); |
input = inclfile[--incldepth]; |
lineno = inclline[incldepth]; |
return getline(0); |
} |
if( rv ) |
return 1; |
lptr = inpline; |
if(inpline[0] == '#') |
return preprocess(); |
return 0; |
} |
|
/* |
* getch - basic get character routine. |
*/ |
int getch() |
{ |
while( (lastch = *lptr++) == '\0') { |
if( lstackptr > 0 ) { |
lptr = linstack[--lstackptr]; |
lastch = chstack[lstackptr]; |
return lastch; |
} |
if(getline(incldepth == 0)) |
return lastch = -1; |
} |
return lastch; |
} |
|
/* |
* getid - get an identifier. |
* |
* identifiers are any isidch conglomerate |
* that doesn't start with a numeric character. |
* this set INCLUDES keywords. |
*/ |
void getid() |
{ |
register int i; |
i = 0; |
while(isidch(lastch)) { |
if(i < 32) |
lastid[i++] = lastch; |
getch(); |
} |
lastid[i] = '\0'; |
lastst = id; |
} |
|
/* |
* getsch - get a character in a quoted string. |
* |
* this routine handles all of the escape mechanisms |
* for characters in strings and character constants. |
*/ |
int getsch() /* return an in-quote character */ |
{ register int i, j; |
if(lastch == '\n') |
return -1; |
if(lastch != '\\') { |
i = lastch; |
getch(); |
return i; |
} |
getch(); /* get an escaped character */ |
if(isdigit(lastch)) { |
i = 0; |
for(j = i = 0;j < 3;++j) { |
if(lastch <= '7' && lastch >= '0') |
i = (i << 3) + lastch - '0'; |
else |
break; |
getch(); |
} |
return i; |
} |
i = lastch; |
getch(); |
switch(i) { |
case '\n': |
getch(); |
return getsch(); |
case 'b': |
return '\b'; |
case 'f': |
return '\f'; |
case 'n': |
return '\n'; |
case 'r': |
return '\r'; |
case 't': |
return '\t'; |
default: |
return i; |
} |
} |
|
__int64 radix36(char c) |
{ |
if(isdigit(c)) |
return c - '0'; |
if(c >= 'a' && c <= 'z') |
return c - 'a' + 10; |
if(c >= 'A' && c <= 'Z') |
return c - 'A' + 10; |
return -1; |
} |
|
/* |
* getbase - get an integer in any base. |
*/ |
void getbase(b) |
{ register __int64 i, j; |
i = 0; |
while(isalnum(lastch)) { |
if((j = radix36(lastch)) < b) { |
i = i * b + j; |
getch(); |
} |
else break; |
} |
if (lastch=='L') // ignore a 'L'ong suffix |
getch(); |
ival = i; |
lastst = iconst; |
} |
|
/* |
* getfrac - get fraction part of a floating number. |
*/ |
void getfrac() |
{ |
double frmul; |
frmul = 0.1; |
while(isdigit(lastch)) { |
rval += frmul * (lastch - '0'); |
getch(); |
frmul *= 0.1; |
} |
} |
|
/* |
* getexp - get exponent part of floating number. |
* |
* this algorithm is primative but usefull. Floating |
* exponents are limited to +/-255 but most hardware |
* won't support more anyway. |
*/ |
getexp() |
{ double expo, exmul; |
expo = 1.0; |
if(lastst != rconst) |
rval = ival; |
if(lastch == '-') { |
exmul = 0.1; |
getch(); |
} |
else |
exmul = 10.0; |
getbase(10); |
if(ival > 255) |
error(ERR_FPCON); |
else |
while(ival--) |
expo *= exmul; |
rval *= expo; |
} |
|
/* |
* getnum - get a number from input. |
* |
* getnum handles all of the numeric input. it accepts |
* decimal, octal, hexidecimal, and floating point numbers. |
*/ |
getnum() |
{ register int i; |
i = 0; |
if(lastch == '0') { |
getch(); |
if(lastch == 'x' || lastch == 'X') { |
getch(); |
getbase(16); |
} |
else getbase(8); |
} |
else { |
getbase(10); |
if(lastch == '.') { |
getch(); |
rval = ival; /* float the integer part */ |
getfrac(); /* add the fractional part */ |
lastst = rconst; |
} |
if(lastch == 'e' || lastch == 'E') { |
getch(); |
getexp(); /* get the exponent */ |
} |
} |
} |
|
void SkipSpaces() |
{ |
while( isspace(lastch) ) |
getch(); |
} |
/* |
* NextToken - get next symbol from input stream. |
* |
* NextToken is the basic lexical analyzer. It builds |
* basic tokens out of the characters on the input |
* stream and sets the following global variables: |
* |
* lastch: A look behind buffer. |
* lastst: type of last symbol read. |
* laststr: last string constant read. |
* lastid: last identifier read. |
* ival: last integer constant read. |
* rval: last real constant read. |
* |
* NextToken should be called for all your input needs... |
*/ |
void NextToken() |
{ register int i, j; |
SYM *sp; |
restart: /* we come back here after comments */ |
SkipSpaces(); |
if( lastch == -1) |
lastst = eof; |
else if(isdigit(lastch)) |
getnum(); |
else if(isidch(lastch)) { |
getid(); |
if( (sp = search(lastid,&defsyms)) != NULL ) { |
linstack[lstackptr] = lptr; |
chstack[lstackptr++] = lastch; |
lptr = sp->value.s; |
getch(); |
goto restart; |
} |
} |
else switch(lastch) { |
case '+': |
getch(); |
if(lastch == '+') { |
getch(); |
lastst = autoinc; |
} |
else if(lastch == '=') { |
getch(); |
lastst = asplus; |
} |
else lastst = plus; |
break; |
case '-': |
getch(); |
if(lastch == '-') { |
getch(); |
lastst = autodec; |
} |
else if(lastch == '=') { |
getch(); |
lastst = asminus; |
} |
else if(lastch == '>') { |
getch(); |
lastst = pointsto; |
} |
else lastst = minus; |
break; |
case '*': |
getch(); |
if(lastch == '=') { |
getch(); |
lastst = astimes; |
} |
else lastst = star; |
break; |
case '/': |
getch(); |
if(lastch == '=') { |
getch(); |
lastst = asdivide; |
} |
else if(lastch == '*') { |
getch(); |
for(;;) { |
if(lastch == '*') { |
getch(); |
if(lastch == '/') { |
getch(); |
goto restart; |
} |
} |
else |
getch(); |
} |
} |
else if (lastch == '/') { |
for(;;) { |
getch(); |
if (lastch=='\n') { |
getch(); |
goto restart; |
} |
} |
} |
else lastst = divide; |
break; |
case '^': |
getch(); |
lastst = uparrow; |
break; |
case ';': |
getch(); |
lastst = semicolon; |
break; |
case ':': |
getch(); |
lastst = colon; |
break; |
case '=': |
getch(); |
if(lastch == '=') { |
getch(); |
lastst = eq; |
} |
else lastst = assign; |
break; |
case '>': |
getch(); |
if(lastch == '=') { |
getch(); |
lastst = geq; |
} |
else if(lastch == '>') { |
getch(); |
if(lastch == '=') { |
getch(); |
lastst = asrshift; |
} |
else lastst = rshift; |
} |
else lastst = gt; |
break; |
case '<': |
getch(); |
if(lastch == '=') { |
getch(); |
lastst = leq; |
} |
else if(lastch == '<') { |
getch(); |
if(lastch == '=') { |
getch(); |
lastst = aslshift; |
} |
else lastst = lshift; |
} |
else if (lastch == '>') { |
getch(); |
lastst = neq; |
} |
else lastst = lt; |
break; |
case '\'': |
getch(); |
ival = getsch(); /* get a string char */ |
if(lastch != '\'') |
error(ERR_SYNTAX); |
else |
getch(); |
lastst = iconst; |
break; |
case '\"': |
getch(); |
for(i = 0;i < MAX_STRLEN;++i) { |
if(lastch == '\"') |
break; |
if((j = getsch()) == -1) |
break; |
else |
laststr[i] = j; |
} |
laststr[i] = 0; |
lastst = sconst; |
if(lastch != '\"') |
error(ERR_SYNTAX); |
else |
getch(); |
break; |
case '!': |
getch(); |
if(lastch == '=') { |
getch(); |
lastst = neq; |
} |
else lastst = not; |
break; |
case '%': |
getch(); |
if(lastch == '=') { |
getch(); |
lastst = asmodop; |
} |
else lastst = modop; |
break; |
case '~': |
getch(); |
lastst = compl; |
break; |
case '.': |
getch(); |
lastst = dot; |
if (lastch=='.') { |
getch(); |
if (lastch=='.') |
getch(); |
lastst = ellipsis; |
} |
break; |
case ',': |
getch(); |
lastst = comma; |
break; |
case '&': |
getch(); |
if( lastch == '&') { |
lastst = land; |
getch(); |
} |
else if( lastch == '=') { |
lastst = asand; |
getch(); |
} |
else |
lastst = and; |
break; |
case '|': |
getch(); |
if(lastch == '|') { |
lastst = lor; |
getch(); |
} |
else if( lastch == '=') { |
lastst = asor; |
getch(); |
} |
else |
lastst = or; |
break; |
case '(': |
getch(); |
lastst = openpa; |
break; |
case ')': |
getch(); |
lastst = closepa; |
break; |
case '[': |
getch(); |
lastst = openbr; |
break; |
case ']': |
getch(); |
lastst = closebr; |
break; |
case '{': |
getch(); |
lastst = begin; |
break; |
case '}': |
getch(); |
lastst = end; |
break; |
case '?': |
getch(); |
lastst = hook; |
break; |
default: |
getch(); |
error(ERR_ILLCHAR); |
goto restart; /* get a real token */ |
} |
if(lastst == id) |
IdentifyKeyword(); |
} |
|
void needpunc(enum e_sym p) |
{ |
if( lastst == p) |
NextToken(); |
else |
error(ERR_PUNCT); |
} |
|
|
/GenerateStatement.c
0,0 → 1,748
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
int breaklab; |
int contlab; |
int retlab; |
int throwlab; |
|
int lastsph; |
char *semaphores[20]; |
|
extern TYP stdfunc; |
|
|
int bitsset(int mask) |
{ |
int nn,bs=0; |
for (nn =0; nn < 32; nn++) |
if (mask & (1 << nn)) bs++; |
return bs; |
} |
|
AMODE *makereg(int r) |
{ |
AMODE *ap; |
ap = allocAmode(); |
ap->mode = am_reg; |
ap->preg = r; |
return ap; |
} |
|
/* |
* generate the mask address structure. |
*/ |
AMODE *make_mask(int mask) |
{ |
AMODE *ap; |
ap = allocAmode(); |
ap->mode = am_mask; |
ap->offset = mask; |
return ap; |
} |
|
/* |
* make a direct reference to an immediate value. |
*/ |
AMODE *make_direct(__int64 i) |
{ |
return make_offset(makeinode(en_icon,i,0)); |
} |
|
/* |
* generate a direct reference to a string label. |
*/ |
AMODE *make_strlab(char *s) |
{ |
AMODE *ap; |
ap = allocAmode(); |
ap->mode = am_direct; |
ap->offset = makesnode(en_nacon,s); |
return ap; |
} |
|
/* |
* generate code to evaluate a while statement. |
*/ |
void GenerateWhile(struct snode *stmt) |
{ |
int lab1, lab2; |
|
initstack(); /* initialize temp registers */ |
lab1 = contlab; /* save old continue label */ |
lab2 = breaklab; /* save old break label */ |
contlab = nextlabel++; /* new continue label */ |
GenerateLabel(contlab); |
if( stmt->s1 != NULL ) /* has block */ |
{ |
breaklab = nextlabel++; |
initstack(); |
GenerateFalseJump(stmt->exp,breaklab); |
GenerateStatement(stmt->s1); |
GenerateDiadic(op_bra,0,make_label(contlab),NULL); |
GenerateLabel(breaklab); |
breaklab = lab2; /* restore old break label */ |
} |
else /* no loop code */ |
{ |
initstack(); |
GenerateTrueJump(stmt->exp,contlab); |
} |
contlab = lab1; /* restore old continue label */ |
} |
|
/* |
* generate code to evaluate an until statement. |
*/ |
void GenerateUntil(Statement *stmt) |
{ |
int lab1, lab2; |
|
initstack(); /* initialize temp registers */ |
lab1 = contlab; /* save old continue label */ |
lab2 = breaklab; /* save old break label */ |
contlab = nextlabel++; /* new continue label */ |
GenerateLabel(contlab); |
if( stmt->s1 != NULL ) /* has block */ |
{ |
breaklab = nextlabel++; |
initstack(); |
GenerateTrueJump(stmt->exp,breaklab); |
GenerateStatement(stmt->s1); |
GenerateDiadic(op_bra,0,make_label(contlab),NULL); |
GenerateLabel(breaklab); |
breaklab = lab2; /* restore old break label */ |
} |
else /* no loop code */ |
{ |
initstack(); |
GenerateFalseJump(stmt->exp,contlab); |
} |
contlab = lab1; /* restore old continue label */ |
} |
|
|
// generate code to evaluate a for loop |
// |
void GenerateFor(struct snode *stmt) |
{ |
int old_break, old_cont, exit_label, loop_label; |
old_break = breaklab; |
old_cont = contlab; |
loop_label = nextlabel++; |
exit_label = nextlabel++; |
contlab = loop_label; |
initstack(); |
if( stmt->initExpr != NULL ) |
GenerateExpression(stmt->initExpr,F_ALL | F_NOVALUE |
,GetNaturalSize(stmt->initExpr)); |
GenerateLabel(loop_label); |
initstack(); |
if( stmt->exp != NULL ) |
GenerateFalseJump(stmt->exp,exit_label); |
if( stmt->s1 != NULL ) |
{ |
breaklab = exit_label; |
GenerateStatement(stmt->s1); |
} |
initstack(); |
if( stmt->incrExpr != NULL ) |
GenerateExpression(stmt->incrExpr,F_ALL | F_NOVALUE,GetNaturalSize(stmt->incrExpr)); |
GenerateTriadic(op_bra,0,make_label(loop_label),NULL,NULL); |
breaklab = old_break; |
contlab = old_cont; |
GenerateLabel(exit_label); |
} |
|
|
// generate code to evaluate a forever loop |
// |
void GenerateForever(Statement *stmt) |
{ |
int old_break, old_cont, exit_label, loop_label; |
old_break = breaklab; |
old_cont = contlab; |
loop_label = nextlabel++; |
exit_label = nextlabel++; |
contlab = loop_label; |
GenerateLabel(loop_label); |
if( stmt->s1 != NULL ) |
{ |
breaklab = exit_label; |
GenerateStatement(stmt->s1); |
} |
GenerateDiadic(op_bra,0,make_label(loop_label),NULL); |
breaklab = old_break; |
contlab = old_cont; |
GenerateLabel(exit_label); |
} |
|
/* |
* generate code to evaluate an if statement. |
*/ |
void GenerateIf(struct snode *stmt) |
{ int lab1, lab2, oldbreak; |
lab1 = nextlabel++; /* else label */ |
lab2 = nextlabel++; /* exit label */ |
oldbreak = breaklab; /* save break label */ |
initstack(); /* clear temps */ |
GenerateFalseJump(stmt->exp,lab1); |
if( stmt->s1 != 0 && stmt->s1->next != 0 ) |
if( stmt->s2 != 0 ) |
breaklab = lab2; |
else |
breaklab = lab1; |
GenerateStatement(stmt->s1); |
if( stmt->s2 != 0 ) /* else part exists */ |
{ |
GenerateDiadic(op_bra,0,make_label(lab2),0); |
GenerateLabel(lab1); |
if( stmt->s2 == 0 || stmt->s2->next == 0 ) |
breaklab = oldbreak; |
else |
breaklab = lab2; |
GenerateStatement(stmt->s2); |
GenerateLabel(lab2); |
} |
else /* no else code */ |
GenerateLabel(lab1); |
breaklab = oldbreak; |
} |
|
/* |
* generate code for a do - while loop. |
*/ |
void GenerateDo(struct snode *stmt) |
{ |
int oldcont, oldbreak; |
oldcont = contlab; |
oldbreak = breaklab; |
contlab = nextlabel++; |
GenerateLabel(contlab); |
if( stmt->s1 != 0 && stmt->s1->next != 0 ) |
{ |
breaklab = nextlabel++; |
GenerateStatement(stmt->s1); /* generate body */ |
initstack(); |
GenerateTrueJump(stmt->exp,contlab); |
GenerateLabel(breaklab); |
} |
else |
{ |
GenerateStatement(stmt->s1); |
initstack(); |
GenerateTrueJump(stmt->exp,contlab); |
} |
breaklab = oldbreak; |
contlab = oldcont; |
} |
|
/* |
* generate code for a do - while loop. |
*/ |
void GenerateDoUntil(struct snode *stmt) |
{ |
int oldcont, oldbreak; |
oldcont = contlab; |
oldbreak = breaklab; |
contlab = nextlabel++; |
GenerateLabel(contlab); |
if( stmt->s1 != 0 && stmt->s1->next != 0 ) |
{ |
breaklab = nextlabel++; |
GenerateStatement(stmt->s1); /* generate body */ |
initstack(); |
GenerateFalseJump(stmt->exp,contlab); |
GenerateLabel(breaklab); |
} |
else |
{ |
GenerateStatement(stmt->s1); |
initstack(); |
GenerateFalseJump(stmt->exp,contlab); |
} |
breaklab = oldbreak; |
contlab = oldcont; |
} |
|
/* |
* generate a call to a library routine. |
*/ |
void call_library(char *lib_name) |
{ |
SYM *sp; |
sp = gsearch(lib_name); |
if( sp == NULL ) |
{ |
++global_flag; |
sp = allocSYM(); |
sp->tp = &stdfunc; |
sp->name = lib_name; |
sp->storage_class = sc_external; |
insert(sp,&gsyms); |
--global_flag; |
} |
GenerateDiadic(op_call,0,make_strlab(lib_name),NULL); |
} |
|
/* |
* generate a linear search switch statement. |
*/ |
void GenerateSwitch(Statement *stmt) |
{ |
int curlab; |
int *bf; |
int nn; |
struct snode *defcase; |
struct amode *ap; |
curlab = nextlabel++; |
defcase = 0; |
initstack(); |
ap = GenerateExpression(stmt->exp,F_REG,4); |
if( ap->preg != 0 ) |
GenerateTriadic(op_or,0,makereg(1),ap,makereg(0)); |
stmt = stmt->s1; |
while( stmt != NULL ) |
{ |
if( stmt->s2 ) /* default case ? */ |
{ |
stmt->label = curlab; |
defcase = stmt; |
} |
else |
{ |
bf = stmt->label; |
for (nn = bf[0]; nn >= 1; nn--) |
GenerateTriadic(op_beq,0,makereg(1),make_immed(bf[nn]),make_label(curlab)); |
//GenerateDiadic(op_dw,0,make_label(curlab), make_direct(stmt->label)); |
stmt->label = curlab; |
} |
if( stmt->s1 != NULL && stmt->next != NULL ) |
curlab = nextlabel++; |
stmt = stmt->next; |
} |
if( defcase == NULL ) |
GenerateTriadic(op_bra,0,make_label(breaklab),NULL,NULL); |
else |
GenerateTriadic(op_bra,0,make_label(defcase->label),NULL,NULL); |
} |
|
|
// generate all cases for a switch statement. |
// |
void GenerateCase(Statement *stmt) |
{ |
while( stmt != NULL ) |
{ |
if( stmt->s1 != NULL ) |
{ |
GenerateLabel(stmt->label); |
GenerateStatement(stmt->s1); |
} |
else if( stmt->next == NULL ) |
GenerateLabel(stmt->label); |
stmt = stmt->next; |
} |
} |
|
/* |
* analyze and generate best switch statement. |
*/ |
genxswitch(Statement *stmt) |
{ |
int oldbreak; |
oldbreak = breaklab; |
breaklab = nextlabel++; |
GenerateSwitch(stmt); |
GenerateCase(stmt->s1); |
GenerateLabel(breaklab); |
breaklab = oldbreak; |
} |
|
int popcnt(int m) |
{ |
int n; |
int cnt; |
|
cnt =0; |
for (n = 0; n < 32; n = n + 1) |
if (m & (1 << n)) cnt = cnt + 1; |
return cnt; |
} |
/* |
void gen_regsave() |
{ |
int lab1; |
|
lab1 = nextlabel++; |
GenerateLabel(lab1); |
GenerateDiadic(op_tas,1,make_strlab("sfRunningTCB"),NULL); |
GenerateDiadic(op_bmi,0,make_label(lab1),NULL); |
GenerateDiadic(op_move,0,makereg(1),make_strlab("a0save")); |
GenerateDiadic(op_move,0,make_strlab("RunningTCB"),makereg(1)); |
GenerateDiadic(op_movem,0,make_strlab("d0-d7/a0-a7"),make_strlab("(a0)")); |
GenerateDiadic(op_move,0,make_strlab("a0save"),make_strlab("32(a0)")); |
GenerateDiadic(op_move,0,make_strlab("usp"),makereg(1)); |
GenerateDiadic(op_move,0,makereg(1),make_strlab("64(a0)")); |
GenerateDiadic(op_move,0,make_strlab("4(a7)"),make_strlab("68(a0)")); |
|
//GenerateDiadic(op_move,4,make_string("sr"),make_string("_TCBsrsave")); |
//GenerateDiadic(op_movem,4,make_mask(0xFFFF),make_string("_TCBregsave")); |
//GenerateDiadic(op_move,4,make_string("usp"),make_string("a0")); |
//GenerateDiadic(op_move,4,make_string("a0"),make_string("_TCBuspsave")); |
} |
|
void gen_regrestore() |
{ |
GenerateDiadic(op_move,0,make_strlab("_TCBuspsave"),make_string("a0")); |
GenerateDiadic(op_move,0,make_string("a0"),make_string("usp")); |
GenerateDiadic(op_movem,0,make_string("_TCBregsave"),make_mask(0xFFFF)); |
GenerateDiadic(op_move,0,make_string("_TCBsrsave"),make_string("sr")); |
} |
*/ |
/* |
void gen_vortex(struct snode *stmt) |
{ |
int lab1; |
|
lab1 = nextlabel++; |
GenerateDiadic(op_bra,0,make_label(lab1),0); |
//gen_ilabel(stmt->label); |
gen_regsave(); |
GenerateStatement(stmt->s1); |
gen_regrestore(); |
GenerateDiadic(op_rte,0,0,0); |
GenerateLabel(lab1); |
} |
*/ |
|
void GenerateTry(Statement *stmt) |
{ |
int lab1,curlab; |
int oldthrow; |
char buf[20]; |
AMODE *ap; |
SYM *sym; |
|
lab1 = nextlabel++; |
oldthrow = throwlab; |
throwlab = nextlabel++; |
|
GenerateDiadic(op_lea,0,makereg(28),make_label(throwlab)); |
GenerateStatement(stmt->s1); |
GenerateDiadic(op_bra,0,make_label(lab1),NULL); |
GenerateLabel(throwlab); |
stmt = stmt->s2; |
while (stmt) { |
throwlab = oldthrow; |
curlab = nextlabel++; |
GenerateLabel(curlab); |
if (stmt->s2==99999) |
; |
else |
GenerateTriadic(op_bnei,0,makereg(2),make_immed((int)stmt->s2),make_label(nextlabel)); |
// move the throw expression result in 'r1' into the catch variable. |
sym = (SYM *)stmt->label; |
if (sym) { |
switch(sym->tp->size) { |
case 1: GenerateDiadic(op_sb,0,makereg(1),make_indexed(sym->value.i,27)); |
case 2: GenerateDiadic(op_sc,0,makereg(1),make_indexed(sym->value.i,27)); |
case 4: GenerateDiadic(op_sh,0,makereg(1),make_indexed(sym->value.i,27)); |
case 8: GenerateDiadic(op_sw,0,makereg(1),make_indexed(sym->value.i,27)); |
} |
} |
GenerateStatement(stmt->s1); |
stmt=stmt->next; |
} |
GenerateLabel(lab1); |
GenerateDiadic(op_lea,0,makereg(28),make_label(oldthrow)); |
} |
|
void GenerateThrow(Statement *stmt) |
{ |
AMODE *ap; |
|
if( stmt != NULL && stmt->exp != NULL ) |
{ |
initstack(); |
ap = GenerateExpression(stmt->exp,F_ALL,8); |
if (ap->mode==am_immed) |
GenerateTriadic(op_ori,0,makereg(1),makereg(0),ap); |
else if( ap->mode != am_reg) |
GenerateDiadic(op_lw,0,makereg(1),ap); |
else if (ap->preg != 1 ) |
GenerateTriadic(op_or,0,makereg(1),ap,makereg(0)); |
ReleaseTempRegister(ap); |
GenerateTriadic(op_ori,0,makereg(2),makereg(0),make_immed((int)stmt->label)); |
} |
GenerateDiadic(op_bra,0,make_label(throwlab),NULL); |
} |
/* |
void GenerateCritical(struct snode *stmt) |
{ |
int lab1; |
|
lab1 = nextlabel++; |
semaphores[lastsph] = stmt->label; |
lastsph++; |
GenerateLabel(lab1); |
GenerateDiadic(op_tas,0,make_string(stmt->label),NULL); |
GenerateDiadic(op_bmi,0,make_label(lab1),NULL); |
GenerateStatement(stmt->s1); |
--lastsph; |
semaphores[lastsph] = NULL; |
GenerateDiadic(op_move,0,make_immed(0),make_string(stmt->label)); |
} |
*/ |
|
void GenerateSpinlock(Statement *stmt) |
{ |
int lab1, lab2, lab3, lab4; |
AMODE *ap1, *ap2; |
|
lab1 = nextlabel++; |
ap1 = GetTempRegister(); |
ap2 = GetTempRegister(); |
if (stmt->exp) { |
lab2 = nextlabel++; |
GenerateTriadic(op_ori,0,ap2,makereg(0),make_immed(stmt->exp)); |
GenerateLabel(lab1); |
GenerateTriadic(op_beq,0,ap2,makereg(0),make_label(lab2)); |
GenerateTriadic(op_subui,0,ap2,ap2,make_immed(1)); |
GenerateTriadic(op_lwr,0,ap1,make_string(stmt->label),NULL); |
GenerateTriadic(op_bne,0,ap1,makereg(0),make_label(lab1),NULL); |
GenerateTriadic(op_not,0,ap1,ap1,NULL); |
GenerateTriadic(op_swc,0,ap1,make_string(stmt->label),NULL); |
GenerateTriadic(op_bnr,0,make_label(lab1),NULL,NULL); |
} |
else { |
GenerateLabel(lab1); |
GenerateTriadic(op_lwr,0,ap1,make_string(stmt->label),NULL); |
GenerateTriadic(op_bne,0,ap1,makereg(0),make_label(lab1),NULL); |
GenerateTriadic(op_not,0,ap1,ap1,NULL); |
GenerateTriadic(op_swc,0,ap1,make_string(stmt->label),NULL); |
GenerateTriadic(op_bnr,0,make_label(lab1),NULL,NULL); |
} |
ReleaseTempRegister(ap1); |
ReleaseTempRegister(ap2); |
GenerateStatement(stmt->s1); |
GenerateDiadic(op_sb,0,makereg(0),make_string(stmt->label)); |
if (stmt->exp) { |
lab3 = nextlabel++; |
GenerateTriadic(op_bra,0,make_label(lab3),NULL,NULL); |
GenerateLabel(lab2); |
GenerateStatement(stmt->s2); |
GenerateLabel(lab3); |
} |
else { |
printf("Warning: The lockfail code is unreachable because spinlock tries are infinite.\r\n"); |
} |
} |
|
void GenerateSpinUnlock(struct snode *stmt) |
{ |
GenerateDiadic(op_sb,0,makereg(0),make_string(stmt->label)); |
} |
/* |
* genstmt will generate a statement and follow the next pointer |
* until the block is generated. |
*/ |
void GenerateStatement(struct snode *stmt) |
{ |
while( stmt != NULL ) |
{ |
switch( stmt->stype ) |
{ |
//case st_vortex: |
// gen_vortex(stmt); |
// break; |
case st_try: |
GenerateTry(stmt); |
break; |
case st_throw: |
GenerateThrow(stmt); |
break; |
case st_intoff: |
GenerateIntoff(stmt); |
break; |
case st_stop: |
GenerateStop(stmt); |
break; |
case st_inton: |
GenerateInton(stmt); |
break; |
case st_asm: |
GenerateAsm(stmt); |
break; |
case st_label: |
GenerateLabel(stmt->label); |
break; |
case st_goto: |
GenerateDiadic(op_bra,0,make_label(stmt->label),0); |
break; |
//case st_critical: |
// GenerateCritical(stmt); |
// break; |
case st_spinlock: |
GenerateSpinlock(stmt); |
break; |
case st_spinunlock: |
GenerateSpinUnlock(stmt); |
break; |
case st_expr: |
initstack(); |
GenerateExpression(stmt->exp,F_ALL | F_NOVALUE, |
GetNaturalSize(stmt->exp)); |
break; |
case st_return: |
GenerateReturn(currentFn,stmt); |
break; |
case st_if: |
GenerateIf(stmt); |
break; |
case st_do: |
GenerateDo(stmt); |
break; |
case st_dountil: |
GenerateDoUntil(stmt); |
break; |
case st_doloop: |
GenerateForever(stmt); |
break; |
case st_while: |
GenerateWhile(stmt); |
break; |
case st_until: |
GenerateUntil(stmt); |
break; |
case st_for: |
GenerateFor(stmt); |
break; |
case st_forever: |
GenerateForever(stmt); |
break; |
case st_firstcall: |
GenerateFirstcall(stmt); |
break; |
case st_continue: |
GenerateDiadic(op_bra,0,make_label(contlab),0); |
break; |
case st_break: |
GenerateDiadic(op_bra,0,make_label(breaklab),0); |
break; |
case st_switch: |
genxswitch(stmt); |
break; |
default: |
printf("DIAG - unknown statement.\n"); |
break; |
} |
stmt = stmt->next; |
} |
} |
|
void GenerateIntoff(Statement *stmt) |
{ |
// GenerateDiadic(op_move,0,make_string("sr"),make_string("_TCBsrsave")); |
GenerateDiadic(op_sei,0,NULL,NULL); |
} |
|
void GenerateInton(Statement *stmt) |
{ |
// GenerateDiadic(op_move,0,make_string("_TCBsrsave"),make_string("sr")); |
} |
|
void GenerateStop(Statement *stmt) |
{ |
GenerateDiadic(op_stop,0,make_immed(0),NULL); |
} |
|
void GenerateAsm(Statement *stmt) |
{ |
GenerateTriadic(op_asm,0,make_string(stmt->label),NULL,NULL); |
} |
|
void GenerateFirstcall(Statement *stmt) |
{ |
int lab1, lab2, lab3,lab4,lab5,lab6,lab7; |
char buf[20]; |
AMODE *ap1,*ap2; |
|
lab1 = contlab; /* save old continue label */ |
lab2 = breaklab; /* save old break label */ |
contlab = nextlabel++; /* new continue label */ |
lab3 = nextlabel++; |
lab4 = nextlabel++; |
lab5 = nextlabel++; |
lab6 = nextlabel++; |
lab7 = nextlabel++; |
if( stmt->s1 != NULL ) /* has block */ |
{ |
breaklab = nextlabel++; |
GenerateLabel(lab3); // marks address of brf |
GenerateDiadic(op_bra,0,make_label(lab7),NULL); // branch to the firstcall statement |
GenerateLabel(lab6); // prevent optimizer from optimizing move away |
GenerateDiadic(op_bra,0,make_label(breaklab),NULL); // then branch around it |
GenerateLabel(lab7); // prevent optimizer from optimizing move away |
ap1 = GetTempRegister(); |
ap2 = GetTempRegister(); |
GenerateDiadic(op_lea,0,ap2,make_label(lab3)); |
GenerateTriadic(op_andi,0,ap2,ap2,make_immed(0x0c)); |
GenerateTriadic(op_beqi,0,ap2,make_immed(0x08L),make_label(lab4)); |
GenerateTriadic(op_beqi,0,ap2,make_immed(0x04L),make_label(lab5)); |
GenerateDiadic(op_lea,0,ap2,make_label(lab3)); |
GenerateDiadic(op_lw,0,ap1,make_indirect(ap2->preg)); |
GenerateTriadic(op_andi,0,ap1,ap1,make_immed(0xFFFFFC0000000000L)); |
GenerateTriadic(op_ori,0,ap1,ap1,make_immed(0x000037800000000L)); // nop instruction |
GenerateDiadic(op_sw,0,ap1,make_indirect(ap2->preg)); |
GenerateDiadic(op_cache,0,make_string("invil"),make_indirect(ap2->preg)); |
GenerateDiadic(op_bra,0,make_label(lab6),NULL); |
GenerateLabel(lab4); |
GenerateDiadic(op_lea,0,ap2,make_label(lab3)); |
GenerateDiadic(op_lw,0,ap1,make_indirect(ap2->preg)); |
GenerateTriadic(op_andi,0,ap1,ap1,make_immed(0x00000000000FFFFFL)); |
GenerateTriadic(op_ori,0,ap1,ap1,make_immed(0x3780000000000000L)); // nop instruction |
GenerateDiadic(op_sw,0,ap1,make_indirect(ap2->preg)); |
GenerateDiadic(op_cache,0,make_string("invil"),make_indirect(ap2->preg)); |
GenerateDiadic(op_bra,0,make_label(lab6),NULL); |
GenerateLabel(lab5); |
GenerateDiadic(op_lea,0,ap2,make_label(lab3)); |
GenerateDiadic(op_lw,0,ap1,make_indexed(4,ap2->preg)); |
GenerateTriadic(op_andi,0,ap1,ap1,make_immed(0xFFFFFFFFFFF00000L)); |
GenerateTriadic(op_ori,0,ap1,ap1,make_immed(0x00000000000DE000L)); // nop instruction |
GenerateDiadic(op_sw,0,ap1,make_indexed(4,ap2->preg)); |
GenerateDiadic(op_cache,0,make_string("invil"),make_indexed(4,ap2->preg)); |
GenerateLabel(lab6); |
GenerateStatement(stmt->s1); |
GenerateLabel(breaklab); |
breaklab = lab2; /* restore old break label */ |
} |
contlab = lab1; /* restore old continue label */ |
} |
/Peepgen.c
0,0 → 1,324
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
static void AddToPeepList(struct ocode *newc); |
void peep_add(struct ocode *ip); |
static void PeepoptSub(struct ocode *ip); |
void peep_move(struct ocode *ip); |
void peep_cmp(struct ocode *ip); |
void opt3(); |
void put_ocode(struct ocode *p); |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Copyright 2012 Robert Finch |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
struct ocode *peep_head = NULL, |
*peep_tail = NULL; |
|
AMODE *copy_addr(AMODE *ap) |
{ |
AMODE *newap; |
if( ap == NULL ) |
return NULL; |
newap = allocAmode(); |
memcpy(newap,ap,sizeof(AMODE)); |
return newap; |
} |
|
void GenerateMonadic(int op, int len, AMODE *ap1) |
{ |
struct ocode *cd; |
cd = (struct ocode *)xalloc(sizeof(struct ocode)); |
cd->opcode = op; |
cd->length = len; |
cd->oper1 = copy_addr(ap1); |
cd->oper2 = NULL; |
cd->oper3 = NULL; |
AddToPeepList(cd); |
} |
|
void GenerateDiadic(int op, int len, AMODE *ap1, AMODE *ap2) |
{ |
struct ocode *cd; |
cd = (struct ocode *)xalloc(sizeof(struct ocode)); |
cd->opcode = op; |
cd->length = len; |
cd->oper1 = copy_addr(ap1); |
cd->oper2 = copy_addr(ap2); |
cd->oper3 = NULL; |
AddToPeepList(cd); |
} |
|
void GenerateTriadic(int op, int len, AMODE *ap1, AMODE *ap2, AMODE *ap3) |
{ |
struct ocode *cd; |
cd = (struct ocode *)xalloc(sizeof(struct ocode)); |
cd->opcode = op; |
cd->length = len; |
cd->oper1 = copy_addr(ap1); |
cd->oper2 = copy_addr(ap2); |
cd->oper3 = copy_addr(ap3); |
AddToPeepList(cd); |
} |
|
static void AddToPeepList(struct ocode *cd) |
{ |
if( peep_head == NULL ) |
{ |
peep_head = peep_tail = cd; |
cd->fwd = NULL; |
cd->back = NULL; |
} |
else |
{ |
cd->fwd = NULL; |
cd->back = peep_tail; |
peep_tail->fwd = cd; |
peep_tail = cd; |
} |
} |
|
/* |
* add a compiler generated label to the peep list. |
*/ |
void GenerateLabel(int labno) |
{ |
struct ocode *newl; |
newl = (struct ocode *)xalloc(sizeof(struct ocode)); |
newl->opcode = op_label; |
newl->oper1 = (struct amode *)labno; |
AddToPeepList(newl); |
} |
|
//void gen_ilabel(char *name) |
//{ |
// struct ocode *new; |
// new = (struct ocode *)xalloc(sizeof(struct ocode)); |
// new->opcode = op_ilabel; |
// new->oper1 = (struct amode *)name; |
// add_peep(new); |
//} |
|
/* |
* output all code and labels in the peep list. |
*/ |
void flush_peep() |
{ |
if (optimize) |
opt3(); /* do the peephole optimizations */ |
while( peep_head != NULL ) |
{ |
if( peep_head->opcode == op_label ) |
put_label(peep_head->oper1); |
else |
put_ocode(peep_head); |
peep_head = peep_head->fwd; |
} |
} |
|
/* |
* output the instruction passed. |
*/ |
void put_ocode(struct ocode *p) |
{ |
put_code(p->opcode,p->length,p->oper1,p->oper2,p->oper3); |
} |
|
/* |
* peephole optimization for move instructions. |
* makes quick immediates when possible. |
* changes move #0,d to clr d. |
* changes long moves to address registers to short when |
* possible. |
* changes move immediate to stack to pea. |
*/ |
void peep_move(struct ocode *ip) |
{ |
return; |
} |
|
/* |
* compare two address nodes and return true if they are |
* equivalent. |
*/ |
int equal_address(AMODE *ap1, AMODE *ap2) |
{ |
if( ap1 == NULL || ap2 == NULL ) |
return FALSE; |
if( ap1->mode != ap2->mode ) |
return FALSE; |
switch( ap1->mode ) |
{ |
case am_reg: |
return ap1->preg == ap2->preg; |
} |
return FALSE; |
} |
|
/* |
* peephole optimization for add instructions. |
* makes quick immediates out of small constants. |
*/ |
void peep_add(struct ocode *ip) |
{ |
return; |
} |
|
// 'subui' followed by a 'bne' gets turned into 'loop' |
// |
static void PeepoptSub(struct ocode *ip) |
{ |
if (ip->opcode==op_subui) { |
if (ip->oper3) { |
if (ip->oper3->mode==am_immed) { |
if (ip->oper3->offset->nodetype==en_icon && ip->oper3->offset->i==1) { |
if (ip->fwd) { |
if (ip->fwd->opcode==op_bne && ip->fwd->oper2->mode==am_reg && ip->fwd->oper2->preg==0) { |
if (ip->fwd->oper1->preg==ip->oper1->preg) { |
ip->opcode = op_loop; |
ip->oper2 = ip->fwd->oper3; |
ip->oper3 = NULL; |
if (ip->fwd->back) ip->fwd->back = ip; |
ip->fwd = ip->fwd->fwd; |
return; |
} |
} |
} |
} |
} |
} |
} |
return; |
} |
|
/* |
* peephole optimization for compare instructions. |
*/ |
void peep_cmp(struct ocode *ip) |
{ |
return; |
} |
|
/* |
* changes multiplies and divides by convienient values |
* to shift operations. op should be either op_asl or |
* op_asr (for divide). |
*/ |
void PeepoptMuldiv(struct ocode *ip, int op) |
{ |
int shcnt; |
|
if( ip->oper1->mode != am_immed ) |
return; |
if( ip->oper1->offset->nodetype != en_icon ) |
return; |
|
shcnt = ip->oper1->offset->i; |
// remove multiply / divide by 1 |
// This shouldn't get through Optimize, but does sometimes. |
if (shcnt==1) { |
if (ip->back) |
ip->back->fwd = ip->fwd; |
if (ip->fwd) |
ip->fwd->back = ip->back; |
return; |
} |
/* vax c doesn't do this type of switch well */ |
if( shcnt == 2) shcnt = 1; |
else if( shcnt == 4) shcnt = 2; |
else if( shcnt == 8) shcnt = 3; |
else if( shcnt == 16) shcnt = 4; |
else if( shcnt == 32) shcnt = 5; |
else if( shcnt == 64) shcnt = 6; |
else if( shcnt == 128) shcnt = 7; |
else if( shcnt == 256) shcnt = 8; |
else if( shcnt == 512) shcnt = 9; |
else if( shcnt == 1024) shcnt = 10; |
else if( shcnt == 2048) shcnt = 11; |
else if( shcnt == 4096) shcnt = 12; |
else if( shcnt == 8192) shcnt = 13; |
else if( shcnt == 16384) shcnt = 14; |
else if( shcnt == 32768) shcnt = 15; |
else return; |
ip->oper1->offset->i = shcnt; |
ip->opcode = op; |
ip->length = 4; |
} |
|
// Optimize unconditional control flow transfers |
// Instructions that follow an unconditional transfer won't be executed |
// unless there is a label to branch to them. |
// |
void PeepoptUctran(struct ocode *ip) |
{ |
if (uctran_off) return; |
while( ip->fwd != NULL && ip->fwd->opcode != op_label) |
{ |
ip->fwd = ip->fwd->fwd; |
if( ip->fwd != NULL ) |
ip->fwd->back = ip; |
} |
} |
|
/* |
* peephole optimizer. This routine calls the instruction |
* specific optimization routines above for each instruction |
* in the peep list. |
*/ |
void opt3() |
{ |
struct ocode *ip; |
ip = peep_head; |
while( ip != NULL ) |
{ |
switch( ip->opcode ) |
{ |
case op_move: |
peep_move(ip); |
break; |
case op_add: |
peep_add(ip); |
break; |
case op_sub: |
PeepoptSub(ip); |
break; |
case op_cmp: |
peep_cmp(ip); |
break; |
case op_muls: |
PeepoptMuldiv(ip,op_shl); |
break; |
case op_bra: |
case op_jmp: |
case op_ret: |
case op_iret: |
PeepoptUctran(ip); |
} |
ip = ip->fwd; |
} |
} |
/Expr.h
0,0 → 1,68
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
|
/* expression tree descriptions */ |
|
enum e_node { |
en_void, /* used for parameter lists */ |
en_cbw, en_cbc, en_cbh, |
en_ccw, en_cch, en_chw, |
en_cwl, en_cld, en_cfd, |
en_icon, en_fcon, en_labcon, en_nacon, en_autocon, |
en_c_ref, en_uc_ref, en_h_ref, en_uh_ref, |
en_b_ref, en_w_ref, en_ub_ref, en_uw_ref, |
en_fcall, en_tempref, en_regvar, en_add, en_sub, en_mul, en_mod, |
en_div, en_shl, en_shr, en_shru, en_cond, en_assign, |
en_asadd, en_assub, en_asmul, en_asdiv, en_asmod, en_asrsh, en_asmulu, |
en_aslsh, en_asand, en_asor, en_asxor, en_uminus, en_not, en_compl, |
en_eq, en_ne, en_lt, en_le, en_gt, en_ge, |
en_and, en_or, en_land, en_lor, |
en_xor, en_ainc, en_adec, en_mulu, en_udiv, en_umod, en_ugt, |
en_uge, en_ule, en_ult, |
en_ref, en_ursh, |
en_uwfieldref,en_wfieldref,en_bfieldref,en_ubfieldref, |
en_uhfieldref,en_hfieldref,en_ucfieldref,en_cfieldref |
}; |
|
struct enode { |
enum e_node nodetype; |
enum e_bt etype; |
long esize; |
__int8 constflag; |
__int8 bit_width; |
__int8 bit_offset; |
// The following could be in a value union |
__int64 i; |
double f; |
char *sp; |
struct enode *p[2]; |
}; |
|
typedef struct enode ENODE; |
|
typedef struct cse { |
struct cse *next; |
struct enode *exp; /* optimizable expression */ |
int uses; /* number of uses */ |
int duses; /* number of dereferenced uses */ |
short int voidf; /* cannot optimize flag */ |
short int reg; /* AllocateRegisterVarsd register */ |
} CSE; |
|
|
|
/Preprocessor.c
0,0 → 1,156
#include <stdio.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Copyright 2012 Robert Finch |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
FILE *inclfile[10]; |
int incldepth = 0; |
int inclline[10]; |
char *lptr; |
extern char inpline[132]; |
int endifCount = 0; |
int dodefine(); |
int doinclude(); |
|
int preprocess() |
{ |
++lptr; |
lastch = ' '; |
NextToken(); /* get first word on line */ |
if( lastst != id ) { |
error(ERR_PREPROC); |
return getline(incldepth == 0); |
} |
if( strcmp(lastid,"include") == 0 ) |
return doinclude(); |
else if( strcmp(lastid,"define") == 0 ) |
return dodefine(); |
else if (strcmp(lastid,"ifdef")==0) |
return doifdef(); |
else if (strcmp(lastid,"ifndef")==0) |
return doifndef(); |
else if (strcmp(lastid,"endif")==0) |
return doendif(); |
else |
{ |
error(ERR_PREPROC); |
return getline(incldepth == 0); |
} |
} |
|
int doinclude() |
{ |
int rv; |
NextToken(); /* get file to include */ |
if( lastst != sconst ) { |
error(ERR_INCLFILE); |
return getline(incldepth == 0); |
} |
inclline[incldepth] = lineno; |
inclfile[incldepth++] = input; /* push current input file */ |
input = fopen(laststr,"r"); |
if( input == 0 ) { |
input = inclfile[--incldepth]; |
error(ERR_CANTOPEN); |
rv = getline(incldepth == 0); |
} |
else { |
rv = getline(incldepth == 1); |
lineno = -32768; /* dont list include files */ |
} |
return rv; |
} |
|
int dodefine() |
{ |
SYM *sp; |
NextToken(); /* get past #define */ |
if( lastst != id ) { |
error(ERR_DEFINE); |
return getline(incldepth == 0); |
} |
++global_flag; /* always do #define as globals */ |
sp = allocSYM(); |
sp->name = litlate(lastid); |
sp->value.s = litlate(lptr-1); |
insert(sp,&defsyms); |
--global_flag; |
return getline(incldepth == 0); |
} |
|
int doifdef() |
{ |
SYM *sp; |
int rv; |
char *lne; |
|
lne = inpline; |
NextToken(); |
if( lastst != id ) { |
error(ERR_DEFINE); |
return getline(incldepth == 0); |
} |
endifCount++; |
sp = search(lastid,&defsyms); |
if (sp == NULL) { |
do |
rv = getline(incldepth == 0); |
while (rv==0 && endifCount!=0); |
} |
return getline(incldepth == 0); |
} |
|
int doifndef() |
{ |
SYM *sp; |
int rv; |
|
NextToken(); |
if( lastst != id ) { |
error(ERR_DEFINE); |
return getline(incldepth == 0); |
} |
endifCount++; |
sp = search(lastid,&defsyms); |
if (sp != NULL) { |
do |
rv = getline(incldepth == 0); |
while (rv==0 && endifCount!=0); |
} |
return getline(incldepth == 0); |
} |
|
int doendif() |
{ |
endifCount--; |
return getline(incldepth == 0); |
} |
|
|
/C.h
0,0 → 1,159
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
|
/* compiler header file */ |
|
enum e_sym { |
id, cconst, iconst, lconst, sconst, rconst, plus, minus, |
star, divide, lshift, rshift, modop, eq, neq, lt, leq, gt, |
geq, assign, asplus, asminus, astimes, asdivide, asmodop, |
aslshift, asrshift, asand, asor, autoinc, autodec, hook, compl, |
comma, colon, semicolon, uparrow, openbr, closebr, begin, end, |
openpa, closepa, pointsto, dot, lor, land, not, or, and, |
ellipsis, |
|
kw_int, kw_byte, kw_icache, kw_dcache, |
kw_void, kw_char, kw_float, kw_double, kw_struct, kw_union, |
kw_long, kw_short, kw_unsigned, kw_auto, kw_extern, |
kw_register, kw_typedef, kw_static, kw_goto, kw_return, |
kw_sizeof, kw_break, kw_continue, kw_if, kw_else, kw_elsif, |
kw_for, kw_forever, kw_signed, |
kw_firstcall, kw_asm, kw_fallthru, kw_until, kw_loop, |
kw_try, kw_catch, kw_throw, kw_typenum, |
kw_do, kw_while, kw_switch, kw_case, kw_default, kw_enum, |
kw_interrupt, kw_vortex, kw_pascal, kw_oscall, kw_nocall, kw_intoff, kw_inton, kw_then, |
kw_private,kw_public,kw_stop,kw_critical,kw_spinlock,kw_spinunlock,kw_lockfail, |
eof }; |
|
enum e_sc { |
sc_static, sc_auto, sc_global, sc_external, sc_type, sc_const, |
sc_member, sc_label, sc_ulabel, sc_typedef }; |
|
enum e_bt { |
bt_byte, |
bt_char, bt_short, bt_long, bt_float, bt_double, bt_pointer, |
bt_uchar, bt_ushort, bt_ulong, |
bt_unsigned, bt_struct, bt_union, bt_enum, bt_void, bt_func, bt_ifunc, |
bt_interrupt, bt_oscall, bt_pascal, bt_bitfield, bt_ubitfield, bt_last}; |
|
struct slit { |
struct slit *next; |
int label; |
char *str; |
}; |
|
struct typ; |
|
struct sym { |
struct sym *next; |
char *name; |
__int8 storage_class; |
// Function attributes |
__int8 NumParms; |
struct sym *parms; |
struct sym *nextparm; |
unsigned int IsPrototype : 1; |
unsigned int IsInterrupt : 1; |
unsigned int IsNocall : 1; |
unsigned int IsPascal : 1; |
unsigned int IsLeaf : 1; |
unsigned int DoesThrow : 1; |
union { |
__int64 i; |
unsigned __int64 u; |
double f; |
char *s; |
} value; |
struct typ *tp; |
}; |
|
typedef struct typ { |
__int8 type; |
__int16 typeno; // number of the type |
unsigned int val_flag : 1; /* is it a value type */ |
unsigned int isUnsigned : 1; |
unsigned int isShort : 1; |
unsigned int isVolatile : 1; |
__int8 bit_width; |
__int8 bit_offset; |
long size; |
struct stab { |
struct sym *head, *tail; |
} lst; |
struct typ *btp; |
char *sname; |
} TYP; |
|
#define SYM struct sym |
//#define TYP struct typ |
#define TABLE struct stab |
|
#define MAX_STRLEN 120 |
#define MAX_STLP1 121 |
#define ERR_SYNTAX 0 |
#define ERR_ILLCHAR 1 |
#define ERR_FPCON 2 |
#define ERR_ILLTYPE 3 |
#define ERR_UNDEFINED 4 |
#define ERR_DUPSYM 5 |
#define ERR_PUNCT 6 |
#define ERR_IDEXPECT 7 |
#define ERR_NOINIT 8 |
#define ERR_INCOMPLETE 9 |
#define ERR_ILLINIT 10 |
#define ERR_INITSIZE 11 |
#define ERR_ILLCLASS 12 |
#define ERR_BLOCK 13 |
#define ERR_NOPOINTER 14 |
#define ERR_NOFUNC 15 |
#define ERR_NOMEMBER 16 |
#define ERR_LVALUE 17 |
#define ERR_DEREF 18 |
#define ERR_MISMATCH 19 |
#define ERR_EXPREXPECT 20 |
#define ERR_WHILEXPECT 21 |
#define ERR_NOCASE 22 |
#define ERR_DUPCASE 23 |
#define ERR_LABEL 24 |
#define ERR_PREPROC 25 |
#define ERR_INCLFILE 26 |
#define ERR_CANTOPEN 27 |
#define ERR_DEFINE 28 |
#define ERR_CATCHEXPECT 29 |
#define ERR_BITFIELD_WIDTH 30 |
#define ERR_EXPRTOOCOMPLEX 31 |
#define ERR_ASMTOOLONG 32 |
#define ERR_TOOMANYCASECONSTANTS 33 |
#define ERR_CATCHSTRUCT 34 |
|
/* alignment sizes */ |
|
#define AL_BYTE 1 |
#define AL_CHAR 2 |
#define AL_SHORT 4 |
#define AL_LONG 8 |
#define AL_POINTER 8 |
#define AL_FLOAT 4 |
#define AL_DOUBLE 8 |
#define AL_STRUCT 8 |
|
#define TRUE 1 |
#define FALSE 0 |
#define NULL ((void *)0) |
|
|
/err.c
0,0 → 1,84
// ============================================================================ |
// (C) 2012 Robert Finch |
// All Rights Reserved. |
// robfinch<remove>@opencores.org |
// |
// C64 - Raptor64 'C' derived language compiler |
// - 64 bit CPU |
// |
// This source file is free software: you can redistribute it and/or modify |
// it under the terms of the GNU Lesser General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or |
// (at your option) any later version. |
// |
// This source file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public License |
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
// |
// ============================================================================ |
// |
#include "c.h" |
|
extern int numerrs; |
extern int total_errors; |
extern int errno[80]; |
|
static char *errtextstr[] = { |
"Syntax error", |
"Illegal character", |
"Floating point", |
"Illegal type", |
"Undefined symbol", |
"Bad punctuation", |
"Identifier expected", |
"No initializer", |
"Incomplete statement", |
"Illegal initializer", |
"Illegal class", |
"block", |
"No pointer", |
"No function", |
"No member", |
"LValue required", |
"Dereference", |
"Mismatch", |
"Expression expected", |
"While/Until expected", |
"Missing case statement", |
"Duplicate case statement", |
"Bad label", |
"Preprocessor error", |
"Include file", |
"Can't open", |
"Define", |
"Expecting a catch statement", |
"Bad bitfield width", |
"Expression too complex", |
"Asm statement too long - break into multiple statements", |
"Too many case constants", |
"Attempting to catch a structure - aggregates may not be caught - use a pointer to struct" |
}; |
|
char *errtext(int errnum) |
{ |
return errtextstr[errnum]; |
} |
|
/* |
* error - print error information |
*/ |
void error(int n) |
{ |
if (numerrs < 80) { |
errno[numerrs++] = n; |
++total_errors; |
} |
else |
exit(1); |
} |
|
|
/Intexpr.c
0,0 → 1,60
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
|
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
int GetIntegerExpression() /* simple integer value */ |
{ |
int temp; |
SYM *sp; |
|
if(lastst == id) { |
sp = gsearch(lastid); |
if(sp == NULL) { |
error(ERR_UNDEFINED); |
NextToken(); |
return 0; |
} |
if(sp->storage_class != sc_const) { |
error(ERR_SYNTAX); |
NextToken(); |
return 0; |
} |
NextToken(); |
return sp->value.i; |
} |
else if(lastst == iconst) |
{ |
temp = ival; |
NextToken(); |
return temp; |
} |
NextToken(); |
error(ERR_SYNTAX); |
return 0; |
} |
/Optimize.c
0,0 → 1,420
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
|
/* Modified to support 64 bit Raptor64 by |
Robert Finch robfinch<remove>@opencores.org |
*/ |
|
void fold_const(struct enode **node); |
|
/* |
* dooper will execute a constant operation in a node and |
* modify the node to be the result of the operation. |
*/ |
void dooper(ENODE **node) |
{ |
ENODE *ep; |
|
ep = *node; |
switch( ep->nodetype ) { |
case en_add: |
ep->nodetype = en_icon; |
ep->i = ep->p[0]->i + ep->p[1]->i; |
break; |
case en_sub: |
ep->nodetype = en_icon; |
ep->i = ep->p[0]->i - ep->p[1]->i; |
break; |
case en_mul: |
case en_mulu: |
ep->nodetype = en_icon; |
ep->i = ep->p[0]->i * ep->p[1]->i; |
break; |
case en_div: |
case en_udiv: |
ep->nodetype = en_icon; |
ep->i = ep->p[0]->i / ep->p[1]->i; |
break; |
case en_shl: |
ep->nodetype = en_icon; |
ep->i = ep->p[0]->i << ep->p[1]->i; |
break; |
case en_shr: |
ep->nodetype = en_icon; |
ep->i = ep->p[0]->i >> ep->p[1]->i; |
break; |
case en_shru: |
ep->nodetype = en_icon; |
ep->i = (unsigned)ep->p[0]->i >> ep->p[1]->i; |
break; |
case en_and: |
ep->nodetype = en_icon; |
ep->i = ep->p[0]->i & ep->p[1]->i; |
break; |
case en_or: |
ep->nodetype = en_icon; |
ep->i = ep->p[0]->i | ep->p[1]->i; |
break; |
case en_xor: |
ep->nodetype = en_icon; |
ep->i = ep->p[0]->i ^ ep->p[1]->i; |
break; |
} |
} |
|
/* |
* return which power of two i is or -1. |
*/ |
int pwrof2(__int64 i) |
{ |
int p; |
__int64 q; |
|
q = 2; |
p = 1; |
while( q > 0 ) |
{ |
if( q == i ) |
return p; |
q <<= 1; |
++p; |
} |
return -1; |
} |
|
/* |
* make a mod mask for a power of two. |
*/ |
__int64 mod_mask(int i) |
{ |
__int64 m; |
m = 0; |
while( i-- ) |
m = (m << 1) | 1; |
return m; |
} |
|
/* |
* opt0 - delete useless expressions and combine constants. |
* |
* opt0 will delete expressions such as x + 0, x - 0, x * 0, |
* x * 1, 0 / x, x / 1, x mod 0, etc from the tree pointed to |
* by node and combine obvious constant operations. It cannot |
* combine name and label constants but will combine icon type |
* nodes. |
*/ |
void opt0(ENODE **node) |
{ |
ENODE *ep; |
__int64 val, sc; |
|
ep = *node; |
if( ep == NULL ) |
return; |
switch( (*node)->nodetype ) { |
case en_b_ref: |
case en_c_ref: |
case en_h_ref: |
case en_w_ref: /* optimize unary node */ |
case en_ub_ref: |
case en_uc_ref: |
case en_uh_ref: |
case en_uw_ref: /* optimize unary node */ |
case en_cbc: |
case en_cbh: |
case en_cbw: |
case en_cch: |
case en_ccw: |
case en_chw: |
case en_ainc: |
case en_adec: |
case en_not: |
case en_compl: |
opt0( &((*node)->p[0])); |
return; |
case en_uminus: |
opt0( &(ep->p[0])); |
if( ep->p[0]->nodetype == en_icon ) |
{ |
ep->nodetype = en_icon; |
ep->i = -ep->p[0]->i; |
} |
return; |
case en_add: |
case en_sub: |
opt0(&(ep->p[0])); |
opt0(&(ep->p[1])); |
if( ep->p[0]->nodetype == en_icon ) { |
if( ep->p[1]->nodetype == en_icon ) { |
dooper(node); |
return; |
} |
if( ep->p[0]->i == 0 ) { |
if( ep->nodetype == en_sub ) |
{ |
ep->p[0] = ep->p[1]; |
ep->nodetype = en_uminus; |
} |
else |
*node = ep->p[1]; |
return; |
} |
} |
else if( ep->p[1]->nodetype == en_icon ) { |
if( ep->p[1]->i == 0 ) { |
*node = ep->p[0]; |
return; |
} |
} |
return; |
case en_mul: |
case en_mulu: |
opt0(&(ep->p[0])); |
opt0(&(ep->p[1])); |
if( ep->p[0]->nodetype == en_icon ) { |
if( ep->p[1]->nodetype == en_icon ) { |
dooper(node); |
return; |
} |
val = ep->p[0]->i; |
if( val == 0 ) { |
*node = ep->p[0]; |
return; |
} |
if( val == 1 ) { |
*node = ep->p[1]; |
return; |
} |
sc = pwrof2(val); |
if( sc != -1 ) |
{ |
swap_nodes(ep); |
ep->p[1]->i = sc; |
ep->nodetype = en_shl; |
} |
} |
else if( ep->p[1]->nodetype == en_icon ) { |
val = ep->p[1]->i; |
if( val == 0 ) { |
*node = ep->p[1]; |
return; |
} |
if( val == 1 ) { |
*node = ep->p[0]; |
return; |
} |
sc = pwrof2(val); |
if( sc != -1 ) |
{ |
ep->p[1]->i = sc; |
ep->nodetype = en_shl; |
} |
} |
break; |
case en_div: |
case en_udiv: |
opt0(&(ep->p[0])); |
opt0(&(ep->p[1])); |
if( ep->p[0]->nodetype == en_icon ) { |
if( ep->p[1]->nodetype == en_icon ) { |
dooper(node); |
return; |
} |
if( ep->p[0]->i == 0 ) { /* 0/x */ |
*node = ep->p[0]; |
return; |
} |
} |
else if( ep->p[1]->nodetype == en_icon ) { |
val = ep->p[1]->i; |
if( val == 1 ) { /* x/1 */ |
*node = ep->p[0]; |
return; |
} |
sc = pwrof2(val); |
if( sc != -1 ) |
{ |
ep->p[1]->i = sc; |
ep->nodetype = en_shr; |
} |
} |
break; |
case en_mod: |
opt0(&(ep->p[0])); |
opt0(&(ep->p[1])); |
if( ep->p[1]->nodetype == en_icon ) |
{ |
if( ep->p[0]->nodetype == en_icon ) |
{ |
dooper(node); |
return; |
} |
sc = pwrof2(ep->p[1]->i); |
if( sc != -1 ) |
{ |
ep->p[1]->i = mod_mask(sc); |
ep->nodetype = en_and; |
} |
} |
break; |
case en_and: case en_or: |
case en_xor: case en_shr: case en_shru: |
case en_shl: |
opt0(&(ep->p[0])); |
opt0(&(ep->p[1])); |
if( ep->p[0]->nodetype == en_icon && |
ep->p[1]->nodetype == en_icon ) |
dooper(node); |
break; |
case en_land: case en_lor: |
case en_ult: case en_ule: |
case en_ugt: case en_uge: |
case en_lt: case en_le: |
case en_gt: case en_ge: |
case en_eq: case en_ne: |
case en_asand: case en_asor: |
case en_asadd: case en_assub: |
case en_asmul: case en_asdiv: |
case en_asmod: case en_asrsh: |
case en_aslsh: case en_cond: |
case en_fcall: case en_void: |
case en_assign: |
opt0(&(ep->p[0])); |
opt0(&(ep->p[1])); |
break; |
} |
} |
|
/* |
* xfold will remove constant nodes and return the values to |
* the calling routines. |
*/ |
__int64 xfold(ENODE *node) |
{ |
__int64 i; |
|
if( node == NULL ) |
return 0; |
switch( node->nodetype ) |
{ |
case en_icon: |
i = node->i; |
node->i = 0; |
return i; |
case en_add: |
return xfold(node->p[0]) + xfold(node->p[1]); |
case en_sub: |
return xfold(node->p[0]) - xfold(node->p[1]); |
case en_mul: |
case en_mulu: |
if( node->p[0]->nodetype == en_icon ) |
return xfold(node->p[1]) * node->p[0]->i; |
else if( node->p[1]->nodetype == en_icon ) |
return xfold(node->p[0]) * node->p[1]->i; |
else return 0; |
case en_shl: |
if( node->p[0]->nodetype == en_icon ) |
return xfold(node->p[1]) << node->p[0]->i; |
else if( node->p[1]->nodetype == en_icon ) |
return xfold(node->p[0]) << node->p[1]->i; |
else return 0; |
case en_uminus: |
return - xfold(node->p[0]); |
case en_shr: case en_div: case en_udiv: case en_shru: |
case en_mod: case en_asadd: |
case en_assub: case en_asmul: |
case en_asdiv: case en_asmod: |
case en_and: case en_land: |
case en_or: case en_lor: |
case en_xor: case en_asand: |
case en_asor: case en_void: |
case en_fcall: case en_assign: |
fold_const(&node->p[0]); |
fold_const(&node->p[1]); |
return 0; |
case en_ub_ref: case en_uw_ref: |
case en_uc_ref: case en_uh_ref: |
case en_b_ref: case en_w_ref: |
case en_c_ref: case en_h_ref: |
case en_compl: |
case en_not: |
fold_const(&node->p[0]); |
return 0; |
} |
return 0; |
} |
|
/* |
* reorganize an expression for optimal constant grouping. |
*/ |
void fold_const(ENODE **node) |
{ ENODE *ep; |
__int64 i; |
ep = *node; |
if( ep == 0 ) |
return; |
if( ep->nodetype == en_add ) |
{ |
if( ep->p[0]->nodetype == en_icon ) |
{ |
ep->p[0]->i += xfold(ep->p[1]); |
return; |
} |
else if( ep->p[1]->nodetype == en_icon ) |
{ |
ep->p[1]->i += xfold(ep->p[0]); |
return; |
} |
} |
else if( ep->nodetype == en_sub ) |
{ |
if( ep->p[0]->nodetype == en_icon ) |
{ |
ep->p[0]->i -= xfold(ep->p[1]); |
return; |
} |
else if( ep->p[1]->nodetype == en_icon ) |
{ |
ep->p[1]->i -= xfold(ep->p[0]); |
return; |
} |
} |
i = xfold(ep); |
if( i != 0 ) |
{ |
ep = makeinode(en_icon,i); |
ep = makenode(en_add,ep,*node); |
*node = ep; |
} |
} |
|
/* |
* apply all constant optimizations. |
*/ |
void opt4(struct enode **node) |
{ |
opt0(node); |
fold_const(node); |
opt0(node); |
} |
/Outcode.c
0,0 → 1,477
#include <stdio.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
|
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
void put_mask(int mask); |
void align(int n); |
|
/* variable initialization */ |
|
enum e_gt { nogen, bytegen, chargen, halfgen, wordgen, longgen }; |
enum e_sg { noseg, codeseg, dataseg }; |
|
int gentype = nogen; |
int curseg = noseg; |
int outcol = 0; |
|
struct oplst { |
char *s; |
int ov; |
} opl[] = |
{ {"move",op_move}, {"add",op_add}, {"addu", op_addu}, {"mov", op_mov}, |
{"add",op_addi}, {"sub",op_sub}, {"subu", op_subu}, |
{"subi",op_subi}, {"and",op_and}, |
{"sext8",op_sext8}, {"sext16", op_sext16}, {"sext32", op_sext32}, |
{"subui",op_subui}, {"shru", op_shru}, {"divsi", op_divsi}, {"not", op_not}, |
{"addui",op_addui}, {"shr", op_shr}, {"dw", op_dw}, {"shl", op_shl}, {"shr", op_shr}, {"shru", op_shru}, |
{"shli", op_shli}, {"shri", op_shri}, {"shrui", op_shrui}, |
{"sw", op_sw}, {"lw", op_lw}, {"lh", op_lh}, {"lc", op_lc}, {"lb", op_lb}, |
{"lm", op_lm}, {"sm",op_sm}, {"sb",op_sb}, {"sc",op_sc}, {"sh",op_sh}, |
{"call", op_call}, {"ret", op_ret}, {"loop", op_loop}, {"beqi", op_beqi}, |
{"jal", op_jal}, {"lwr", op_lwr}, {"swc", op_swc}, {"cache",op_cache}, |
{"or",op_or}, {"ori",op_ori}, {"iret", op_iret}, {"andi", op_andi}, |
{"xor",op_xor}, {"xori", op_xori}, {"muls",op_muls}, {"mulsi", op_mulsi}, {"mului", op_mului}, |
{"divs",op_divs}, {"swap",op_swap}, {"mod", op_mod}, {"modu", op_modu}, |
{"beq",op_beq}, {"bnei", op_bnei}, {"sei", op_sei}, |
{"bltu", op_bltu}, {"bleu",op_bleu}, {"bgtu",op_bgtu}, {"bgeu", op_bgeu}, |
{"bhi",op_bhi}, {"bhs",op_bhs}, {"blo",op_blo}, |
{"bls",op_bls}, {"mulu",op_mulu}, {"divu",op_divu}, |
{"bne",op_bne}, {"blt",op_blt}, {"ble",op_ble}, |
{"bgt",op_bgt}, {"bge",op_bge}, {"neg",op_neg}, {"bnr", op_bnr}, |
{"not",op_not}, {"cmp",op_cmp}, {"ext",op_ext}, |
{"jmp",op_jmp}, |
{"lea",op_lea}, {"asr",op_asr}, |
{"clr",op_clr}, {"link",op_link}, {"unlk",op_unlk}, |
{"bra",op_bra}, {"pea",op_pea}, |
{"cmp",op_cmpi}, {"tst",op_tst}, |
{"stop", op_stop}, |
{"bmi", op_bmi}, |
{"dc",op_dc}, |
{"",op_empty}, {"",op_asm}, |
{0,0} }; |
|
static char *pad(char *op) |
{ |
static char buf[20]; |
int n; |
|
n = strlen(op); |
strncpy(buf,op,20); |
if (n < 5) { |
strcat(buf, " "); |
buf[5] = '\0'; |
} |
return buf; |
} |
|
void putop(int op) |
{ |
int i; |
i = 0; |
while( opl[i].s ) |
{ |
if( opl[i].ov == op ) |
{ |
fprintf(output,"\t%s",pad(opl[i].s)); |
return; |
} |
++i; |
} |
printf("DIAG - illegal opcode.\n"); |
} |
|
static void PutConstant(ENODE *offset) |
{ |
switch( offset->nodetype ) |
{ |
case en_autocon: |
case en_icon: |
fprintf(output,"%I64d",offset->i); |
break; |
case en_labcon: |
fprintf(output,"L_%I64d",offset->i); |
break; |
case en_nacon: |
fprintf(output,"%s",offset->sp); |
break; |
case en_add: |
PutConstant(offset->p[0]); |
fprintf(output,"+"); |
PutConstant(offset->p[1]); |
break; |
case en_sub: |
PutConstant(offset->p[0]); |
fprintf(output,"-"); |
PutConstant(offset->p[1]); |
break; |
case en_uminus: |
fprintf(output,"-"); |
PutConstant(offset->p[0]); |
break; |
default: |
printf("DIAG - illegal constant node.\n"); |
break; |
} |
} |
|
char *RegMoniker(int regno) |
{ |
static char buf[4][20]; |
static int n; |
|
n = (n + 1) & 3; |
switch(regno) { |
case 27: sprintf(&buf[n], "bp"); break; |
case 28: sprintf(&buf[n], "xlr"); break; |
case 29: sprintf(&buf[n], "pc"); break; |
case 30: sprintf(&buf[n], "sp"); break; |
case 31: sprintf(&buf[n], "lr"); break; |
default: sprintf(&buf[n], "r%d", regno); break; |
} |
return &buf[n]; |
} |
|
void PutAddressMode(AMODE *ap) |
{ |
switch( ap->mode ) |
{ |
case am_immed: |
fprintf(output,"#"); |
case am_direct: |
PutConstant(ap->offset); |
break; |
case am_reg: |
fprintf(output, "%s", RegMoniker(ap->preg)); |
break; |
case am_ind: |
//if (ap->offset != NULL) { |
// if (ap->offset->i != 0) |
// fprintf(output, "%I64d[r%d]", ap->offset->i, ap->preg); |
// else |
// fprintf(output,"[r%d]",ap->preg); |
//} |
//else |
fprintf(output,"[%s]",RegMoniker(ap->preg)); |
break; |
case am_ainc: |
fprintf(output,"******[r%d]",ap->preg); |
fprintf(output,"addui\ta%d,a%d,#",ap->preg,ap->preg); |
break; |
case am_adec: |
fprintf(output,"subui\ta%d,a%d,#",ap->preg,ap->preg); |
fprintf(output,"******[a%d]",ap->preg); |
break; |
case am_indx: |
PutConstant(ap->offset); |
fprintf(output,"[%s]",RegMoniker(ap->preg)); |
break; |
case am_indx2: |
PutConstant(ap->offset); |
fprintf(output,"[%s+%s]",RegMoniker(ap->preg),RegMoniker(ap->sreg)); |
break; |
case am_indx3: |
PutConstant(ap->offset); |
fprintf(output,"[%s+%s]",RegMoniker(ap->preg),RegMoniker(ap->sreg)); |
break; |
case am_mask: |
put_mask(ap->offset); |
break; |
default: |
printf("DIAG - illegal address mode.\n"); |
break; |
} |
} |
|
/* |
* output a generic instruction. |
*/ |
void put_code(int op, int len,AMODE *aps,AMODE *apd,AMODE *ap3) |
{ if( op == op_dc ) |
{ |
switch( len ) |
{ |
case 1: fprintf(output,"\tdb"); break; |
case 2: fprintf(output,"\tdc"); break; |
case 4: fprintf(output,"\tdh"); break; |
case 8: fprintf(output,"\tdw"); break; |
} |
} |
else |
{ |
putop(op); |
} |
if( aps != 0 ) |
{ |
fprintf(output,"\t"); |
PutAddressMode(aps); |
if( apd != 0 ) |
{ |
fprintf(output,","); |
PutAddressMode(apd); |
if (ap3 != NULL) { |
fprintf(output,","); |
PutAddressMode(ap3); |
} |
} |
} |
fprintf(output,"\n"); |
} |
|
/* |
* generate a register mask for restore and save. |
*/ |
void put_mask(int mask) |
{ |
int nn; |
int first = 1; |
|
for (nn = 0; nn < 32; nn++) { |
if (mask & (1<<nn)) { |
if (!first) |
fprintf(output,"/"); |
fprintf(output,"r%d",nn); |
first = 0; |
} |
} |
// fprintf(output,"#0x%04x",mask); |
|
} |
|
/* |
* generate a register name from a tempref number. |
*/ |
void putreg(int r) |
{ |
fprintf(output, "r%d", r); |
} |
|
/* |
* generate a named label. |
*/ |
void gen_strlab(char *s) |
{ fprintf(output,"%s:\n",s); |
} |
|
/* |
* output a compiler generated label. |
*/ |
void put_label(int lab) |
{ |
fprintf(output,"L_%d:\n",lab); |
} |
|
void GenerateByte(int val) |
{ |
if( gentype == bytegen && outcol < 60) { |
fprintf(output,",%d",val & 0x00ff); |
outcol += 4; |
} |
else { |
nl(); |
fprintf(output,"\tdb\t%d",val & 0x00ff); |
gentype = bytegen; |
outcol = 19; |
} |
} |
|
void GenerateChar(int val) |
{ |
if( gentype == chargen && outcol < 60) { |
fprintf(output,",%d",val & 0xffff); |
outcol += 6; |
} |
else { |
nl(); |
fprintf(output,"\tdc\t%d",val & 0xffff); |
gentype = chargen; |
outcol = 21; |
} |
} |
|
void genhalf(int val) |
{ |
if( gentype == bytegen && outcol < 60) { |
fprintf(output,",%d",val & 0xffffffff); |
outcol += 10; |
} |
else { |
nl(); |
fprintf(output,"\tdh\t%d",val & 0xffffffff); |
gentype = halfgen; |
outcol = 25; |
} |
} |
|
void GenerateWord(__int64 val) |
{ |
if( gentype == wordgen && outcol < 58) { |
fprintf(output,",%I64d",val); |
outcol += 18; |
} |
else { |
nl(); |
fprintf(output,"\tdw\t%I64d",val); |
gentype = wordgen; |
outcol = 33; |
} |
} |
|
void GenerateLong(__int64 val) |
{ if( gentype == longgen && outcol < 56) { |
fprintf(output,",%I64d",val); |
outcol += 10; |
} |
else { |
nl(); |
fprintf(output,"\tdw\t%I64d",val); |
gentype = longgen; |
outcol = 25; |
} |
} |
|
void GenerateReference(SYM *sp,int offset) |
{ |
char sign; |
if( offset < 0) { |
sign = '-'; |
offset = -offset; |
} |
else |
sign = '+'; |
if( gentype == longgen && outcol < 55 - strlen(sp->name)) { |
if( sp->storage_class == sc_static) |
fprintf(output,",L_%I64d%c%d",sp->value.i,sign,offset); |
else |
fprintf(output,",%s%c%d",sp->name,sign,offset); |
outcol += (11 + strlen(sp->name)); |
} |
else { |
nl(); |
if(sp->storage_class == sc_static) |
fprintf(output,"\tdw\tL_%I64d%c%d",sp->value.i,sign,offset); |
else |
fprintf(output,"\tdw\t%s%c%d",sp->name,sign,offset); |
outcol = 26 + strlen(sp->name); |
gentype = longgen; |
} |
} |
|
void genstorage(int nbytes) |
{ nl(); |
fprintf(output,"\tdcb.b\t%d,0xff\n",nbytes); |
} |
|
void GenerateLabelReference(int n) |
{ if( gentype == longgen && outcol < 58) { |
fprintf(output,",L_%d",n); |
outcol += 6; |
} |
else { |
nl(); |
fprintf(output,"\tlong\tL_%d",n); |
outcol = 22; |
gentype = longgen; |
} |
} |
|
/* |
* make s a string literal and return it's label number. |
*/ |
int stringlit(char *s) |
{ |
struct slit *lp; |
|
++global_flag; /* always AllocateRegisterVars from global space. */ |
lp = (struct slit *)xalloc(sizeof(struct slit)); |
lp->label = nextlabel++; |
lp->str = litlate(s); |
lp->next = strtab; |
strtab = lp; |
--global_flag; |
return lp->label; |
} |
|
/* |
* dump the string literal pool. |
*/ |
void dumplits() |
{ |
char *cp; |
|
cseg(); |
nl(); |
align(8); |
nl(); |
while( strtab != NULL) { |
nl(); |
put_label(strtab->label); |
cp = strtab->str; |
while(*cp) |
GenerateChar(*cp++); |
GenerateChar(0); |
strtab = strtab->next; |
} |
nl(); |
} |
|
void nl() |
{ if(outcol > 0) { |
fprintf(output,"\n"); |
outcol = 0; |
gentype = nogen; |
} |
} |
|
void align(int n) |
{ |
fprintf(output,"\talign\t%d\n",n); |
} |
|
void cseg() |
{ |
if( curseg != codeseg) { |
nl(); |
fprintf(output,"\tcode\n"); |
fprintf(output,"\talign\t16\n"); |
curseg = codeseg; |
} |
} |
|
void dseg() |
{ |
if( curseg != dataseg) { |
nl(); |
fprintf(output,"\tdata\n"); |
fprintf(output,"\talign\t8\n"); |
curseg = dataseg; |
} |
} |
|
|
/ParseDeclarations.c
0,0 → 1,647
#include <stdio.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
TYP *head = NULL; |
TYP *tail = NULL; |
char *declid = NULL; |
TABLE tagtable = {0,0}; |
TYP stdconst = { bt_long, bt_long, 1, FALSE, FALSE, FALSE, 0, 0, 8, {0, 0}, 0, "stdconst"}; |
char *names[20]; |
int nparms = 0; |
int funcdecl = FALSE; |
int catchdecl = FALSE; |
int isTypedef = FALSE; |
int isUnion = FALSE; |
int isUnsigned = FALSE; |
|
/* variable for bit fields */ |
static int bit_max; // largest bitnumber |
int bit_offset; /* the actual offset */ |
int bit_width; /* the actual width */ |
int bit_next; /* offset for next variable */ |
|
int declbegin(int st); |
void dodecl(int defclass); |
void ParseDeclarationSuffix(); |
void declstruct(int ztype); |
void structbody(TYP *tp, int ztype); |
void ParseEnumDeclaration(TABLE *table); |
void enumbody(TABLE *table); |
|
int imax(int i, int j) |
{ return (i > j) ? i : j; |
} |
|
|
char *litlate(char *s) |
{ |
char *p; |
p = xalloc(strlen(s) + 1); |
strcpy(p,s); |
return p; |
} |
|
TYP *maketype(int bt, int siz) |
{ |
TYP *tp; |
tp = allocTYP(); |
tp->val_flag = 0; |
tp->size = siz; |
tp->type = bt; |
tp->typeno = bt; |
tp->sname = 0; |
tp->lst.head = 0; |
return tp; |
} |
|
void ParseSpecifier(TABLE *table) |
{ |
SYM *sp; |
|
isUnsigned = FALSE; |
for (;;) { |
switch (lastst) { |
case kw_signed: // Ignore 'signed' |
NextToken(); |
break; |
case kw_typedef: |
isTypedef = TRUE; |
NextToken(); |
break; |
case kw_nocall: |
isNocall = TRUE; |
head = tail = maketype(bt_oscall,8); |
NextToken(); |
goto lxit; |
case kw_oscall: |
isOscall = TRUE; |
head = tail = maketype(bt_oscall,8); |
NextToken(); |
goto lxit; |
case kw_interrupt: |
isInterrupt = TRUE; |
head = tail = maketype(bt_interrupt,8); |
NextToken(); |
goto lxit; |
case kw_pascal: |
isPascal = TRUE; |
head = tail = maketype(bt_pascal,8); |
NextToken(); |
break; |
case kw_byte: |
head = tail = maketype(bt_byte,1); |
NextToken(); |
head->isUnsigned = isUnsigned; |
bit_max = 8; |
goto lxit; |
case kw_char: |
head = tail = maketype(bt_char,2); |
NextToken(); |
head->isUnsigned = isUnsigned; |
bit_max = 16; |
goto lxit; |
case kw_short: |
head = tail = maketype(bt_short,4); |
bit_max = 32; |
NextToken(); |
if( lastst == kw_int ) |
NextToken(); |
head->isUnsigned = isUnsigned; |
head->isShort = TRUE; |
goto lxit; |
break; |
case kw_long: // long, long int |
if (lastst==kw_int) { |
NextToken(); |
} |
if (lastst==kw_float) |
head = tail = maketype(bt_double,8); |
else |
head = tail = maketype(bt_long,8); |
NextToken(); |
if (lastst==kw_oscall) { |
isOscall = TRUE; |
NextToken(); |
} |
if (lastst==kw_nocall) { |
isNocall = TRUE; |
NextToken(); |
} |
head->isUnsigned = isUnsigned; |
bit_max = 64; |
goto lxit; |
break; |
case kw_int: |
head = tail = maketype(bt_long,8); |
head->isUnsigned = isUnsigned; |
NextToken(); |
if (lastst==kw_oscall) { |
isOscall = TRUE; |
NextToken(); |
} |
if (lastst==kw_nocall) { |
isNocall = TRUE; |
NextToken(); |
} |
bit_max = 64; |
goto lxit; |
break; |
case kw_unsigned: |
NextToken(); |
isUnsigned = TRUE; |
break; |
case id: /* no type ParseSpecifierarator */ |
sp = search(lastid,&gsyms[0]); |
if (sp) { |
if (sp->storage_class==sc_typedef) { |
NextToken(); |
head = tail = sp->tp; |
} |
else |
head = tail = sp->tp; |
// head = tail = maketype(bt_long,4); |
} |
else { |
head = tail = maketype(bt_long,8); |
bit_max = 64; |
} |
goto lxit; |
break; |
case kw_float: |
head = tail = maketype(bt_float,4); |
NextToken(); |
bit_max = 32; |
goto lxit; |
case kw_double: |
head = tail = maketype(bt_double,8); |
NextToken(); |
bit_max = 64; |
goto lxit; |
case kw_void: |
head = tail = maketype(bt_void,0); |
NextToken(); |
if (lastst==kw_interrupt) { |
isInterrupt = TRUE; |
NextToken(); |
} |
if (lastst==kw_nocall) { |
isNocall = TRUE; |
NextToken(); |
} |
bit_max = 0; |
goto lxit; |
case kw_enum: |
NextToken(); |
ParseEnumDeclaration(table); |
bit_max = 16; |
goto lxit; |
case kw_struct: |
NextToken(); |
ParseStructDeclaration(bt_struct); |
goto lxit; |
case kw_union: |
NextToken(); |
ParseStructDeclaration(bt_union); |
goto lxit; |
default: |
goto lxit; |
} |
} |
lxit:; |
} |
|
void ParseDeclarationPrefix(char isUnion) |
{ |
TYP *temp1, *temp2, *temp3, *temp4; |
|
switch (lastst) { |
case id: |
declid = litlate(lastid); |
if (funcdecl==1) |
names[nparms++] = declid; |
NextToken(); |
if (lastst == colon) { |
NextToken(); |
bit_width = GetIntegerExpression(); |
if (isUnion) |
bit_offset = 0; |
else |
bit_offset = bit_next; |
if (bit_width < 0 || bit_width > bit_max) { |
error(ERR_BITFIELD_WIDTH); |
bit_width = 1; |
} |
if (bit_width == 0 || bit_offset + bit_width > bit_max) |
bit_offset = 0; |
bit_next = bit_offset + bit_width; |
break; // no ParseDeclarationSuffix() |
} |
ParseDeclarationSuffix(); |
break; |
case star: |
temp1 = maketype(bt_pointer,8); |
temp1->btp = head; |
head = temp1; |
if(tail == NULL) |
tail = head; |
NextToken(); |
ParseDeclarationPrefix(isUnion); |
break; |
case openpa: |
NextToken(); |
temp1 = head; |
temp2 = tail; |
head = tail = NULL; |
ParseDeclarationPrefix(isUnion); |
needpunc(closepa); |
temp3 = head; |
temp4 = tail; |
head = temp1; |
tail = temp2; |
ParseDeclarationSuffix(); |
temp4->btp = head; |
if(temp4->type == bt_pointer && temp4->val_flag != 0 && head != NULL) |
temp4->size *= head->size; |
head = temp3; |
break; |
default: |
ParseDeclarationSuffix(); |
break; |
} |
} |
|
// Take care of the () or [] trailing part of a ParseSpecifieraration |
// |
void ParseDeclarationSuffix() |
{ |
TYP *temp1; |
switch (lastst) { |
case openbr: |
NextToken(); |
temp1 = maketype(bt_pointer,0); |
temp1->val_flag = 1; |
temp1->btp = head; |
if(lastst == closebr) { |
temp1->size = 0; |
NextToken(); |
} |
else if(head != NULL) { |
temp1->size = GetIntegerExpression() * head->size; |
needpunc(closebr); |
} |
else { |
temp1->size = GetIntegerExpression(); |
needpunc(closebr); |
} |
head = temp1; |
if( tail == NULL) |
tail = head; |
ParseDeclarationSuffix(); |
break; |
case openpa: |
NextToken(); |
temp1 = maketype(bt_func,0); |
temp1->val_flag = 1; |
temp1->btp = head; |
head = temp1; |
if( lastst == closepa) { |
NextToken(); |
if(lastst == begin) |
temp1->type = bt_ifunc; |
} |
else |
temp1->type = bt_ifunc; |
break; |
} |
} |
|
int alignment(TYP *tp) |
{ |
switch(tp->type) { |
case bt_byte: return AL_BYTE; |
case bt_char: return AL_CHAR; |
case bt_short: return AL_SHORT; |
case bt_long: return AL_LONG; |
case bt_enum: return AL_CHAR; |
case bt_pointer: |
if(tp->val_flag) |
return alignment(tp->btp); |
else |
return AL_POINTER; |
case bt_float: return AL_FLOAT; |
case bt_double: return AL_DOUBLE; |
case bt_struct: |
case bt_union: return AL_STRUCT; |
default: return AL_CHAR; |
} |
} |
|
/* |
* process ParseSpecifierarations of the form: |
* |
* <type> <ParseSpecifier>, <ParseSpecifier>...; |
* |
* leaves the ParseSpecifierarations in the symbol table pointed to by |
* table and returns the number of bytes declared. al is the |
* allocation type to assign, ilc is the initial location |
* counter. if al is sc_member then no initialization will |
* be processed. ztype should be bt_struct for normal and in |
* structure ParseSpecifierarations and sc_union for in union ParseSpecifierarations. |
*/ |
int declare(TABLE *table,int al,int ilc,int ztype) |
{ |
SYM *sp, *sp1, *sp2; |
TYP *dhead; |
|
static long old_nbytes; |
int nbytes; |
|
nbytes = 0; |
ParseSpecifier(table); |
dhead = head; |
for(;;) { |
declid = 0; |
bit_width = -1; |
ParseDeclarationPrefix(ztype==bt_union); |
if( declid != 0) { /* otherwise just struct tag... */ |
sp = allocSYM(); |
sp->name = declid; |
sp->storage_class = al; |
if (bit_width > 0 && bit_offset > 0) { |
// share the storage word with the previously defined field |
nbytes = old_nbytes - ilc; |
} |
old_nbytes = ilc + nbytes; |
if (al != sc_member) { |
// sp->isTypedef = isTypedef; |
if (isTypedef) |
sp->storage_class = sc_typedef; |
isTypedef = FALSE; |
} |
while( (ilc + nbytes) % alignment(head)) { |
if( al != sc_member && al != sc_external && al != sc_auto) { |
dseg(); |
GenerateByte(0); |
} |
++nbytes; |
} |
if( al == sc_static) |
sp->value.i = nextlabel++; |
else if( ztype == bt_union) |
sp->value.i = ilc; |
else if( al != sc_auto ) |
sp->value.i = ilc + nbytes; |
else |
sp->value.i = -(ilc + nbytes + head->size); |
|
if (bit_width == -1) |
sp->tp = head; |
else { |
sp->tp = allocTYP(); |
*(sp->tp) = *head; |
sp->tp->type = bt_bitfield; |
sp->tp->size = head->size;//tp_int.size; |
sp->tp->bit_width = bit_width; |
sp->tp->bit_offset = bit_offset; |
} |
|
if( |
(sp->tp->type == bt_func) && |
sp->storage_class == sc_global ) |
sp->storage_class = sc_external; |
if(ztype == bt_union) |
nbytes = imax(nbytes,sp->tp->size); |
else if(al != sc_external) |
nbytes += sp->tp->size; |
if( sp->tp->type == bt_ifunc && (sp1 = search(sp->name,table)) != 0 && |
sp1->tp->type == bt_func ) |
{ |
sp1->tp = sp->tp; |
sp1->storage_class = sp->storage_class; |
// sp1->value.i = sp->value.i; |
sp1->IsPrototype = sp->IsPrototype; |
sp = sp1; |
} |
else { |
sp2 = search(sp->name,table); |
if (sp2 == NULL) |
insert(sp,table); |
else { |
if (funcdecl==2) |
sp2->tp = sp->tp; |
//else if (!sp2->IsPrototype) |
// insert(sp,table); |
} |
} |
if( sp->tp->type == bt_ifunc) { /* function body follows */ |
ParseFunction(sp); |
return nbytes; |
} |
if( (al == sc_global || al == sc_static) && |
sp->tp->type != bt_func && sp->storage_class!=sc_typedef) |
doinit(sp); |
} |
if (funcdecl==TRUE) { |
if (lastst==comma || lastst==semicolon) |
break; |
if (lastst==closepa) |
goto xit1; |
} |
else if (catchdecl==TRUE) { |
if (lastst==closepa) |
goto xit1; |
} |
else if (lastst == semicolon) |
break; |
|
needpunc(comma); |
if(declbegin(lastst) == 0) |
break; |
head = dhead; |
} |
NextToken(); |
xit1: |
return nbytes; |
} |
|
int declbegin(int st) |
{ |
return st == star || st == id || st == openpa || st == openbr; |
} |
|
void ParseGlobalDeclarations() |
{ |
funcdecl = FALSE; |
for(;;) { |
switch(lastst) { |
case id: |
case kw_interrupt: |
case kw_pascal: |
case kw_nocall: |
case kw_oscall: |
case kw_typedef: |
case kw_byte: case kw_char: case kw_int: case kw_short: case kw_unsigned: case kw_signed: |
case kw_long: case kw_struct: case kw_union: |
case kw_enum: case kw_void: |
case kw_float: case kw_double: |
lc_static += declare(&gsyms,sc_global,lc_static,bt_struct); |
break; |
case kw_register: |
NextToken(); |
error(ERR_ILLCLASS); |
lc_static += declare(&gsyms,sc_global,lc_static,bt_struct); |
break; |
case kw_private: |
case kw_static: |
NextToken(); |
lc_static += declare(&gsyms,sc_static,lc_static,bt_struct); |
break; |
case kw_extern: |
NextToken(); |
if (lastst==kw_oscall || lastst==kw_interrupt || lastst==kw_nocall) |
NextToken(); |
++global_flag; |
declare(&gsyms,sc_external,0,bt_struct); |
--global_flag; |
break; |
default: |
return; |
} |
} |
} |
|
void ParseParameterDeclarations(int fd) |
{ |
funcdecl = fd; |
for(;;) { |
switch(lastst) { |
case kw_interrupt: |
case kw_nocall: |
case kw_oscall: |
case kw_pascal: |
case kw_typedef: |
error(ERR_ILLCLASS); |
declare(&lsyms,sc_auto,0,bt_struct); |
break; |
case id: |
case kw_byte: case kw_char: case kw_int: case kw_short: case kw_unsigned: case kw_signed: |
case kw_long: case kw_struct: case kw_union: |
case kw_enum: case kw_void: |
case kw_float: case kw_double: |
declare(&lsyms,sc_auto,0,bt_struct); |
break; |
case kw_static: |
NextToken(); |
error(ERR_ILLCLASS); |
lc_static += declare(&gsyms,sc_static,lc_static,bt_struct); |
break; |
case kw_extern: |
NextToken(); |
error(ERR_ILLCLASS); |
if (lastst==kw_oscall || lastst==kw_interrupt || lastst == kw_nocall) |
NextToken(); |
++global_flag; |
declare(&gsyms,sc_external,0,bt_struct); |
--global_flag; |
break; |
default: |
return; |
} |
} |
} |
|
|
void ParseAutoDeclarations() |
{ |
SYM *sp; |
|
funcdecl = FALSE; |
for(;;) { |
switch(lastst) { |
case kw_interrupt: |
case kw_nocall: |
case kw_oscall: |
case kw_pascal: |
case kw_typedef: |
error(ERR_ILLCLASS); |
lc_auto += declare(&lsyms,sc_auto,lc_auto,bt_struct); |
break; |
case id: //return; |
sp = search(lastid,&gsyms[0]); |
if (sp) { |
if (sp->storage_class==sc_typedef) { |
lc_auto += declare(&lsyms,sc_auto,lc_auto,bt_struct); |
break; |
} |
} |
return; |
case kw_register: |
NextToken(); |
case kw_byte: case kw_char: case kw_int: case kw_short: case kw_unsigned: case kw_signed: |
case kw_long: case kw_struct: case kw_union: |
case kw_enum: case kw_void: |
case kw_float: case kw_double: |
lc_auto += declare(&lsyms,sc_auto,lc_auto,bt_struct); |
break; |
case kw_static: |
NextToken(); |
lc_static += declare(&lsyms,sc_static,lc_static,bt_struct); |
break; |
case kw_extern: |
NextToken(); |
if (lastst==kw_oscall || lastst==kw_interrupt || lastst == kw_nocall) |
NextToken(); |
++global_flag; |
declare(&gsyms,sc_external,0,bt_struct); |
--global_flag; |
break; |
default: |
return; |
} |
} |
} |
|
/* |
* main compiler routine. this routine parses all of the |
* ParseSpecifierarations using declare which will call funcbody as |
* functions are encountered. |
*/ |
void compile() |
{ |
while(lastst != eof) |
{ |
ParseGlobalDeclarations(); |
if( lastst != eof) |
NextToken(); |
} |
dumplits(); |
} |
|
/Analyze.c
0,0 → 1,578
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
|
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
extern int popcnt(int m); |
|
/* |
* this module will step through the parse tree and find all |
* optimizable expressions. at present these expressions are |
* limited to expressions that are valid throughout the scope |
* of the function. the list of optimizable expressions is: |
* |
* constants |
* global and static addresses |
* auto addresses |
* contents of auto addresses. |
* |
* contents of auto addresses are valid only if the address is |
* never referred to without dereferencing. |
* |
* scan will build a list of optimizable expressions which |
* opt1 will replace during the second optimization pass. |
*/ |
|
static CSE *olist; /* list of optimizable expressions */ |
|
/* |
* equalnode will return 1 if the expressions pointed to by |
* node1 and node2 are equivalent. |
*/ |
static int equalnode(ENODE *node1, ENODE *node2) |
{ |
// if( node1 == 0 || node2 == 0 ) |
// return 0; |
// if( node1->nodetype != node2->nodetype ) |
// return 0; |
// if( (node1->nodetype == en_icon || node1->nodetype == en_labcon || |
// node1->nodetype == en_nacon || node1->nodetype == en_autocon) && |
// node1->v.i == node2->v.i ) |
// return 1; |
// if( IsLValue(node1) && equalnode(node1->v.p[0], node2->v.p[0]) ) |
// return 1; |
// return 0; |
//} |
if (node1 == NULL || node2 == NULL) |
return FALSE; |
if (node1->nodetype != node2->nodetype) |
return FALSE; |
switch (node1->nodetype) { |
case en_icon: |
case en_labcon: |
case en_autocon: |
return (node1->i == node2->i); |
case en_nacon: |
return (!strcmp(node1->sp, node2->sp)); |
default: |
if( IsLValue(node1) && equalnode(node1->p[0], node2->p[0]) ) |
return TRUE; |
return FALSE; |
} |
} |
|
/* |
* SearchCSEList will search the common expression table for an entry |
* that matches the node passed and return a pointer to it. |
*/ |
static CSE *SearchCSEList(ENODE *node) |
{ |
CSE *csp; |
|
csp = olist; |
while( csp != NULL ) { |
if( equalnode(node,csp->exp) ) |
return csp; |
csp = csp->next; |
} |
return NULL; |
} |
|
/* |
* copy the node passed into a new enode so it wont get |
* corrupted during substitution. |
*/ |
static ENODE *DuplicateEnode(ENODE *node) |
{ |
ENODE *temp; |
|
if( node == NULL ) |
return NULL; |
temp = allocEnode(); |
memcpy(temp,node,sizeof(ENODE)); // copy all the fields |
return temp; |
} |
|
/* |
* InsertNodeIntoCSEList will enter a reference to an expression node into the |
* common expression table. duse is a flag indicating whether or not |
* this reference will be dereferenced. |
*/ |
CSE *InsertNodeIntoCSEList(ENODE *node, int duse) |
{ |
CSE *csp; |
|
if( (csp = SearchCSEList(node)) == NULL ) { /* add to tree */ |
csp = allocCSE(); |
csp->next = olist; |
csp->uses = 1; |
csp->duses = (duse != 0); |
csp->exp = DuplicateEnode(node); |
csp->voidf = 0; |
csp->reg = 0; |
olist = csp; |
return csp; |
} |
++(csp->uses); |
if( duse ) |
++(csp->duses); |
return csp; |
} |
|
/* |
* voidauto will void an auto dereference node which points to |
* the same auto constant as node. |
*/ |
CSE *voidauto(ENODE *node) |
{ |
CSE *csp; |
|
csp = olist; |
while( csp != NULL ) { |
if( IsLValue(csp->exp) && equalnode(node,csp->exp->p[0]) ) { |
if( csp->voidf ) |
return NULL; |
csp->voidf = 1; |
return csp; |
} |
csp = csp->next; |
} |
return NULL; |
} |
|
/* |
* scanexpr will scan the expression pointed to by node for optimizable |
* subexpressions. when an optimizable expression is found it is entered |
* into the tree. if a reference to an autocon node is scanned the |
* corresponding auto dereferenced node will be voided. duse should be |
* set if the expression will be dereferenced. |
*/ |
static void scanexpr(ENODE *node, int duse) |
{ |
CSE *csp, *csp1; |
|
if( node == NULL ) |
return; |
|
switch( node->nodetype ) { |
case en_icon: |
case en_labcon: |
case en_nacon: |
InsertNodeIntoCSEList(node,duse); |
break; |
case en_autocon: |
if( (csp = voidauto(node)) != NULL ) { |
csp1 = InsertNodeIntoCSEList(node,duse); |
csp1->uses = (csp1->duses += csp->uses); |
} |
else |
InsertNodeIntoCSEList(node,duse); |
break; |
case en_b_ref: |
case en_c_ref: |
case en_h_ref: |
case en_w_ref: |
case en_ub_ref: |
case en_uc_ref: |
case en_uh_ref: |
case en_uw_ref: |
case en_bfieldref: |
case en_ubfieldref: |
case en_cfieldref: |
case en_ucfieldref: |
case en_hfieldref: |
case en_uhfieldref: |
case en_wfieldref: |
case en_uwfieldref: |
if( node->p[0]->nodetype == en_autocon ) { |
csp = InsertNodeIntoCSEList(node,duse); |
if( csp->voidf ) |
scanexpr(node->p[0],1); |
} |
else |
scanexpr(node->p[0],1); |
break; |
case en_cbc: |
case en_cbh: |
case en_cbw: |
case en_cch: |
case en_ccw: |
case en_chw: |
case en_uminus: |
case en_compl: case en_ainc: |
case en_adec: case en_not: |
scanexpr(node->p[0],duse); |
break; |
case en_asadd: case en_assub: |
case en_add: case en_sub: |
scanexpr(node->p[0],duse); |
scanexpr(node->p[1],duse); |
break; |
case en_mul: case en_mulu: case en_div: case en_udiv: |
case en_shl: case en_shr: case en_shru: |
case en_mod: case en_and: |
case en_or: case en_xor: |
case en_lor: case en_land: |
case en_eq: case en_ne: |
case en_gt: case en_ge: |
case en_lt: case en_le: |
case en_asmul: case en_asdiv: |
case en_asmod: case en_aslsh: |
case en_asrsh: |
case en_asand: case en_asxor: case en_asor: |
case en_cond: |
case en_void: case en_assign: |
scanexpr(node->p[0],0); |
scanexpr(node->p[1],0); |
break; |
case en_fcall: |
scanexpr(node->p[0],1); |
scanexpr(node->p[1],0); |
break; |
} |
} |
|
/* |
* scan will gather all optimizable expressions into the expression |
* list for a block of statements. |
*/ |
static void scan(Statement *block) |
{ |
while( block != NULL ) { |
switch( block->stype ) { |
case st_return: |
case st_throw: |
case st_expr: |
opt4(&block->exp); |
scanexpr(block->exp,0); |
break; |
case st_while: |
case st_until: |
case st_do: |
case st_dountil: |
opt4(&block->exp); |
scanexpr(block->exp,0); |
case st_doloop: |
case st_forever: |
scan(block->s1); |
break; |
case st_for: |
opt4(&block->initExpr); |
scanexpr(block->initExpr,0); |
opt4(&block->exp); |
scanexpr(block->exp,0); |
scan(block->s1); |
opt4(&block->incrExpr); |
scanexpr(block->incrExpr,0); |
break; |
case st_if: |
opt4(&block->exp); |
scanexpr(block->exp,0); |
scan(block->s1); |
scan(block->s2); |
break; |
case st_switch: |
opt4(&block->exp); |
scanexpr(block->exp,0); |
scan(block->s1); |
break; |
case st_case: |
scan(block->s1); |
break; |
case st_spinlock: |
scan(block->s1); |
break; |
} |
block = block->next; |
} |
} |
|
/* |
* exchange will exchange the order of two expression entries |
* following c1 in the linked list. |
*/ |
static void exchange(CSE **c1) |
{ |
CSE *csp1, *csp2; |
|
csp1 = *c1; |
csp2 = csp1->next; |
csp1->next = csp2->next; |
csp2->next = csp1; |
*c1 = csp2; |
} |
|
/* |
* returns the desirability of optimization for a subexpression. |
*/ |
int OptimizationDesireability(CSE *csp) |
{ |
if( csp->voidf || (csp->exp->nodetype == en_icon && |
csp->exp->i < 256 && csp->exp->i >= 0)) |
return 0; |
if( IsLValue(csp->exp) ) |
return 2 * csp->uses; |
return csp->uses; |
} |
|
/* |
* bsort implements a bubble sort on the expression list. |
*/ |
int bsort(CSE **list) |
{ |
CSE *csp1, *csp2; |
int i; |
|
csp1 = *list; |
if( csp1 == NULL || csp1->next == NULL ) |
return FALSE; |
i = bsort( &(csp1->next)); |
csp2 = csp1->next; |
if( OptimizationDesireability(csp1) < OptimizationDesireability(csp2) ) { |
exchange(list); |
return TRUE; |
} |
return FALSE; |
} |
|
/* |
* AllocateRegisterVars will allocate registers for the expressions that have |
* a high enough desirability. |
*/ |
void AllocateRegisterVars() |
{ |
CSE *csp; |
ENODE *exptr; |
int reg, mask, rmask; |
AMODE *ap, *ap2; |
int nn; |
|
reg = 11; |
mask = 0; |
rmask = 0; |
while( bsort(&olist) ); /* sort the expression list */ |
csp = olist; |
while( csp != NULL ) { |
if( OptimizationDesireability(csp) < 3 ) // was < 3 |
csp->reg = -1; |
// else if( csp->duses > csp->uses / 8 && reg < 18 ) // was / 4 |
else if( reg < 18 ) // was / 4 |
csp->reg = reg++; |
else |
csp->reg = -1; |
if( csp->reg != -1 ) |
{ |
rmask = rmask | (1 << (31 - csp->reg)); |
mask = mask | (1 << csp->reg); |
} |
csp = csp->next; |
} |
if( mask != 0 ) { |
if (bitsset(rmask) < 2) { |
for (nn = 0; nn < 32; nn++) |
if (rmask & (0x80000000 >> nn)) { |
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(8)); |
GenerateTriadic(op_sw,0,makereg(nn&31),make_indirect(30),NULL); |
} |
} |
else { |
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(popcnt(mask)*8)); |
GenerateDiadic(op_sm,0,make_indirect(30),make_mask(mask),NULL); |
} |
} |
save_mask = mask; |
csp = olist; |
while( csp != NULL ) { |
if( csp->reg != -1 ) |
{ /* see if preload needed */ |
exptr = csp->exp; |
if( !IsLValue(exptr) || (exptr->p[0]->i > 0) ) |
{ |
initstack(); |
ap = GenerateExpression(exptr,F_REG|F_IMMED,8); |
ap2 = makereg(csp->reg); |
if (ap->mode==am_immed) |
GenerateTriadic(op_ori,0,ap2,makereg(0),ap); |
else |
GenerateDiadic(op_mov,0,ap2,ap); |
ReleaseTempRegister(ap); |
} |
} |
csp = csp->next; |
} |
} |
|
/* |
* repexpr will replace all allocated references within an expression |
* with tempref nodes. |
*/ |
void repexpr(ENODE *node) |
{ |
struct cse *csp; |
if( node == NULL ) |
return; |
switch( node->nodetype ) { |
case en_icon: |
case en_nacon: |
case en_labcon: |
case en_autocon: |
if( (csp = SearchCSEList(node)) != NULL ) |
if( csp->reg > 0 ) { |
node->nodetype = en_regvar; |
node->i = csp->reg; |
} |
break; |
case en_b_ref: |
case en_c_ref: |
case en_h_ref: |
case en_w_ref: |
case en_ub_ref: |
case en_uc_ref: |
case en_uh_ref: |
case en_uw_ref: |
case en_bfieldref: |
case en_ubfieldref: |
case en_cfieldref: |
case en_ucfieldref: |
case en_hfieldref: |
case en_uhfieldref: |
case en_wfieldref: |
case en_uwfieldref: |
if( (csp = SearchCSEList(node)) != NULL ) { |
if( csp->reg > 0 ) { |
node->nodetype = en_regvar; |
node->i = csp->reg; |
} |
else |
repexpr(node->p[0]); |
} |
else |
repexpr(node->p[0]); |
break; |
case en_cbc: |
case en_cbh: |
case en_cbw: |
case en_cch: |
case en_ccw: |
case en_chw: |
case en_uminus: |
case en_not: case en_compl: |
case en_ainc: case en_adec: |
repexpr(node->p[0]); |
break; |
case en_add: case en_sub: |
case en_mul: case en_mulu: case en_div: case en_udiv: |
case en_mod: case en_shl: case en_shru: |
case en_shr: case en_and: |
case en_or: case en_xor: |
case en_land: case en_lor: |
case en_eq: case en_ne: |
case en_lt: case en_le: |
case en_gt: case en_ge: |
case en_cond: case en_void: |
case en_asadd: case en_assub: |
case en_asmul: case en_asdiv: |
case en_asor: case en_asand: |
case en_asmod: case en_aslsh: |
case en_asrsh: case en_fcall: |
case en_assign: |
repexpr(node->p[0]); |
repexpr(node->p[1]); |
break; |
} |
} |
|
/* |
* repcse will scan through a block of statements replacing the |
* optimized expressions with their temporary references. |
*/ |
void repcse(Statement *block) |
{ |
while( block != NULL ) { |
switch( block->stype ) { |
case st_return: |
case st_throw: |
repexpr(block->exp); |
break; |
case st_expr: |
repexpr(block->exp); |
break; |
case st_while: |
case st_until: |
case st_do: |
case st_dountil: |
repexpr(block->exp); |
case st_doloop: |
case st_forever: |
repcse(block->s1); |
repcse(block->s2); |
break; |
case st_for: |
repexpr(block->initExpr); |
repexpr(block->exp); |
repcse(block->s1); |
repexpr(block->incrExpr); |
break; |
case st_if: |
repexpr(block->exp); |
repcse(block->s1); |
repcse(block->s2); |
break; |
case st_switch: |
repexpr(block->exp); |
repcse(block->s1); |
break; |
case st_try: |
case st_catch: |
case st_case: |
repcse(block->s1); |
break; |
case st_spinlock: |
repcse(block->s1); |
repcse(block->s2); // lockfail statement |
break; |
} |
block = block->next; |
} |
} |
|
/* |
* opt1 is the externally callable optimization routine. it will |
* collect and allocate common subexpressions and substitute the |
* tempref for all occurrances of the expression within the block. |
* |
* optimizer is currently turned off... |
*/ |
void opt1(Statement *block) |
{ |
olist = NULL; |
scan(block); /* collect expressions */ |
AllocateRegisterVars(); /* allocate registers */ |
repcse(block); /* replace allocated expressions */ |
} |
/Symbol.c
0,0 → 1,81
// ============================================================================ |
// (C) 2012 Robert Finch |
// All Rights Reserved. |
// robfinch<remove>@opencores.org |
// |
// C64 - Raptor64 'C' derived language compiler |
// - 64 bit CPU |
// |
// This source file is free software: you can redistribute it and/or modify |
// it under the terms of the GNU Lesser General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or |
// (at your option) any later version. |
// |
// This source file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public License |
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
// |
// ============================================================================ |
// |
#include <stdio.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
static unsigned __int8 hashadd(char *nm) |
{ |
unsigned __int8 hsh; |
|
for(hsh=0;*nm;nm++) |
hsh += *nm; |
return hsh; |
} |
|
SYM *search(char *na,TABLE *tbl) |
{ |
SYM *thead; |
if (tbl==&gsyms[0]) |
thead = gsyms[hashadd(na)].head; |
else |
thead = tbl->head; |
while( thead != NULL) { |
if (thead->name != NULL) |
if(strcmp(thead->name,na) == 0) |
return thead; |
thead = thead->next; |
} |
return NULL; |
} |
|
SYM *gsearch(char *na) |
{ |
SYM *sp; |
|
if((sp = search(na,&lsyms)) == NULL) |
sp = search(na,&gsyms[0]); |
return sp; |
} |
|
void insert(SYM* sp, TABLE *table) |
{ |
if (table==&gsyms[0]) |
table = &gsyms[hashadd(sp->name)]; |
if( search(sp->name,table) == NULL) { |
if( table->head == NULL) |
table->head = table->tail = sp; |
else { |
table->tail->next = sp; |
table->tail = sp; |
} |
sp->next = NULL; |
} |
else |
error(ERR_DUPSYM); |
} |
/MemoryManagement.c
0,0 → 1,148
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
#define BLKSIZE 4000 |
|
struct blk { |
char name[8]; // string overwrite area |
struct blk *next; |
char m[1]; /* memory area */ |
}; |
|
static int glbsize = 0, /* size left in current global block */ |
locsize = 0, /* size left in current local block */ |
glbindx = 0, /* global index */ |
locindx = 0; /* local index */ |
|
static struct blk *locblk = 0, /* pointer to local block */ |
*glbblk = 0; /* pointer to global block */ |
|
char *xalloc(int siz) |
{ |
struct blk *bp; |
char *rv; |
|
while(siz % 8) // align word |
siz++; |
if( global_flag ) { |
if( glbsize >= siz ) { |
rv = &(glbblk->m[glbindx]); |
glbsize -= siz; |
glbindx += siz; |
return rv; |
} |
else { |
bp = calloc(1,sizeof(struct blk) + BLKSIZE); |
if( bp == NULL ) |
{ |
printf(" not enough memory.\n"); |
exit(1); |
} |
strcpy(bp->name,"C64 "); |
bp->next = glbblk; |
glbblk = bp; |
glbsize = BLKSIZE - siz; |
glbindx = siz; |
return glbblk->m; |
} |
} |
else { |
if( locsize >= siz ) { |
rv = &(locblk->m[locindx]); |
locsize -= siz; |
locindx += siz; |
return rv; |
} |
else { |
bp = calloc(1,sizeof(struct blk) + BLKSIZE); |
if( bp == NULL ) |
{ |
printf(" not enough local memory.\n"); |
exit(1); |
} |
strcpy(bp->name,"C64 "); |
bp->next = locblk; |
locblk = bp; |
locsize = BLKSIZE - siz; |
locindx = siz; |
return locblk->m; |
} |
} |
} |
|
void ReleaseLocalMemory() |
{ |
struct blk *bp1, *bp2; |
int blkcnt; |
blkcnt = 0; |
bp1 = locblk; |
while( bp1 != NULL ) { |
bp2 = bp1->next; |
free( bp1 ); |
++blkcnt; |
bp1 = bp2; |
} |
locblk = NULL; |
locsize = 0; |
lsyms.head = NULL; |
lsyms.tail = NULL; |
printf(" releasing %d bytes local tables.\n",blkcnt * BLKSIZE); |
} |
|
void ReleaseGlobalMemory() |
{ |
struct blk *bp1, *bp2; |
int blkcnt; |
bp1 = glbblk; |
blkcnt = 0; |
while( bp1 != 0 ) { |
bp2 = bp1->next; |
free(bp1); |
++blkcnt; |
bp1 = bp2; |
} |
glbblk = NULL; |
glbsize = 0; |
// gsyms.head = NULL; /* clear global symbol table */ |
// gsyms.tail = NULL; |
memset(gsyms,0,sizeof(gsyms)); |
printf(" releasing %d bytes global tables.\n",blkcnt * BLKSIZE); |
strtab = 0; /* clear literal table */ |
} |
|
SYM *allocSYM() { return (SYM *)xalloc(sizeof(SYM)); }; |
TYP *allocTYP() { return (TYP *)xalloc(sizeof(TYP)); }; |
struct snode *allocSnode() { return (struct snode *)xalloc(sizeof(struct snode)); }; |
ENODE *allocEnode() { return (ENODE *)xalloc(sizeof(ENODE)); }; |
AMODE *allocAmode() { return (AMODE *)xalloc(sizeof(AMODE)); }; |
CSE *allocCSE() { return (CSE *)xalloc(sizeof(CSE)); }; |
|
/Initializers.c
0,0 → 1,219
#include <stdio.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
int InitializeType(TYP *tp); |
int InitializeStructure(TYP *tp); |
int initbyte(); |
int initchar(); |
int initshort(); |
int initlong(); |
int InitializePointer(); |
void endinit(); |
int InitializeArray(TYP *tp); |
|
void doinit(SYM *sp) |
{ |
dseg(); /* initialize into data segment */ |
nl(); /* start a new line in object */ |
if(sp->storage_class == sc_static) |
put_label(sp->value.i); |
else |
gen_strlab(sp->name); |
if( lastst != assign) { |
genstorage(sp->tp->size); |
} |
else { |
NextToken(); |
InitializeType(sp->tp); |
} |
endinit(); |
} |
|
int InitializeType(TYP *tp) |
{ |
int nbytes; |
|
switch(tp->type) { |
case bt_byte: |
nbytes = initbyte(); |
break; |
case bt_char: |
case bt_enum: |
nbytes = initchar(); |
break; |
case bt_short: |
nbytes = initshort(); |
break; |
case bt_pointer: |
if( tp->val_flag) |
nbytes = InitializeArray(tp); |
else |
nbytes = InitializePointer(); |
break; |
case bt_long: |
nbytes = initlong(); |
break; |
case bt_struct: |
nbytes = InitializeStructure(tp); |
break; |
default: |
error(ERR_NOINIT); |
nbytes = 0; |
} |
return nbytes; |
} |
|
int InitializeArray(TYP *tp) |
{ |
int nbytes; |
char *p; |
|
nbytes = 0; |
if( lastst == begin) { |
NextToken(); /* skip past the brace */ |
while(lastst != end) { |
nbytes += InitializeType(tp->btp); |
if( lastst == comma) |
NextToken(); |
else if( lastst != end) |
error(ERR_PUNCT); |
} |
NextToken(); /* skip closing brace */ |
} |
else if( lastst == sconst && tp->btp->type == bt_char) { |
nbytes = strlen(laststr) * 2 + 2; |
p = laststr; |
while( *p ) |
GenerateChar(*p++); |
GenerateChar(0); |
NextToken(); |
} |
else if( lastst != semicolon) |
error(ERR_ILLINIT); |
if( nbytes < tp->size) { |
genstorage( tp->size - nbytes); |
nbytes = tp->size; |
} |
else if( tp->size != 0 && nbytes > tp->size) |
error(ERR_INITSIZE); /* too many initializers */ |
return nbytes; |
} |
|
int InitializeStructure(TYP *tp) |
{ |
SYM *sp; |
int nbytes; |
|
needpunc(begin); |
nbytes = 0; |
sp = tp->lst.head; /* start at top of symbol table */ |
while(sp != 0) { |
while(nbytes < sp->value.i) { /* align properly */ |
// nbytes += GenerateByte(0); |
GenerateByte(0); |
// nbytes++; |
} |
nbytes += InitializeType(sp->tp); |
if( lastst == comma) |
NextToken(); |
else if(lastst == end) |
break; |
else |
error(ERR_PUNCT); |
sp = sp->next; |
} |
if( nbytes < tp->size) |
genstorage( tp->size - nbytes); |
needpunc(end); |
return tp->size; |
} |
|
int initbyte() |
{ |
GenerateByte(GetIntegerExpression()); |
return 1; |
} |
|
int initchar() |
{ |
GenerateChar(GetIntegerExpression()); |
return 2; |
} |
|
int initshort() |
{ |
GenerateWord(GetIntegerExpression()); |
return 4; |
} |
|
int initlong() |
{ |
GenerateLong(GetIntegerExpression()); |
return 8; |
} |
|
int InitializePointer() |
{ |
SYM *sp; |
|
if(lastst == and) { /* address of a variable */ |
NextToken(); |
if( lastst != id) |
error(ERR_IDEXPECT); |
else if( (sp = gsearch(lastid)) == NULL) |
error(ERR_UNDEFINED); |
else { |
NextToken(); |
if( lastst == plus || lastst == minus) |
GenerateReference(sp,GetIntegerExpression()); |
else |
GenerateReference(sp,0); |
if( sp->storage_class == sc_auto) |
error(ERR_NOINIT); |
} |
} |
else if(lastst == sconst) { |
GenerateLabelReference(stringlit(laststr)); |
NextToken(); |
} |
else |
GenerateLong(GetIntegerExpression()); |
endinit(); |
return 8; /* pointers are 4 bytes long */ |
} |
|
void endinit() |
{ |
if( lastst != comma && lastst != semicolon && lastst != end) { |
error(ERR_PUNCT); |
while( lastst != comma && lastst != semicolon && lastst != end) |
NextToken(); |
} |
} |
/Statement.h
0,0 → 1,22
/* statement node descriptions */ |
|
enum e_stmt { |
st_expr, st_while, |
st_until, st_forever, st_firstcall, st_asm, |
st_dountil, st_doloop, |
st_try, st_catch, st_throw, st_critical, st_spinlock, st_spinunlock, |
st_for, |
st_do, st_if, st_switch, st_default, |
st_case, st_goto, st_break, st_continue, st_label, |
st_return, st_vortex, st_intoff, st_inton, st_stop }; |
|
typedef struct snode { |
__int8 stype; |
struct snode *next; /* next statement */ |
ENODE *exp; /* condition or expression */ |
ENODE *initExpr; /* initialization expression - for loops */ |
ENODE *incrExpr; /* increment expression - for loops */ |
struct snode *s1, *s2; /* internal statements */ |
__int64 *label; /* label number for goto */ |
} Statement; |
|
/Code.h
0,0 → 1,26
/* |
* code structure definitions. |
*/ |
|
enum address_mode { |
am_const, am_label, am_string, am_temp, am_auto, |
am_defcon, am_deflab, am_defstr, am_deftemp, am_defauto, |
am_none }; |
|
enum instruction { |
i_move, i_add, i_sub, i_mul, i_div, i_mod, i_and, i_or, |
i_xor, i_shl, i_shr, i_jmp, i_jeq, i_jne, i_jlt, i_jle, |
i_jgt, i_jge, i_call, i_enter, i_ret, i_table, i_label }; |
|
union aval { |
int i; |
char *s; |
}; |
|
struct inst { |
struct inst *fwd, *back; |
int opcode, size; |
char sm0, sm1, dm; |
union aval sv0, sv1, dv; |
}; |
|
/ParseFunction.c
0,0 → 1,191
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Copyright 2012 Robert Finch |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
|
extern int funcdecl; |
extern char *names[20]; |
extern int nparms; |
|
void ParseFunctionBody(SYM *sp); |
void funcbottom(); |
|
/* function compilation routines */ |
|
/* |
* funcbody starts with the current symbol being either |
* the first parameter id or the begin for the local |
* block. If begin is the current symbol then funcbody |
* assumes that the function has no parameters. |
*/ |
void ParseFunction(SYM *sp) |
{ |
int poffset, i; |
int oldglobal; |
SYM *sp1, *sp2, *makeint(); |
|
oldglobal = global_flag; |
global_flag = 0; |
poffset = 24; /* size of return block */ |
nparms = 0; |
if(lastst == id || 1) { /* declare parameters */ |
//while(lastst == id) { |
// names[nparms++] = litlate(lastid); |
// NextToken(); |
// if( lastst == comma) |
// NextToken(); |
// else |
// break; |
// } |
//needpunc(closepa); |
// dodecl(sc_member); /* declare parameters */ |
sp->parms = NULL; |
ParseParameterDeclarations(1); |
for(i = 0;i < nparms;++i) { |
if( (sp1 = search(names[i],&lsyms)) == NULL) |
sp1 = makeint(names[i]); |
//if( sp1->tp->size < 8 ) |
//{ |
// sp1->value.i = poffset;// + (8 - sp1->tp->size); |
// poffset += 8; |
//} |
//else |
//{ |
// sp1->value.i = poffset; |
// poffset += sp1->tp->size; |
//} |
sp1->value.i = poffset; |
poffset += 8; |
sp1->storage_class = sc_auto; |
sp1->nextparm = NULL; |
// record parameter list |
if (sp->parms == NULL) { |
sp->parms = sp1; |
} |
else { |
sp1->nextparm = sp->parms; |
sp->parms = sp1; |
} |
} |
} |
if (lastst == closepa) |
NextToken(); |
if (lastst == semicolon) { // Function prototype |
sp->IsPrototype = 1; |
sp->IsNocall = isNocall; |
sp->IsPascal = isPascal; |
sp->IsInterrupt = isInterrupt; |
sp->NumParms = nparms; |
isPascal = FALSE; |
isOscall = FALSE; |
isInterrupt = FALSE; |
isNocall = FALSE; |
ReleaseLocalMemory(); /* release local symbols (parameters)*/ |
} |
else if(lastst != begin) { |
NextToken(); |
ParseParameterDeclarations(2); |
sp->IsNocall = isNocall; |
sp->IsPascal = isPascal; |
sp->IsInterrupt = isInterrupt; |
sp->NumParms = nparms; |
ParseFunctionBody(sp); |
funcbottom(); |
} |
// error(ERR_BLOCK); |
else { |
sp->IsNocall = isNocall; |
sp->IsPascal = isPascal; |
sp->IsInterrupt = isInterrupt; |
sp->NumParms = nparms; |
ParseFunctionBody(sp); |
funcbottom(); |
} |
global_flag = oldglobal; |
} |
|
SYM *makeint(char *name) |
{ SYM *sp; |
TYP *tp; |
sp = allocSYM(); |
tp = allocTYP(); |
tp->type = bt_long; |
tp->size = 8; |
tp->btp = 0; |
tp->lst.head = 0; |
tp->sname = 0; |
sp->name = name; |
sp->storage_class = sc_auto; |
sp->tp = tp; |
sp->IsPrototype = FALSE; |
insert(sp,&lsyms); |
return sp; |
} |
|
void check_table(SYM *head) |
{ |
while( head != 0 ) { |
if( head->storage_class == sc_ulabel ) |
fprintf(list,"*** UNDEFINED LABEL - %s\n",head->name); |
head = head->next; |
} |
} |
|
void funcbottom() |
{ |
nl(); |
check_table(&lsyms); |
lc_auto = 0; |
fprintf(list,"\n\n*** local symbol table ***\n\n"); |
ListTable(&lsyms,0); |
fprintf(list,"\n\n\n"); |
ReleaseLocalMemory(); /* release local symbols */ |
isPascal = FALSE; |
isOscall = FALSE; |
isInterrupt = FALSE; |
isNocall = FALSE; |
} |
|
void ParseFunctionBody(SYM *sp) |
{ |
needpunc(begin); |
ParseAutoDeclarations(); |
cseg(); |
if (sp->storage_class == sc_static) |
put_label((unsigned int) sp->value.i); |
else |
gen_strlab(sp->name); |
currentFn = sp; |
currentFn->IsLeaf = TRUE; |
currentFn->DoesThrow = FALSE; |
GenerateFunction(sp, ParseCompoundStatement()); |
// if (optimize) |
flush_peep(); |
} |
/IdentifyKeyword.c
0,0 → 1,208
// ============================================================================ |
// (C) 2012 Robert Finch |
// All Rights Reserved. |
// robfinch<remove>@opencores.org |
// |
// C64 - Raptor64 'C' derived language compiler |
// - 64 bit CPU |
// |
// This source file is free software: you can redistribute it and/or modify |
// it under the terms of the GNU Lesser General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or |
// (at your option) any later version. |
// |
// This source file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public License |
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
// |
// ============================================================================ |
// |
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
int IdentifyKeyword() |
{ |
char *p = lastid; |
|
if (p[0]=='i') { // if,int,inton,intoff,interrupt,icache |
if (p[1]=='f' && p[2]=='\0') |
return lastst = kw_if; |
if (p[1]=='n' && p[2]=='t' && p[3]=='\0') |
return lastst = kw_int; |
if (p[1]=='n' && p[2]=='t' && p[3]=='o' && p[4]=='n' && p[5]=='\0') |
return lastst = kw_inton; |
if (p[1]=='n' && p[2]=='t' && p[3]=='o' && p[4]=='f' && p[5]=='f' && p[6]=='\0') |
return lastst = kw_intoff; |
if (p[1]=='n' && p[2]=='t' && p[3]=='e' && p[4]=='r' && p[5]=='r' && p[6]=='u' && p[7]=='p' && p[8]=='t' && p[9]=='\0') |
return lastst = kw_interrupt; |
if (p[1]=='c' && p[2]=='a' && p[3]=='c' && p[4]=='h' && p[5]=='e' && p[6]=='\0') |
return lastst = kw_icache; |
} |
|
if (p[0]=='b' && p[1]=='r' && p[2]=='e' && p[3]=='a' && p[4]=='k' && p[5]=='\0') |
return lastst = kw_break; |
if (p[0]=='b' && p[1]=='y' && p[2]=='t' && p[3]=='e' && p[4]=='\0') |
return lastst = kw_byte; |
if (p[0]=='w' && p[1]=='h' && p[2]=='i' && p[3]=='l' && p[4]=='e' && p[5]=='\0') |
return lastst = kw_while; |
|
if (p[0]=='d') { // do,default,double,dcache |
if (p[1]=='o' && p[2]=='\0') |
return lastst = kw_do; |
if (p[1]=='o' && p[2]=='u' && p[3]=='b' && p[4]=='l' && p[5]=='e' && p[6]=='\0') |
return lastst = kw_double; |
if (p[1]=='e' && p[2]=='f' && p[3]=='a' && p[4]=='u' && p[5]=='l' && p[6]=='t' && p[7]=='\0') |
return lastst = kw_default; |
if (p[1]=='c' && p[2]=='a' && p[3]=='c' && p[4]=='h' && p[5]=='e' && p[6]=='\0') |
return lastst = kw_dcache; |
} |
|
if (p[0]=='o') { // or,oscall |
if (p[1]=='r' && p[2]=='\0') |
return lastst = lor; |
if (p[1]=='s' && p[2]=='c' && p[3]=='a' && p[4]=='l' && p[5]=='l' && p[6]=='\0') |
return lastst = kw_oscall; |
} |
|
if (p[0]=='c') { // case,catch,char,continue |
if(p[1]=='a' && p[2]=='s' && p[3]=='e' && p[4]=='\0') |
return lastst = kw_case; |
if(p[1]=='a' && p[2]=='t' && p[3]=='c' && p[4]=='h' && p[5]=='\0') |
return lastst = kw_catch; |
if(p[1]=='h' && p[2]=='a' && p[3]=='r' && p[4]=='\0') |
return lastst = kw_char; |
if (p[1]=='o' && p[2]=='n' && p[3]=='t' && p[4]=='i' && p[5]=='n' && p[6]=='u' && p[7]=='e' && p[8]=='\0') |
return lastst = kw_continue; |
if (p[1]=='r' && p[2]=='i' && p[3]=='t' && p[4]=='i' && p[5]=='c' && p[6]=='a' && p[7]=='l' && p[8]=='\0') |
return lastst = kw_critical; |
} |
|
if (p[0]=='l') { // long,loop,lockfail |
if (p[1]=='o' && p[2]=='n' && p[3]=='g' && p[4]=='\0') |
return lastst = kw_long; |
if (p[1]=='o' && p[2]=='o' && p[3]=='p' && p[4]=='\0') |
return lastst = kw_loop; |
if (p[1]=='o' && p[2]=='c' && p[3]=='k' && p[4]=='f' && p[5]=='a' && p[6]=='i' && p[7]=='l' && p[8]=='\0') |
return lastst = kw_lockfail; |
} |
|
if (p[0]=='s') { // switch,short,static,stop,struct,sizeof,signed |
if (p[1]=='w' && p[2]=='i' && p[3]=='t' && p[4]=='c' && p[5]=='h' && p[6]=='\0') |
return lastst = kw_switch; |
if (p[1]=='t' && p[2]=='a' && p[3]=='t' && p[4]=='i' && p[5]=='c' && p[6]=='\0') |
return lastst = kw_static; |
if (p[1]=='h' && p[2]=='o' && p[3]=='r' && p[4]=='t' && p[5]=='\0') |
return lastst = kw_short; |
if (p[1]=='t' && p[2]=='o' && p[3]=='p' && p[4]=='\0') |
return lastst = kw_stop; |
if (p[1]=='t' && p[2]=='r' && p[3]=='u' && p[4]=='c' && p[5]=='t' && p[6]=='\0') |
return lastst = kw_struct; |
if (p[1]=='i' && p[2]=='z' && p[3]=='e' && p[4]=='o' && p[5]=='f' && p[6]=='\0') |
return lastst = kw_sizeof; |
if (p[1]=='i' && p[2]=='g' && p[3]=='n' && p[4]=='e' && p[5]=='d' && p[6]=='\0') |
return lastst = kw_signed; |
} |
|
if (p[0]=='t') { // typedef,typenum,throw,then,try |
if (p[1]=='y' && p[2]=='p' && p[3]=='e' && p[4]=='d' && p[5]=='e' && p[6]=='f' && p[7]=='\0') |
return lastst = kw_typedef; |
if (p[1]=='y' && p[2]=='p' && p[3]=='e' && p[4]=='n' && p[5]=='u' && p[6]=='n' && p[7]=='\0') |
return lastst = kw_typenum; |
if (p[1]=='h' && p[2]=='r' && p[3]=='o' && p[4]=='w' && p[5]=='\0') |
return lastst = kw_throw; |
if (p[1]=='h' && p[2]=='e' && p[3]=='n' && p[4]=='\0') |
return lastst = kw_then; |
if (p[1]=='r' && p[2]=='y' && p[3]=='\0') |
return lastst = kw_try; |
} |
|
if (p[0]=='g' && p[1]=='o' && p[2]=='t' && p[3]=='o' && p[4]=='\0') |
return lastst = kw_goto; |
if (p[0]=='j' && p[1]=='u' && p[2]=='m' && p[3]=='p' && p[4]=='\0') |
return lastst = kw_goto; |
|
if (p[0]=='e') { // else,enum,extern |
if (p[1]=='l' && p[2]=='s' && p[3]=='e' && p[4]=='\0') |
return lastst = kw_else; |
if (p[1]=='l' && p[2]=='s' && p[3]=='i' && p[4]=='f' && p[5]=='\0') |
return lastst = kw_elsif; |
if (p[1]=='n' && p[2]=='u' && p[3]=='m' && p[4]=='\0') |
return lastst = kw_enum; |
if (p[1]=='x' && p[2]=='t' && p[3]=='e' && p[4]=='r' && p[5]=='n' && p[6]=='\0') |
return lastst = kw_extern; |
} |
if (p[0]=='a') { // and,asm |
if (p[1]=='n' && p[2]=='d' && p[3]=='\0') |
return lastst = land; |
if (p[1]=='s' && p[2]=='m' && p[3]=='\0') |
return lastst = kw_asm; |
} |
if (p[0]=='v' && p[1]=='o' && p[2]=='i' && p[3]=='d' && p[4]=='\0') |
return lastst = kw_void; |
if (p[0]=='r' && p[1]=='e') { // return,register |
if (p[2]=='t' && p[3]=='u' && p[4]=='r' && p[5]=='n' && p[6]=='\0') |
return lastst = kw_return; |
if (p[2]=='g' && p[3]=='i' && p[4]=='s' && p[5]=='t' && p[6]=='e' && p[7]=='r' && p[8]=='\0') |
return lastst = kw_register; |
} |
if (p[0]=='l' && p[1]=='o' && p[2]=='o' && p[3]=='p' && p[4]=='\0') |
return lastst = kw_loop; |
if (p[0]=='u') { // unsigned,union,until |
if (p[1]=='n' && p[2]=='s' && p[3]=='i' && p[4]=='g' && p[5]=='n' && p[6]=='e' && p[7]=='d' && p[8]=='\0') |
return lastst = kw_unsigned; |
if (p[1]=='n' && p[2]=='i' && p[3]=='o' && p[4]=='n' && p[5]=='\0') |
return lastst = kw_union; |
if (p[1]=='n' && p[2]=='t' && p[3]=='i' && p[4]=='l' && p[5]=='\0') |
return lastst = kw_until; |
} |
if (p[0]=='f') { // float,forever,for,fallthru,firstcall |
if (p[1]=='o' && p[2]=='r' && p[3]=='\0') |
return lastst = kw_for; |
if (p[1]=='l' && p[2]=='o' && p[3]=='a' && p[4]=='t' && p[5]=='\0') |
return lastst = kw_float; |
if (p[1]=='o' && p[2]=='r' && p[3]=='e' && p[4]=='v' && p[5]=='e' && p[6]=='r' && p[7]=='\0') |
return lastst = kw_forever; |
if (p[1]=='a' && p[2]=='l' && p[3]=='l' && p[4]=='t' && p[5]=='h' && p[6]=='r' && p[7]=='u' && p[8]=='\0') |
return lastst = kw_fallthru; |
if (p[1]=='i' && p[2]=='r' && p[3]=='s' && p[4]=='t' && p[5]=='c' && p[6]=='a' && p[7]=='l' && p[8]=='l' && p[9]=='\0') |
return lastst = kw_firstcall; |
} |
if (p[0]=='m' && p[1]=='o' && p[2]=='d' && p[3]=='\0') |
return lastst = modop; |
|
if (p[0]=='p') { // private,public,pascal |
if (p[1]=='r' && p[2]=='i' && p[3]=='v' && p[4]=='a' && p[5]=='t' && p[6]=='e' && p[7]=='\0') |
return lastst = kw_private; |
if (p[1]=='u' && p[2]=='b' && p[3]=='l' && p[4]=='i' && p[5]=='c' && p[6]=='\0') |
return lastst = kw_public; |
if (p[1]=='a' && p[2]=='s' && p[3]=='c' && p[4]=='a' && p[5]=='l' && p[6]=='\0') |
return lastst = kw_pascal; |
} |
if (p[0]=='n') { // nocall |
if (p[1]=='o' && p[2]=='c' && p[3]=='a' && p[4]=='l' && p[5]=='l' && p[6]=='\0') |
return lastst = kw_nocall; |
} |
// __spinlock,__spinunlock |
if (p[0]=='s' && p[1]=='p' && p[2]=='i' && p[3]=='n' && p[4]=='l' && p[5]=='o' && p[6]=='c' && p[7]=='k' && p[8]=='\0') |
return lastst = kw_spinlock; |
if (p[0]=='s' && p[1]=='p' && p[2]=='i' && p[3]=='n' && p[4]=='u' && p[5]=='n' && p[6]=='l' && p[7]=='o' && p[8]=='c' && p[9]=='k' && p[10]=='\0') |
return lastst = kw_spinunlock; |
|
if (p[0]=='f' && p[1]=='a' && p[2]=='l' && p[3]=='s' && p[4]=='e' && p[5]=='\0') { |
ival = 0; |
return lastst = iconst; |
} |
if (p[0]=='t' && p[1]=='r' && p[2]=='u' && p[3]=='e' && p[4]=='\0') { |
ival = 1; |
return lastst = iconst; |
} |
|
return 0; |
} |
/CodeGenerator.c
0,0 → 1,1197
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
|
/* |
* this module contains all of the code generation routines |
* for evaluating expressions and conditions. |
*/ |
|
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
AMODE *GenerateExpression(); /* forward ParseSpecifieraration */ |
|
extern int throwlab; |
/* |
* construct a reference node for an internal label number. |
*/ |
AMODE *make_label(__int64 lab) |
{ |
struct enode *lnode; |
struct amode *ap; |
lnode = xalloc(sizeof(struct enode)); |
lnode->nodetype = en_labcon; |
lnode->i = lab; |
ap = xalloc(sizeof(struct amode)); |
ap->mode = am_direct; |
ap->offset = lnode; |
return ap; |
} |
|
AMODE *make_string(char *s) |
{ |
ENODE *lnode; |
AMODE *ap; |
|
lnode = xalloc(sizeof(struct enode)); |
lnode->nodetype = en_nacon; |
lnode->sp = s; |
ap = allocAmode(); |
ap->mode = am_direct; |
ap->offset = lnode; |
return ap; |
} |
|
/* |
* make a node to reference an immediate value i. |
*/ |
AMODE *make_immed(__int64 i) |
{ |
AMODE *ap; |
ENODE *ep; |
ep = xalloc(sizeof(struct enode)); |
ep->nodetype = en_icon; |
ep->i = i; |
ap = allocAmode(); |
ap->mode = am_immed; |
ap->offset = ep; |
return ap; |
} |
|
AMODE *make_indirect(int i) |
{ |
AMODE *ap; |
ENODE *ep; |
ep = xalloc(sizeof(struct enode)); |
ep->nodetype = en_uw_ref; |
ep->i = 0; |
ap = allocAmode(); |
ap->mode = am_ind; |
ap->preg = i; |
ap->offset = ep; |
return ap; |
} |
|
AMODE *make_indexed(__int64 o, int i) |
{ |
AMODE *ap; |
ENODE *ep; |
ep = xalloc(sizeof(struct enode)); |
ep->nodetype = en_icon; |
ep->i = o; |
ap = allocAmode(); |
ap->mode = am_indx; |
ap->preg = i; |
ap->offset = ep; |
return ap; |
} |
|
/* |
* make a direct reference to a node. |
*/ |
AMODE *make_offset(ENODE *node) |
{ |
AMODE *ap; |
ap = allocAmode(); |
ap->mode = am_direct; |
ap->offset = node; |
return ap; |
} |
|
/* |
* MakeLegalAmode will coerce the addressing mode in ap1 into a |
* mode that is satisfactory for the flag word. |
*/ |
void MakeLegalAmode(AMODE *ap,int flags, int size) |
{ |
AMODE *ap2; |
__int64 i; |
|
if (ap==NULL) return; |
if( ((flags & F_VOL) == 0) || ap->tempflag ) |
{ |
switch( ap->mode ) { |
case am_immed: |
i = ((ENODE *)(ap->offset))->i; |
if (flags & F_IMMED18) { |
if (i < 0x1ffff && i > -0x1ffff) |
return; |
} |
else if( flags & F_IMMED ) |
return; /* mode ok */ |
break; |
case am_reg: |
if( flags & F_REG ) |
return; |
break; |
case am_ind: |
case am_indx: |
case am_indx2: |
case am_direct: |
case am_indx3: |
if( flags & F_MEM ) |
return; |
break; |
} |
} |
|
if( flags & F_REG ) |
{ |
ReleaseTempRegister(ap); /* maybe we can use it... */ |
ap2 = GetTempRegister(); /* AllocateRegisterVars to dreg */ |
if (ap->mode == am_ind || ap->mode==am_indx) { |
switch(size) { |
case 1: GenerateDiadic(op_lb,0,ap2,ap); break; |
case 2: GenerateDiadic(op_lc,0,ap2,ap); break; |
case 4: GenerateDiadic(op_lh,0,ap2,ap); break; |
case 8: GenerateDiadic(op_lw,0,ap2,ap); break; |
} |
} |
else if (ap->mode==am_immed) |
GenerateTriadic(op_ori,0,ap2,makereg(0),ap); |
else { |
if (ap->mode==am_reg) |
GenerateTriadic(op_or,0,ap2,ap,makereg(0)); |
else { |
switch(size) { |
case 1: GenerateDiadic(op_lb,0,ap2,ap); break; |
case 2: GenerateDiadic(op_lc,0,ap2,ap); break; |
case 4: GenerateDiadic(op_lh,0,ap2,ap); break; |
case 8: GenerateDiadic(op_lw,0,ap2,ap); break; |
} |
} |
} |
ap->mode = am_reg; |
ap->preg = ap2->preg; |
ap->deep = ap2->deep; |
ap->tempflag = 1; |
return; |
} |
if( size == 1 ) |
{ |
ReleaseTempRegister(ap); |
ap2 = GetTempRegister(); |
GenerateTriadic(op_or,0,ap2,ap,makereg(0)); |
GenerateTriadic(op_sext8,0,ap2,ap2,NULL); |
ap->mode = ap2->mode; |
ap->preg = ap2->preg; |
ap->deep = ap2->deep; |
size = 2; |
} |
ap2 = GetTempRegister(); |
switch(ap->mode) { |
case am_ind: |
case am_indx: |
switch(size) { |
case 1: GenerateDiadic(op_lb,0,ap2,ap); break; |
case 2: GenerateDiadic(op_lc,0,ap2,ap); break; |
case 4: GenerateDiadic(op_lh,0,ap2,ap); break; |
case 8: GenerateDiadic(op_lw,0,ap2,ap); break; |
} |
break; |
case am_immed: |
GenerateTriadic(op_ori,0,ap2,makereg(0),ap); |
case am_reg: |
GenerateTriadic(op_or,0,ap2,ap,makereg(0)); |
default: |
switch(size) { |
case 1: GenerateDiadic(op_lb,0,ap2,ap); break; |
case 2: GenerateDiadic(op_lc,0,ap2,ap); break; |
case 4: GenerateDiadic(op_lh,0,ap2,ap); break; |
case 8: GenerateDiadic(op_lw,0,ap2,ap); break; |
} |
} |
ap->mode = am_reg; |
ap->preg = ap2->preg; |
ap->deep = ap2->deep; |
ap->tempflag = 1; |
} |
|
/* |
* if isize is not equal to osize then the operand ap will be |
* loaded into a register (if not already) and if osize is |
* greater than isize it will be extended to match. |
*/ |
void GenerateSignExtend(AMODE *ap, int isize, int osize, int flags) |
{ |
struct amode *ap2; |
|
if( isize == osize ) |
return; |
if(ap->mode != am_reg) |
MakeLegalAmode(ap,flags & F_REG,isize); |
switch( isize ) |
{ |
case 1: GenerateDiadic(op_sext8,0,ap,ap); break; |
case 2: GenerateDiadic(op_sext16,0,ap,ap); break; |
case 4: GenerateDiadic(op_sext32,0,ap,ap); break; |
} |
} |
|
/* |
* return true if the node passed can be generated as a short |
* offset. |
*/ |
int isshort(ENODE *node) |
{ |
return node->nodetype == en_icon && |
(node->i >= -32768 && node->i <= 32767); |
} |
|
/* |
* return true if the node passed can be evaluated as a byte |
* offset. |
*/ |
int isbyte(ENODE *node) |
{ |
return node->nodetype == en_icon && |
(-128 <= node->i && node->i <= 127); |
} |
|
int ischar(ENODE *node) |
{ |
return node->nodetype == en_icon && |
(node->i >= -32768 && node->i <= 32767); |
} |
|
/* |
* generate code to evaluate an index node (^+) and return |
* the addressing mode of the result. This routine takes no |
* flags since it always returns either am_ind or am_indx. |
*/ |
AMODE *GenerateIndex(ENODE *node) |
{ |
AMODE *ap1, *ap2, *ap3; |
|
if( (node->p[0]->nodetype == en_tempref || node->p[0]->nodetype==en_regvar) && (node->p[1]->nodetype == en_tempref || node->p[1]->nodetype==en_regvar)) |
{ /* both nodes are registers */ |
ap1 = GenerateExpression(node->p[0],F_REG,8); |
ap2 = GenerateExpression(node->p[1],F_REG,8); |
ap1->mode = am_indx2; |
ap1->sreg = ap2->preg; |
ap1->offset = makeinode(en_icon,0); |
return ap1; |
} |
ap1 = GenerateExpression(node->p[0],F_REG | F_IMMED,8); |
if( ap1->mode == am_immed ) |
{ |
ap2 = GenerateExpression(node->p[1],F_REG,8); |
ap2->mode = am_indx; |
ap2->offset = ap1->offset; |
ReleaseTempRegister(ap1); |
return ap2; |
} |
ap2 = GenerateExpression(node->p[1],F_ALL,8); /* get right op */ |
if( ap2->mode == am_immed && ap1->mode == am_reg ) /* make am_indx */ |
{ |
ap2->mode = am_indx; |
ReleaseTempRegister(ap2); |
ap2->preg = ap1->preg; |
ap2->deep = ap1->deep; |
return ap2; |
} |
// ap1->mode must be F_REG |
MakeLegalAmode(ap2,F_REG,8); |
// ap3 = GetTempRegister(); |
// GenerateTriadic(op_addu,0,ap3,ap1,ap2); /* add left to address reg */ |
ap1->mode = am_indx2; /* make indirect */ |
ap1->sreg = ap2->preg; |
ap1->offset = makeinode(en_icon,0); |
// ReleaseTempRegister(ap2); /* release any temps in ap2 */ |
// ReleaseTempRegister(ap1); |
return ap1; /* return indirect */ |
} |
|
long GetReferenceSize(ENODE *node) |
{ |
switch( node->nodetype ) /* get load size */ |
{ |
case en_b_ref: |
case en_ub_ref: |
case en_bfieldref: |
case en_ubfieldref: |
return 1; |
case en_c_ref: |
case en_uc_ref: |
case en_cfieldref: |
case en_ucfieldref: |
return 2; |
case en_h_ref: |
case en_uh_ref: |
case en_hfieldref: |
case en_uhfieldref: |
return 4; |
case en_w_ref: |
case en_uw_ref: |
case en_wfieldref: |
case en_uwfieldref: |
case en_tempref: |
case en_regvar: |
return 8; |
} |
return 8; |
} |
|
/* |
* return the addressing mode of a dereferenced node. |
*/ |
AMODE *GenerateDereference(ENODE *node,int flags,int size) |
{ |
struct amode *ap1; |
int siz1; |
|
siz1 = GetReferenceSize(node); |
if( node->p[0]->nodetype == en_add ) |
{ |
ap1 = GenerateIndex(node->p[0]); |
GenerateSignExtend(ap1,siz1,size,flags); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
else if( node->p[0]->nodetype == en_autocon ) |
{ |
ap1 = xalloc(sizeof(struct amode)); |
ap1->mode = am_indx; |
ap1->preg = 27; |
ap1->offset = makeinode(en_icon,node->p[0]->i); |
GenerateSignExtend(ap1,siz1,size,flags); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
ap1 = GenerateExpression(node->p[0],F_REG | F_IMMED,4); /* generate address */ |
if( ap1->mode == am_reg ) |
{ |
ap1->mode = am_ind; |
GenerateSignExtend(ap1,siz1,size,flags); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
ap1->mode = am_direct; |
GenerateSignExtend(ap1,siz1,size,flags); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
|
void SignExtendBitfield(ENODE *node, struct amode *ap3, __int64 mask) |
{ |
struct amode *ap2; |
__int64 umask; |
|
umask = 0x8000000000000000L | ~(mask >> 1); |
ap2 = GetTempRegister(); |
GenerateTriadic(op_ori,0,ap2,makereg(0),make_immed(umask)); |
GenerateTriadic(op_add,0,ap3,ap3,ap2); |
GenerateTriadic(op_xor,0,ap3,ap3,ap2); |
ReleaseTempRegister(ap2); |
} |
|
AMODE *GenerateBitfieldDereference(ENODE *node, int flags, int size) |
{ |
AMODE *ap, *ap1,*ap2,*ap3; |
long mask,umask; |
int width = node->bit_width + 1; |
int isSigned; |
|
isSigned = node->nodetype==en_wfieldref || node->nodetype==en_hfieldref || node->nodetype==en_cfieldref || node->nodetype==en_bfieldref; |
mask = 0; |
while (--width) mask = mask + mask + 1; |
ap = GenerateDereference(node, flags, node->esize); |
MakeLegalAmode(ap, flags, node->esize); |
ap3 = GetTempRegister(); |
GenerateTriadic(op_or,0,ap3,ap,makereg(0)); |
ReleaseTempRegister(ap); |
if (node->bit_offset > 0) { |
GenerateDiadic(op_shru, 0, ap3, make_immed((__int64) node->bit_offset)); |
GenerateDiadic(op_and, 0, ap3, make_immed(mask)); |
//MakeLegalAmode(ap, flags, node->esize); |
if (isSigned) |
SignExtendBitfield(node, ap3, mask); |
} |
else { |
GenerateTriadic(op_and, 0, ap3, ap3, make_immed(mask)); |
if (isSigned) |
SignExtendBitfield(node, ap3, mask); |
} |
//mask = 0; |
//while (--width) mask = mask + mask + 1; |
// GenerateDiadic(op_and, (int) node->esize, make_immed(mask), ap); |
MakeLegalAmode(ap3, flags, node->esize); |
return ap3; |
} |
|
/* |
* generate code to evaluate a unary minus or complement. |
*/ |
AMODE *GenerateUnary(ENODE *node,int flags, int size, int op) |
{ |
AMODE *ap,*ap1; |
ap = GenerateExpression(node->p[0],F_REG,size); |
ap1 = GetTempRegister(); |
GenerateDiadic(op,0,ap1,ap); |
ReleaseTempRegister(ap); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
|
AMODE *GenerateBinary(ENODE *node,int flags, int size, int op) |
{ |
AMODE *ap1, *ap2, *ap3; |
int op2; |
ap1 = GenerateExpression(node->p[0],F_REG,size); |
ap2 = GenerateExpression(node->p[1],F_REG|F_IMMED,size); |
ap3 = GetTempRegister(); |
GenerateTriadic(op,0,ap3,ap1,ap2); |
ReleaseTempRegister(ap1); |
ReleaseTempRegister(ap2); |
MakeLegalAmode(ap3,flags,size); |
return ap3; |
} |
|
/* |
* generate code to evaluate a mod operator or a divide |
* operator. |
*/ |
AMODE *GenerateModDiv(ENODE *node,int flags,int size, int op) |
{ |
AMODE *ap1, *ap2; |
|
if( node->p[0]->nodetype == en_icon ) |
swap_nodes(node); |
ap1 = GenerateExpression(node->p[0],F_REG,8); |
ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,8); |
GenerateTriadic(op,0,ap1,ap1,ap2); |
GenerateDiadic(op_ext,0,ap1,0); |
MakeLegalAmode(ap1,flags,4); |
ReleaseTempRegister(ap2); |
return ap1; |
} |
|
/* |
* exchange the two operands in a node. |
*/ |
void swap_nodes(ENODE *node) |
{ |
ENODE *temp; |
temp = node->p[0]; |
node->p[0] = node->p[1]; |
node->p[1] = temp; |
} |
|
/* |
* generate code to evaluate a multiply node. both operands |
* are treated as words and the result is long and is always |
* in a register so that the 68000 mul instruction can be used. |
*/ |
AMODE *GenerateMultiply(ENODE *node, int flags, int size, int op) |
{ |
AMODE *ap1, *ap2, *ap3; |
if( node->p[0]->nodetype == en_icon ) |
swap_nodes(node); |
ap1 = GenerateExpression(node->p[0],F_REG,8); |
ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,8); |
ap3 = GetTempRegister(); |
if (ap2->mode == am_immed) { |
if (op==op_mulu) |
GenerateTriadic(op_mului,0,ap3,ap1,ap2); |
else |
GenerateTriadic(op_mulsi,0,ap3,ap1,ap2); |
} |
else |
GenerateTriadic(op,0,ap3,ap1,ap2); |
ReleaseTempRegister(ap1); |
ReleaseTempRegister(ap2); |
MakeLegalAmode(ap3,flags,8); |
return ap3; |
} |
|
/* |
* generate code to evaluate a condition operator node (?:) |
*/ |
AMODE *gen_hook(ENODE *node,int flags, int size) |
{ |
AMODE *ap1, *ap2; |
int false_label, end_label; |
|
false_label = nextlabel++; |
end_label = nextlabel++; |
flags = (flags & F_REG) | F_VOL; |
GenerateFalseJump(node->p[0],false_label); |
node = node->p[1]; |
ap1 = GenerateExpression(node->p[0],flags,size); |
ReleaseTempRegister(ap1); |
GenerateDiadic(op_bra,0,make_label(end_label),0); |
GenerateLabel(false_label); |
ap2 = GenerateExpression(node->p[1],flags,size); |
if( !equal_address(ap1,ap2) ) |
{ |
ReleaseTempRegister(ap2); |
// GetTempRegister(); |
GenerateTriadic(op_or,0,ap1,makereg(0),ap2); |
} |
GenerateLabel(end_label); |
return ap1; |
} |
|
AMODE *GenerateAssignAdd(ENODE *node,int flags, int size, int op) |
{ |
AMODE *ap1, *ap2, *ap3; |
int ssize, mask0, mask1; |
ssize = GetNaturalSize(node->p[0]); |
if( ssize > size ) |
size = ssize; |
ap1 = GenerateExpression(node->p[0],F_ALL,ssize); |
ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,size); |
if (ap2->mode ==am_immed) |
switch(op) { |
case op_addu: op = op_addui; break; |
case op_add: op = op_addui; break; |
case op_subu: op = op_subui; break; |
case op_sub: op = op_subui; break; |
} |
if (ap1->mode==am_reg) { |
GenerateTriadic(op,0,ap1,ap1,ap2); |
} |
else { |
ap3 = GetTempRegister(); |
switch(ssize) { |
case 1: GenerateDiadic(op_lb,0,ap3,ap1); break; |
case 2: GenerateDiadic(op_lc,0,ap3,ap1); break; |
case 4: GenerateDiadic(op_lh,0,ap3,ap1); break; |
case 8: GenerateDiadic(op_lw,0,ap3,ap1); break; |
} |
GenerateTriadic(op,0,ap3,ap3,ap2); |
switch(ssize) { |
case 1: GenerateDiadic(op_sb,0,ap3,ap1); break; |
case 2: GenerateDiadic(op_sc,0,ap3,ap1); break; |
case 4: GenerateDiadic(op_sh,0,ap3,ap1); break; |
case 8: GenerateDiadic(op_sw,0,ap3,ap1); break; |
} |
ReleaseTempRegister(ap3); |
} |
ReleaseTempRegister(ap2); |
GenerateSignExtend(ap1,ssize,size,flags); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
|
AMODE *GenerateAssignLogic(ENODE *node,int flags, int size, int op) |
{ |
AMODE *ap1, *ap2, *ap3; |
int ssize, mask0, mask1; |
ssize = GetNaturalSize(node->p[0]); |
if( ssize > size ) |
size = ssize; |
ap1 = GenerateExpression(node->p[0],F_ALL,ssize); |
ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,size); |
if (ap2->mode==am_immed) |
switch(op) { |
case op_and: op = op_andi; break; |
case op_or: op = op_ori; break; |
case op_xor: op = op_xori; break; |
} |
if (ap1->mode==am_reg) { |
GenerateTriadic(op,0,ap1,ap1,ap2); |
} |
else { |
ap3 = GetTempRegister(); |
switch(ssize) { |
case 1: GenerateDiadic(op_lb,0,ap3,ap1); break; |
case 2: GenerateDiadic(op_lc,0,ap3,ap1); break; |
case 4: GenerateDiadic(op_lh,0,ap3,ap1); break; |
case 8: GenerateDiadic(op_lw,0,ap3,ap1); break; |
} |
GenerateTriadic(op,0,ap3,ap3,ap2); |
switch(ssize) { |
case 1: GenerateDiadic(op_sb,0,ap3,ap1); break; |
case 2: GenerateDiadic(op_sc,0,ap3,ap1); break; |
case 4: GenerateDiadic(op_sh,0,ap3,ap1); break; |
case 8: GenerateDiadic(op_sw,0,ap3,ap1); break; |
} |
ReleaseTempRegister(ap3); |
} |
ReleaseTempRegister(ap2); |
GenerateSignExtend(ap1,ssize,size,flags); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
|
/* |
* generate a *= node. |
*/ |
AMODE *GenerateAssignMultiply(ENODE *node,int flags, int size, int op) |
{ |
AMODE *ap1, *ap2, *ap3; |
int ssize, mask0, mask1; |
ssize = GetNaturalSize(node->p[0]); |
if( ssize > size ) |
size = ssize; |
ap1 = GenerateExpression(node->p[0],F_ALL,ssize); |
ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,size); |
if (ap2->mode==am_immed) |
switch(op) { |
case op_mulu: op = op_mului; break; |
case op_muls: op = op_mulsi; break; |
} |
if (ap1->mode==am_reg) { |
GenerateTriadic(op,0,ap1,ap1,ap2); |
} |
else { |
ap3 = GetTempRegister(); |
switch(ssize) { |
case 1: GenerateDiadic(op_lb,0,ap3,ap1); break; |
case 2: GenerateDiadic(op_lc,0,ap3,ap1); break; |
case 4: GenerateDiadic(op_lh,0,ap3,ap1); break; |
case 8: GenerateDiadic(op_lw,0,ap3,ap1); break; |
} |
GenerateTriadic(op,0,ap3,ap3,ap2); |
switch(ssize) { |
case 1: GenerateDiadic(op_sb,0,ap3,ap1); break; |
case 2: GenerateDiadic(op_sc,0,ap3,ap1); break; |
case 4: GenerateDiadic(op_sh,0,ap3,ap1); break; |
case 8: GenerateDiadic(op_sw,0,ap3,ap1); break; |
} |
ReleaseTempRegister(ap3); |
} |
ReleaseTempRegister(ap2); |
GenerateSignExtend(ap1,ssize,size,flags); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
|
/* |
* generate /= and %= nodes. |
*/ |
AMODE *gen_asmodiv(ENODE *node,int flags,int size,int op) |
{ |
AMODE *ap1, *ap2, *ap3; |
int siz1; |
|
siz1 = GetNaturalSize(node->p[0]); |
ap1 = GetTempRegister(); |
ap2 = GenerateExpression(node->p[0],F_ALL & ~F_IMMED,siz1); |
if (ap2->mode==am_reg && ap2->preg != ap1->preg) |
GenerateTriadic(op_or,0,ap1,ap2,makereg(0)); |
else { |
switch(siz1) { |
case 1: GenerateDiadic(op_lb,0,ap1,ap2); break; |
case 2: GenerateDiadic(op_lc,0,ap1,ap2); break; |
case 4: GenerateDiadic(op_lh,0,ap1,ap2); break; |
case 8: GenerateDiadic(op_lw,0,ap1,ap2); break; |
} |
} |
GenerateSignExtend(ap1,siz1,8,flags); |
ap3 = GenerateExpression(node->p[1],F_REG,2); |
GenerateTriadic(op,0,ap1,ap1,ap3); |
ReleaseTempRegister(ap3); |
//GenerateDiadic(op_ext,0,ap1,0); |
if (ap2->mode==am_reg) |
GenerateTriadic(op_or,0,ap2,ap1,makereg(0)); |
else |
switch(siz1) { |
case 1: GenerateDiadic(op_sb,0,ap1,ap2); break; |
case 2: GenerateDiadic(op_sc,0,ap1,ap2); break; |
case 4: GenerateDiadic(op_sh,0,ap1,ap2); break; |
case 8: GenerateDiadic(op_sw,0,ap1,ap2); break; |
} |
ReleaseTempRegister(ap2); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
|
/* |
* generate code for an assignment node. if the size of the |
* assignment destination is larger than the size passed then |
* everything below this node will be evaluated with the |
* assignment size. |
*/ |
AMODE *GenerateAssign(ENODE *node, int flags, int size) |
{ struct amode *ap1, *ap2 ,*ap3; |
int ssize; |
ENODE *ep; |
if (node->p[0]->nodetype == en_uwfieldref || |
node->p[0]->nodetype == en_wfieldref || |
node->p[0]->nodetype == en_uhfieldref || |
node->p[0]->nodetype == en_hfieldref || |
node->p[0]->nodetype == en_ucfieldref || |
node->p[0]->nodetype == en_cfieldref || |
node->p[0]->nodetype == en_ubfieldref || |
node->p[0]->nodetype == en_bfieldref) { |
long mask; |
int i; |
/* |
* Field assignment |
*/ |
/* get the value */ |
ap1 = GenerateExpression(node->p[1], F_REG | F_VOL,8); |
i = node->p[0]->bit_width; |
for (mask = 0; i--; mask = mask + mask + 1); |
GenerateDiadic(op_and, 0, make_immed(mask), ap1); |
mask <<= node->p[0]->bit_offset; |
if (!(flags & F_NOVALUE)) { |
/* |
* result value needed |
*/ |
ap3 = GetTempRegister(); |
GenerateTriadic(op_or, 0, ap3, ap1, makereg(0)); |
} else |
ap3 = ap1; |
if (node->p[0]->bit_offset > 0) { |
if (node->p[0]->bit_offset < 9) { |
GenerateTriadic(op_shl, 0, ap3,ap3,make_immed((long) node->p[0]->bit_offset)); |
} |
else { |
ap2 = GetTempRegister(); |
GenerateTriadic(op_ori, 0, ap2,makereg(0),make_immed((long) node->p[0]->bit_offset)); |
GenerateTriadic(op_shl, 0, ap3, ap3, ap2); |
ReleaseTempRegister(ap2); |
} |
} |
ep = makenode(en_w_ref, node->p[0]->p[0], NULL); |
ap2 = GenerateExpression(ep, F_MEM,8); |
//ap2 = GenerateExpression(node->v.p[0],F_ALL,4); |
GenerateTriadic(op_andi, 0, ap2,ap2,make_immed(~mask)); |
GenerateTriadic(op_or, 0, ap2, ap2, ap3); |
ReleaseTempRegister(ap2); |
if (!(flags & F_NOVALUE)) { |
ReleaseTempRegister(ap3); |
} |
MakeLegalAmode(ap1, flags, size); |
return ap1; |
} |
|
ssize = GetReferenceSize(node->p[0]); |
if( ssize > size ) |
size = ssize; |
ap2 = GenerateExpression(node->p[1],F_REG,size); |
ap1 = GenerateExpression(node->p[0],F_ALL,ssize); |
if (ap1->mode == am_reg) { |
GenerateDiadic(op_mov,0,ap1,ap2); |
} |
else { |
switch(size) { |
case 1: GenerateDiadic(op_sb,0,ap2,ap1); break; |
case 2: GenerateDiadic(op_sc,0,ap2,ap1); break; |
case 4: GenerateDiadic(op_sh,0,ap2,ap1); break; |
case 8: GenerateDiadic(op_sw,0,ap2,ap1); break; |
} |
} |
ReleaseTempRegister(ap1); |
return ap2; |
} |
|
/* |
* generate an auto increment or decrement node. op should be |
* either op_add (for increment) or op_sub (for decrement). |
*/ |
AMODE *GenerateAutoIncrement(ENODE *node,int flags,int size,int op) |
{ |
AMODE *ap1, *ap2; |
int siz1; |
|
siz1 = GetNaturalSize(node->p[0]); |
if( flags & F_NOVALUE ) /* dont need result */ |
{ |
ap1 = GenerateExpression(node->p[0],F_ALL,siz1); |
switch(op) { |
case op_addu: op = op_addui; break; |
case op_add: op = op_addui; break; |
case op_subu: op = op_subui; break; |
case op_sub: op = op_subui; break; |
} |
if (ap1->mode != am_reg) { |
ap2 = GetTempRegister(); |
switch(size) { |
case 1: GenerateTriadic(op_lb,0,ap2,ap1,NULL); break; |
case 2: GenerateTriadic(op_lc,0,ap2,ap1,NULL); break; |
case 4: GenerateTriadic(op_lh,0,ap2,ap1,NULL); break; |
case 8: GenerateTriadic(op_lw,0,ap2,ap1,NULL); break; |
} |
GenerateTriadic(op,0,ap2,ap2,make_immed(node->i)); |
switch(size) { |
case 1: GenerateTriadic(op_sb,0,ap2,ap1,NULL); break; |
case 2: GenerateTriadic(op_sc,0,ap2,ap1,NULL); break; |
case 4: GenerateTriadic(op_sh,0,ap2,ap1,NULL); break; |
case 8: GenerateTriadic(op_sw,0,ap2,ap1,NULL); break; |
} |
ReleaseTempRegister(ap2); |
} |
else |
GenerateTriadic(op,0,ap1,ap1,make_immed(node->i)); |
ReleaseTempRegister(ap1); |
return ap1; |
} |
ap2 = GenerateExpression(node->p[0],F_ALL,siz1); |
if (ap2->mode == am_reg) { |
GenerateTriadic(op,0,ap2,ap2,make_immed(node->i)); |
return ap2; |
} |
else { |
ap1 = GetTempRegister(); |
switch(siz1) { |
case 1: GenerateDiadic(op_lb,0,ap1,ap2); break; |
case 2: GenerateDiadic(op_lc,0,ap1,ap2); break; |
case 4: GenerateDiadic(op_lh,0,ap1,ap2); break; |
case 8: GenerateDiadic(op_lw,0,ap1,ap2); break; |
} |
switch(op) { |
case op_addu: op = op_addui; break; |
case op_add: op = op_addui; break; |
case op_subu: op = op_subui; break; |
case op_sub: op = op_subui; break; |
} |
GenerateTriadic(op,0,ap1,ap1,make_immed(node->i)); |
switch(siz1) { |
case 1: GenerateDiadic(op_sb,0,ap1,ap2); break; |
case 2: GenerateDiadic(op_sc,0,ap1,ap2); break; |
case 4: GenerateDiadic(op_sh,0,ap1,ap2); break; |
case 8: GenerateDiadic(op_sw,0,ap1,ap2); break; |
} |
} |
ReleaseTempRegister(ap2); |
GenerateSignExtend(ap1,siz1,size,flags); |
return ap1; |
} |
|
/* |
* general expression evaluation. returns the addressing mode |
* of the result. |
*/ |
AMODE *GenerateExpression(ENODE *node, int flags, int size) |
{ |
AMODE *ap1, *ap2; |
int lab0, lab1; |
int natsize; |
|
if( node == NULL ) |
{ |
printf("DIAG - null node in GenerateExpression.\n"); |
return NULL; |
} |
switch( node->nodetype ) |
{ |
case en_icon: |
case en_labcon: |
case en_nacon: |
ap1 = allocAmode(); |
ap1->mode = am_immed; |
ap1->offset = node; |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
case en_autocon: |
ap1 = GetTempRegister(); |
ap2 = allocAmode(); |
ap2->mode = am_indx; |
ap2->preg = 27; /* frame pointer */ |
ap2->offset = node; /* use as constant node */ |
GenerateDiadic(op_lea,0,ap1,ap2); |
MakeLegalAmode(ap1,flags,size); |
return ap1; /* return reg */ |
case en_b_ref: |
case en_c_ref: |
case en_h_ref: |
case en_ub_ref: |
case en_uc_ref: |
case en_uh_ref: |
case en_w_ref: |
case en_uw_ref: |
return GenerateDereference(node,flags,size); |
case en_uwfieldref: |
case en_wfieldref: |
case en_bfieldref: |
case en_ubfieldref: |
case en_cfieldref: |
case en_ucfieldref: |
case en_hfieldref: |
case en_uhfieldref: |
return GenerateBitfieldDereference(node,flags,size); |
case en_regvar: |
case en_tempref: |
ap1 = xalloc(sizeof(struct amode)); |
ap1->mode = am_reg; |
ap1->preg = node->i; |
ap1->tempflag = 0; /* not a temporary */ |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
case en_uminus: return GenerateUnary(node,flags,size,op_neg); |
case en_compl: return GenerateUnary(node,flags,size,op_not); |
case en_add: return GenerateBinary(node,flags,size,op_add); |
case en_sub: return GenerateBinary(node,flags,size,op_sub); |
case en_and: return GenerateBinary(node,flags,size,op_and); |
case en_or: return GenerateBinary(node,flags,size,op_or); |
case en_xor: return GenerateBinary(node,flags,size,op_xor); |
case en_mul: return GenerateMultiply(node,flags,size,op_muls); |
case en_mulu: return GenerateMultiply(node,flags,size,op_mulu); |
case en_div: return GenerateModDiv(node,flags,size,op_divs); |
case en_udiv: return GenerateModDiv(node,flags,size,op_divu); |
case en_mod: return GenerateModDiv(node,flags,size,op_mod); |
case en_umod: return GenerateModDiv(node,flags,size,op_modu); |
case en_shl: return GenerateShift(node,flags,size,op_shl); |
case en_shr: return GenerateShift(node,flags,size,op_shr); |
case en_shru: return GenerateShift(node,flags,size,op_shru); |
case en_asadd: return GenerateAssignAdd(node,flags,size,op_add); |
case en_assub: return GenerateAssignAdd(node,flags,size,op_sub); |
case en_asand: return GenerateAssignLogic(node,flags,size,op_and); |
case en_asor: return GenerateAssignLogic(node,flags,size,op_or); |
case en_asxor: return GenerateAssignLogic(node,flags,size,op_xor); |
case en_aslsh: |
return GenerateAssignShift(node,flags,size,op_shl); |
case en_asrsh: |
return GenerateAssignShift(node,flags,size,op_shr); |
case en_asmul: return GenerateAssignMultiply(node,flags,size,op_muls); |
case en_asmulu: return GenerateAssignMultiply(node,flags,size,op_mulu); |
case en_asdiv: |
return gen_asmodiv(node,flags,size,op_divs); |
case en_asmod: |
return gen_asmodiv(node,flags,size,op_muls); |
case en_assign: |
return GenerateAssign(node,flags,size); |
case en_ainc: |
return GenerateAutoIncrement(node,flags,size,op_add); |
case en_adec: |
return GenerateAutoIncrement(node,flags,size,op_sub); |
case en_land: case en_lor: |
case en_eq: case en_ne: |
case en_lt: case en_le: |
case en_gt: case en_ge: |
case en_ult: case en_ule: |
case en_ugt: case en_uge: |
case en_not: |
lab0 = nextlabel++; |
lab1 = nextlabel++; |
GenerateFalseJump(node,lab0); |
ap1 = GetTempRegister(); |
GenerateTriadic(op_ori,0,ap1,makereg(0),make_immed(1)); |
GenerateTriadic(op_bra,0,make_label(lab1),NULL,NULL); |
GenerateLabel(lab0); |
GenerateTriadic(op_ori,0,ap1,makereg(0),make_immed(0)); |
GenerateLabel(lab1); |
return ap1; |
case en_cond: |
return gen_hook(node,flags,size); |
case en_void: |
natsize = GetNaturalSize(node->p[0]); |
ReleaseTempRegister(GenerateExpression(node->p[0],F_ALL | F_NOVALUE,natsize)); |
return GenerateExpression(node->p[1],flags,size); |
case en_fcall: |
return GenerateFunctionCall(node,flags); |
default: |
printf("DIAG - uncoded node in GenerateExpression.\n"); |
return 0; |
} |
} |
|
/* |
* return the natural evaluation size of a node. |
*/ |
int GetNaturalSize(ENODE *node) |
{ |
int siz0, siz1; |
if( node == NULL ) |
return 0; |
switch( node->nodetype ) |
{ |
case en_uwfieldref: |
case en_wfieldref: |
return 8; |
case en_bfieldref: |
case en_ubfieldref: |
return 1; |
case en_cfieldref: |
case en_ucfieldref: |
return 2; |
case en_hfieldref: |
case en_uhfieldref: |
return 4; |
case en_icon: |
if( -128 <= node->i && node->i <= 127 ) |
return 1; |
if( -32768 <= node->i && node->i <= 32767 ) |
return 2; |
if (-2147483648L <= node->i && node->i <= 2147483647L) |
return 4; |
return 8; |
case en_fcall: case en_labcon: |
case en_nacon: case en_autocon: |
case en_tempref: |
case en_regvar: |
case en_cbw: |
case en_ccw: |
case en_chw: |
return 8; |
case en_b_ref: |
case en_ub_ref: |
return 1; |
case en_cbc: |
case en_c_ref: return 2; |
case en_uc_ref: return 2; |
case en_cbh: return 4; |
case en_cch: return 4; |
case en_h_ref: return 4; |
case en_uh_ref: return 4; |
case en_w_ref: case en_uw_ref: |
return 8; |
case en_not: case en_compl: |
case en_uminus: case en_assign: |
case en_ainc: case en_adec: |
return GetNaturalSize(node->p[0]); |
case en_add: case en_sub: |
case en_mul: case en_div: |
case en_mod: case en_and: |
case en_or: case en_xor: |
case en_shl: case en_shr: case en_shru: |
case en_eq: case en_ne: |
case en_lt: case en_le: |
case en_gt: case en_ge: |
case en_ult: case en_ule: |
case en_ugt: case en_uge: |
case en_land: case en_lor: |
case en_asadd: case en_assub: |
case en_asmul: case en_asdiv: |
case en_asmod: case en_asand: |
case en_asor: case en_asxor: case en_aslsh: |
case en_asrsh: |
siz0 = GetNaturalSize(node->p[0]); |
siz1 = GetNaturalSize(node->p[1]); |
if( siz1 > siz0 ) |
return siz1; |
else |
return siz0; |
case en_void: case en_cond: |
return GetNaturalSize(node->p[1]); |
default: |
printf("DIAG - natural size error %d.\n", node->nodetype); |
break; |
} |
return 0; |
} |
|
|
void gen_b(ENODE *node, int op, int label) |
{ |
int size; |
struct amode *ap1, *ap2; |
|
size = GetNaturalSize(node); |
ap1 = GenerateExpression(node->p[0],F_REG, size); |
ap2 = GenerateExpression(node->p[1],F_REG|F_IMMED18,size); |
GenerateTriadic(op,0,ap1,ap2,make_label(label)); |
ReleaseTempRegister(ap2); |
ReleaseTempRegister(ap1); |
} |
/* |
* generate a jump to label if the node passed evaluates to |
* a true condition. |
*/ |
void GenerateTrueJump(ENODE *node, int label) |
{ AMODE *ap1,*ap2; |
int siz1; |
int lab0; |
int size; |
if( node == 0 ) |
return; |
switch( node->nodetype ) |
{ |
case en_eq: gen_b(node, op_beq, label); break; |
case en_ne: gen_b(node, op_bne, label); break; |
case en_lt: gen_b(node, op_blt, label); break; |
case en_le: gen_b(node, op_ble, label); break; |
case en_gt: gen_b(node, op_bgt, label); break; |
case en_ge: gen_b(node, op_bge, label); break; |
case en_ult: gen_b(node, op_bltu, label); break; |
case en_ule: gen_b(node, op_bleu, label); break; |
case en_ugt: gen_b(node, op_bgtu, label); break; |
case en_uge: gen_b(node, op_bgeu, label); break; |
case en_land: |
lab0 = nextlabel++; |
GenerateFalseJump(node->p[0],lab0); |
GenerateTrueJump(node->p[1],label); |
GenerateLabel(lab0); |
break; |
case en_lor: |
GenerateTrueJump(node->p[0],label); |
GenerateTrueJump(node->p[1],label); |
break; |
case en_not: |
GenerateFalseJump(node->p[0],label); |
break; |
default: |
siz1 = GetNaturalSize(node); |
ap1 = GenerateExpression(node,F_REG,siz1); |
// GenerateDiadic(op_tst,siz1,ap1,0); |
ReleaseTempRegister(ap1); |
GenerateTriadic(op_bne,0,ap1,makereg(0),make_label(label)); |
break; |
} |
} |
|
/* |
* generate code to execute a jump to label if the expression |
* passed is false. |
*/ |
void GenerateFalseJump(ENODE *node,int label) |
{ |
AMODE *ap,*ap1,*ap2; |
int size; |
int siz1; |
int lab0; |
if( node == NULL ) |
return; |
switch( node->nodetype ) |
{ |
case en_eq: gen_b(node, op_bne, label); break; |
case en_ne: gen_b(node, op_beq, label); break; |
case en_lt: gen_b(node, op_bge, label); break; |
case en_le: gen_b(node, op_bgt, label); break; |
case en_gt: gen_b(node, op_ble, label); break; |
case en_ge: gen_b(node, op_blt, label); break; |
case en_ult: gen_b(node, op_bgeu, label); break; |
case en_ule: gen_b(node, op_bgtu, label); break; |
case en_ugt: gen_b(node, op_bleu, label); break; |
case en_uge: gen_b(node, op_bltu, label); break; |
case en_land: |
GenerateFalseJump(node->p[0],label); |
GenerateFalseJump(node->p[1],label); |
break; |
case en_lor: |
lab0 = nextlabel++; |
GenerateTrueJump(node->p[0],lab0); |
GenerateFalseJump(node->p[1],label); |
GenerateLabel(lab0); |
break; |
case en_not: |
GenerateTrueJump(node->p[0],label); |
break; |
default: |
siz1 = GetNaturalSize(node); |
ap = GenerateExpression(node,F_REG,siz1); |
// GenerateDiadic(op_tst,siz1,ap,0); |
ReleaseTempRegister(ap); |
GenerateTriadic(op_beq,0,ap,makereg(0),make_label(label)); |
break; |
} |
} |
/ParseStatements.c
0,0 → 1,735
// ============================================================================ |
// (C) 2012 Robert Finch |
// All Rights Reserved. |
// robfinch<remove>@opencores.org |
// |
// C64 - Raptor64 'C' derived language compiler |
// - 64 bit CPU |
// |
// This source file is free software: you can redistribute it and/or modify |
// it under the terms of the GNU Lesser General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or |
// (at your option) any later version. |
// |
// This source file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public License |
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
// |
// ============================================================================ |
// |
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
extern TYP *head, *tail; |
extern char *declid; |
extern int catchdecl; |
Statement *ParseStatement(); /* forward declararation */ |
Statement *ParseCatchStatement(); |
|
Statement *NewStatement(int typ, int gt) { |
Statement *s = (Statement *)xalloc(sizeof(Statement)); |
s->stype = typ; |
if (gt) NextToken(); |
return s; |
}; |
|
|
int GetTypeHash(TYP *p) |
{ |
int n; |
TYP *p1; |
|
n = 0; |
do { |
if (p->type==bt_pointer) |
n+=20000; |
p1 = p; |
p = p->btp; |
} while (p); |
n += p1->typeno; |
return n; |
} |
|
|
//struct snode *interrupt_stmt() |
//{ struct snode *snp; |
// SYM *sp; |
// TYP *temp1; |
// |
// NextToken(); |
// if( lastst != id ) { |
// error(ERR_IDEXPECT); |
// return 0; |
// } |
// sp = allocSYM(); |
// sp->name = litlate(lastid); |
// sp->value.i = nextlabel++; |
// sp->storage_class = sc_global; |
// sp->tp = temp1; |
// temp1 = maketype(bt_long,0); |
// temp1->val_flag = 1; |
// insert(sp,&lsyms); |
// NextToken(); /* get past label name */ |
// needpunc( colon ); |
// snp = (struct snode *)xalloc(sizeof(struct snode)); |
// snp->stype = st_interrupt; |
// snp->label = sp->name; |
// snp->next = 0; |
// snp->s1 = statement(); |
// return snp; |
//} |
// |
struct snode *vortex_stmt() |
{ struct snode *snp; |
SYM *sp; |
TYP *temp1; |
|
NextToken(); |
if( lastst != id ) { |
error(ERR_IDEXPECT); |
return 0; |
} |
temp1 = maketype(bt_long,0); |
temp1->val_flag = 1; |
sp = allocSYM(); |
sp->name = litlate(lastid); |
sp->value.i = nextlabel++; |
sp->storage_class = sc_global; |
sp->tp = temp1; |
insert(sp,&lsyms); |
NextToken(); /* get past label name */ |
needpunc( colon ); |
snp = (struct snode *)xalloc(sizeof(struct snode)); |
snp->stype = st_vortex; |
snp->label = sp->name; |
snp->next = 0; |
snp->s1 = ParseStatement(); |
return snp; |
} |
|
Statement *ParseWhileStatement() |
{ |
Statement *snp; |
|
snp = NewStatement(st_while, TRUE); |
if( lastst != openpa ) |
error(ERR_EXPREXPECT); |
else { |
NextToken(); |
if( expression(&(snp->exp)) == 0 ) |
error(ERR_EXPREXPECT); |
needpunc( closepa ); |
if (lastst==kw_do) |
NextToken(); |
snp->s1 = ParseStatement(); |
} |
return snp; |
} |
|
Statement *ParseUntilStatement() |
{ |
Statement *snp; |
snp = NewStatement(st_until, TRUE); |
if( lastst != openpa ) |
error(ERR_EXPREXPECT); |
else { |
NextToken(); |
if( expression(&(snp->exp)) == 0 ) |
error(ERR_EXPREXPECT); |
needpunc( closepa ); |
snp->s1 = ParseStatement(); |
} |
return snp; |
} |
|
Statement *ParseDoStatement() |
{ |
Statement *snp; |
snp = NewStatement(st_do, TRUE); |
snp->s1 = ParseStatement(); |
if (lastst == kw_until) |
snp->stype = st_dountil; |
else if (lastst== kw_loop) |
snp->stype = st_doloop; |
if( lastst != kw_while && lastst != kw_until && lastst != kw_loop ) |
error(ERR_WHILEXPECT); |
else { |
NextToken(); |
if (snp->stype!=st_doloop) { |
if( expression(&(snp->exp)) == 0 ) |
error(ERR_EXPREXPECT); |
} |
if( lastst != end ) |
needpunc( semicolon ); |
} |
return snp; |
} |
|
Statement *ParseForStatement() |
{ |
Statement *snp; |
snp = NewStatement(st_for, TRUE); |
needpunc(openpa); |
if( expression(&(snp->initExpr)) == NULL ) |
snp->initExpr = NULL; |
needpunc(semicolon); |
if( expression(&(snp->exp)) == NULL ) |
snp->exp = NULL; |
needpunc(semicolon); |
if( expression(&(snp->incrExpr)) == NULL ) |
snp->incrExpr = NULL; |
needpunc(closepa); |
snp->s1 = ParseStatement(); |
return snp; |
} |
|
Statement *ParseForeverStatement() |
{ |
Statement *snp; |
snp = NewStatement(st_forever, TRUE); |
snp->stype = st_forever; |
snp->s1 = ParseStatement(); |
return snp; |
} |
|
struct snode *ParseCriticalStatement() |
{ |
struct snode *snp; |
SYM *sp; |
snp = (struct snode*)xalloc(sizeof(struct snode)); |
NextToken(); |
if (lastst==openpa) |
NextToken(); |
if( lastst != id ) { |
error(ERR_IDEXPECT); |
return 0; |
} |
if( (sp = search(lastid,&gsyms[0])) == NULL ) { |
error( ERR_UNDEFINED ); |
return 0; |
} |
NextToken(); |
if (lastst==closepa) |
NextToken(); |
snp->stype = st_critical; |
snp->label = sp->name; |
snp->next = 0; |
snp->s1 = ParseStatement(); |
return snp; |
} |
|
Statement *ParseSpinlockStatement() |
{ |
Statement *snp; |
SYM *sp; |
|
snp = NewStatement(st_spinlock, TRUE); |
if (lastst==openpa) |
NextToken(); |
if( lastst != id ) { |
error(ERR_IDEXPECT); |
return 0; |
} |
if( (sp = search(lastid,&gsyms[0])) == NULL ) { |
error( ERR_UNDEFINED ); |
return 0; |
} |
NextToken(); |
if (lastst==comma) { |
NextToken(); |
snp->exp = GetIntegerExpression(); |
} |
if (lastst==closepa) |
NextToken(); |
snp->label = sp->name; |
snp->next = 0; |
snp->s1 = ParseStatement(); |
if (lastst==kw_lockfail) { |
NextToken(); |
snp->s2 = ParseStatement(); |
} |
return snp; |
} |
|
Statement *ParseSpinunlockStatement() |
{ |
Statement *snp; |
SYM *sp; |
|
snp = NewStatement(st_spinunlock, TRUE); |
if (lastst==openpa) |
NextToken(); |
if( lastst != id ) { |
error(ERR_IDEXPECT); |
return 0; |
} |
if( (sp = search(lastid,&gsyms[0])) == NULL ) { |
error( ERR_UNDEFINED ); |
return 0; |
} |
NextToken(); |
if (lastst==closepa) |
NextToken(); |
snp->label = sp->name; |
snp->next = 0; |
return snp; |
} |
|
Statement *ParseFirstcallStatement() |
{ |
Statement *snp; |
snp = NewStatement(st_firstcall, TRUE); |
snp->s1 = ParseStatement(); |
return snp; |
} |
|
Statement *ParseIfStatement() |
{ |
Statement *snp; |
|
snp = NewStatement(st_if, TRUE); |
if( lastst != openpa ) |
error(ERR_EXPREXPECT); |
else { |
NextToken(); |
if( expression(&(snp->exp)) == 0 ) |
error(ERR_EXPREXPECT); |
needpunc( closepa ); |
if (lastst==kw_then) |
NextToken(); |
snp->s1 = ParseStatement(); |
if( lastst == kw_else ) { |
NextToken(); |
snp->s2 = ParseStatement(); |
} |
else if (lastst == kw_elsif) { |
snp->s2 = ParseIfStatement(); |
} |
else |
snp->s2 = 0; |
} |
return snp; |
} |
|
Statement *ParseCatchStatement() |
{ |
Statement *snp; |
SYM *sp; |
TYP *tp,*tp1,*tp2; |
|
snp = NewStatement(st_catch, TRUE); |
if (lastst != openpa) { |
snp->label = NULL; |
snp->s2 = 99999; |
snp->s1 = ParseStatement(); |
return snp; |
} |
needpunc(openpa); |
tp = head; |
tp1 = tail; |
catchdecl = TRUE; |
ParseAutoDeclarations(); |
catchdecl = FALSE; |
tp2 = head; |
head = tp; |
tail = tp1; |
needpunc(closepa); |
|
if( (sp = search(declid,&lsyms)) == NULL) |
sp = makeint(declid); |
snp->s1 = ParseStatement(); |
snp->label = (char *)sp; // save off symbol pointer |
if (sp->tp->typeno >= bt_last) |
error(ERR_CATCHSTRUCT); |
snp->s2 = GetTypeHash(sp->tp); |
return snp; |
} |
|
Statement *ParseCaseStatement() |
{ |
Statement *snp; |
Statement *head, *tail; |
int buf[256]; |
int nn; |
int *bf; |
|
snp = NewStatement(st_case, FALSE); |
if (lastst == kw_fallthru) // ignore "fallthru" |
NextToken(); |
if( lastst == kw_case ) { |
NextToken(); |
snp->s2 = 0; |
nn = 0; |
do { |
buf[nn] = GetIntegerExpression(); |
nn++; |
if (lastst != comma) |
break; |
NextToken(); |
} while (nn < 256); |
if (nn==256) |
error(ERR_TOOMANYCASECONSTANTS); |
bf = (int *)xalloc(sizeof(int)*(nn+1)); |
bf[0] = nn; |
for (; nn > 0; nn--) |
bf[nn]=buf[nn-1]; |
snp->label = bf; |
} |
else if( lastst == kw_default) { |
NextToken(); |
snp->s2 = 1; |
snp->stype = st_default; |
} |
else { |
error(ERR_NOCASE); |
return NULL; |
} |
needpunc(colon); |
head = NULL; |
while( lastst != end && lastst != kw_case && lastst != kw_default ) { |
if( head == NULL ) |
head = tail = ParseStatement(); |
else { |
tail->next = ParseStatement(); |
if( tail->next != NULL ) |
tail = tail->next; |
} |
tail->next = 0; |
} |
snp->s1 = head; |
return snp; |
} |
|
int CheckForDuplicateCases(Statement *head) |
{ |
Statement *top, *cur; |
|
cur = top = head; |
while( top != NULL ) |
{ |
cur = top->next; |
while( cur != NULL ) |
{ |
if( (!(cur->s1 || cur->s2) && cur->label == top->label) |
|| (cur->s2 && top->s2) ) |
{ |
printf(" duplicate case value %d\n",cur->label); |
return TRUE; |
} |
cur = cur->next; |
} |
top = top->next; |
} |
return FALSE; |
} |
|
Statement *ParseSwitchStatement() |
{ |
Statement *snp; |
Statement *head, *tail; |
|
snp = NewStatement(st_switch, TRUE); |
if( expression(&(snp->exp)) == NULL ) |
error(ERR_EXPREXPECT); |
needpunc(begin); |
head = 0; |
while( lastst != end ) { |
if( head == NULL ) |
head = tail = ParseCaseStatement(); |
else { |
tail->next = ParseCaseStatement(); |
if( tail->next != NULL ) |
tail = tail->next; |
} |
if (tail==NULL) break; // end of file in switch |
tail->next = NULL; |
} |
snp->s1 = head; |
NextToken(); |
if( CheckForDuplicateCases(head) ) |
error(ERR_DUPCASE); |
return snp; |
} |
|
Statement *ParseReturnStatement() |
{ |
Statement *snp; |
|
snp = NewStatement(st_return, TRUE); |
expression(&(snp->exp)); |
if( lastst != end ) |
needpunc( semicolon ); |
return snp; |
} |
|
Statement *ParseThrowStatement() |
{ |
Statement *snp; |
TYP *tp; |
|
currentFn->DoesThrow = TRUE; |
snp = NewStatement(st_throw, TRUE); |
tp = expression(&(snp->exp)); |
snp->label = GetTypeHash(tp); |
if( lastst != end ) |
needpunc( semicolon ); |
return snp; |
} |
|
Statement *ParseBreakStatement() |
{ |
Statement *snp; |
|
snp = NewStatement(st_break, TRUE); |
if( lastst != end ) |
needpunc( semicolon ); |
return snp; |
} |
|
Statement *ParseContinueStatement() |
{ |
Statement *snp; |
|
snp = NewStatement(st_continue, TRUE); |
if( lastst != end ) |
needpunc( semicolon ); |
return snp; |
} |
|
Statement *ParseIntoffStatement() |
{ |
Statement *snp; |
snp = NewStatement(st_intoff, TRUE); |
if( lastst != end ) |
needpunc( semicolon ); |
return snp; |
} |
|
Statement *ParseIntonStatement() |
{ |
Statement *snp; |
|
snp = NewStatement(st_inton, TRUE); |
if( lastst != end ) |
needpunc( semicolon ); |
return snp; |
} |
|
Statement *ParseStopStatement() |
{ |
Statement *snp; |
|
snp = NewStatement(st_stop, TRUE); |
if( lastst != end ) |
needpunc( semicolon ); |
return snp; |
} |
|
Statement *ParseAsmStatement() |
{ |
static char buf[2001]; |
int nn; |
|
Statement *snp; |
snp = NewStatement(st_asm, FALSE); |
while( isspace(lastch) ) |
getch(); |
NextToken(); |
if (lastst != begin) |
error(ERR_PUNCT); |
nn = 0; |
do { |
getch(); |
if (lastch=='}') |
break; |
buf[nn++] = lastch; |
} |
while(lastch!=-1 && nn < 2000); |
if (nn >= 2000) |
error(ERR_ASMTOOLONG); |
buf[nn] = '\0'; |
snp->label = litlate(buf); |
return snp; |
} |
|
Statement *ParseTryStatement() |
{ |
Statement *snp; |
TYP *tp,*tp1,*tp2; |
SYM *sp; |
Statement *hd, *tl; |
|
hd = NULL; |
tl = NULL; |
snp = NewStatement(st_try, TRUE); |
snp->s1 = ParseStatement(); |
if (lastst != kw_catch) |
error(ERR_CATCHEXPECT); |
while( lastst == kw_catch ) { |
if( hd == NULL ) |
hd = tl = ParseCatchStatement(); |
else { |
tl->next = ParseCatchStatement(); |
if( tl->next != NULL ) |
tl = tl->next; |
} |
if (tl==NULL) break; // end of file in try |
tl->next = NULL; |
} |
snp->s2 = hd; |
return snp; |
} |
|
Statement *ParseExpressionStatement() |
{ |
Statement *snp; |
snp = NewStatement(st_expr, FALSE); |
if( expression(&(snp->exp)) == NULL ) { |
error(ERR_EXPREXPECT); |
NextToken(); |
} |
if( lastst != end ) |
needpunc( semicolon ); |
return snp; |
} |
|
Statement *ParseCompoundStatement() |
{ |
Statement *head, *tail; |
|
head = 0; |
while( lastst != end ) { |
if( head == NULL ) |
head = tail = ParseStatement(); |
else { |
tail->next = ParseStatement(); |
if( tail->next != NULL ) |
tail = tail->next; |
} |
} |
NextToken(); |
return head; |
} |
|
Statement *ParseLabelStatement() |
{ |
Statement *snp; |
SYM *sp; |
|
snp = NewStatement(st_label, FALSE); |
if( (sp = search(lastid,&lsyms)) == NULL ) { |
sp = allocSYM(); |
sp->name = litlate(lastid); |
sp->storage_class = sc_label; |
sp->tp = 0; |
sp->value.i = nextlabel++; |
insert(sp,&lsyms); |
} |
else { |
if( sp->storage_class != sc_ulabel ) |
error(ERR_LABEL); |
else |
sp->storage_class = sc_label; |
} |
NextToken(); /* get past id */ |
needpunc(colon); |
if( sp->storage_class == sc_label ) { |
snp->label = sp->value.i; |
snp->next = NULL; |
return snp; |
} |
return 0; |
} |
|
Statement *ParseGotoStatement() |
{ |
Statement *snp; |
SYM *sp; |
|
NextToken(); |
if( lastst != id ) { |
error(ERR_IDEXPECT); |
return NULL; |
} |
snp = NewStatement(st_goto, FALSE); |
if( (sp = search(lastid,&lsyms)) == NULL ) { |
sp = allocSYM(); |
sp->name = litlate(lastid); |
sp->value.i = nextlabel++; |
sp->storage_class = sc_ulabel; |
sp->tp = 0; |
insert(sp,&lsyms); |
} |
NextToken(); /* get past label name */ |
if( lastst != end ) |
needpunc( semicolon ); |
if( sp->storage_class != sc_label && sp->storage_class != sc_ulabel) |
error( ERR_LABEL ); |
else { |
snp->stype = st_goto; |
snp->label = sp->value.i; |
snp->next = NULL; |
return snp; |
} |
return NULL; |
} |
|
Statement *ParseStatement() |
{ |
Statement *snp; |
switch( lastst ) { |
case semicolon: |
NextToken(); |
snp = NULL; |
break; |
case begin: |
NextToken(); |
snp = ParseCompoundStatement(); |
return snp; |
case kw_if: snp = ParseIfStatement(); break; |
case kw_while: snp = ParseWhileStatement(); break; |
case kw_until: snp = ParseUntilStatement(); break; |
case kw_for: snp = ParseForStatement(); break; |
case kw_forever: snp = ParseForeverStatement(); break; |
case kw_firstcall: snp = ParseFirstcallStatement(); break; |
case kw_return: snp = ParseReturnStatement(); break; |
case kw_break: snp = ParseBreakStatement(); break; |
case kw_goto: snp = ParseGotoStatement(); break; |
case kw_continue: snp = ParseContinueStatement(); break; |
case kw_do: |
case kw_loop: snp = ParseDoStatement(); break; |
case kw_switch: snp = ParseSwitchStatement(); break; |
case kw_try: snp = ParseTryStatement(); break; |
case kw_throw: snp = ParseThrowStatement(); break; |
case kw_vortex: |
snp = vortex_stmt(); |
break; |
case kw_intoff: snp = ParseIntoffStatement(); break; |
case kw_inton: snp = ParseIntonStatement(); break; |
case kw_stop: snp = ParseStopStatement(); break; |
case kw_asm: |
snp = ParseAsmStatement(); break; |
case kw_critical: snp = ParseCriticalStatement(); break; |
case kw_spinlock: snp = ParseSpinlockStatement(); break; |
case kw_spinunlock: snp = ParseSpinunlockStatement(); break; |
case id: |
SkipSpaces(); |
if( lastch == ':' ) |
return ParseLabelStatement(); |
// else fall through to parse expression |
default: |
snp = ParseExpressionStatement(); |
break; |
} |
if( snp != NULL ) |
snp->next = NULL; |
return snp; |
} |
/Register.c
0,0 → 1,132
// ============================================================================ |
// (C) 2012 Robert Finch |
// All Rights Reserved. |
// robfinch<remove>@opencores.org |
// |
// C64 - Raptor64 'C' derived language compiler |
// - 64 bit CPU |
// |
// This source file is free software: you can redistribute it and/or modify |
// it under the terms of the GNU Lesser General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or |
// (at your option) any later version. |
// |
// This source file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public License |
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
// |
// ============================================================================ |
// |
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
int tmpregs[] = {3,4,5,6,7,8,9,10}; |
int regstack[8]; |
int rsp=7; |
int regmask=0; |
|
void initRegStack() |
{ |
for (rsp=0; rsp < 8; rsp=rsp+1) |
regstack[rsp] = tmpregs[rsp]; |
rsp = 0; |
} |
|
void GenerateTempRegPush(int reg, int rmode) |
{ |
AMODE *ap1; |
ap1 = allocAmode(); |
ap1->preg = reg; |
ap1->mode = rmode; |
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(8)); |
GenerateTriadic(op_sw,0,ap1,make_indirect(30),NULL); |
} |
|
void GenerateTempRegPop(int reg, int rmode) |
{ |
AMODE *ap1; |
ap1 = allocAmode(); |
ap1->preg = reg; |
ap1->mode = rmode; |
GenerateTriadic(op_lw,0,ap1,make_indirect(30),NULL); |
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(8)); |
} |
|
void initstack() |
{ |
initRegStack(); |
} |
|
AMODE *GetTempRegister() |
{ |
AMODE *ap; |
ap = allocAmode(); |
ap->mode = am_reg; |
ap->preg = PopFromRstk(); |
ap->deep = rsp; |
return ap; |
} |
|
int PopFromRstk() |
{ |
int reg = 0; |
|
if (rsp < 8) { |
reg = regstack[rsp]; |
rsp = rsp + 1; |
regmask |= (1 << (reg)); |
} |
else |
error(ERR_EXPRTOOCOMPLEX); |
return reg; |
} |
|
void PushOnRstk(int reg) |
{ |
if (rsp > 0) { |
rsp = rsp - 1; |
regstack[rsp] = reg; |
regmask &= ~(1 << (reg)); |
} |
else |
printf("DIAG - register stack underflow.\r\n"); |
} |
|
int SaveTempRegs() |
{ |
if (regmask != 0) { |
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(popcnt(regmask)*8)); |
GenerateTriadic(op_sm,0,make_indirect(30),make_mask(regmask),NULL); |
} |
return regmask; |
} |
|
void RestoreTempRegs(int rgmask) |
{ |
if (rgmask != 0) { |
GenerateTriadic(op_lm,0,make_indirect(30),make_mask(rgmask),NULL); |
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(popcnt(rgmask)*8)); |
} |
} |
|
void ReleaseTempRegister(struct amode *ap) |
{ |
if (ap==NULL) { |
printf("DIAG - NULL pointer in ReleaseTempRegister\r\n"); |
return; |
} |
if( ap->mode == am_immed || ap->mode == am_direct ) |
return; // no registers used |
if(ap->preg < 11 && ap->preg >= 3) |
PushOnRstk(ap->preg); |
} |
|
|
/ParseStructDeclaration.c
0,0 → 1,106
#include <stdio.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Copyright 2012 Robert Finch |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
extern TABLE tagtable; |
extern TYP *head; |
extern TYP stdconst; |
extern int bit_next; |
extern int bit_offset; |
extern int bit_width; |
|
__int16 typeno = bt_last; |
|
void ParseStructMembers(TYP *tp, int ztype); |
|
void ParseStructDeclaration(int ztype) |
{ |
SYM *sp; |
TYP *tp; |
bit_offset = 0; |
bit_next = 0; |
bit_width = -1; |
if(lastst == id) { |
if((sp = search(lastid,&tagtable)) == NULL) { |
sp = allocSYM(); |
sp->name = litlate(lastid); |
sp->tp = allocTYP(); |
sp->tp->type = ztype; |
sp->tp->typeno = typeno++; |
sp->tp->lst.head = 0; |
sp->storage_class = sc_type; |
sp->tp->sname = sp->name; |
NextToken(); |
if(lastst != begin) |
error(ERR_INCOMPLETE); |
else { |
insert(sp,&tagtable); |
NextToken(); |
ParseStructMembers(sp->tp,ztype); |
} |
} |
else |
NextToken(); |
head = sp->tp; |
} |
else { |
tp = allocTYP(); |
tp->type = ztype; |
tp->sname = 0; |
tp->lst.head = 0; |
if( lastst != begin) |
error(ERR_INCOMPLETE); |
else { |
NextToken(); |
ParseStructMembers(tp,ztype); |
} |
head = tp; |
} |
} |
|
void ParseStructMembers(TYP *tp, int ztype) |
{ |
int slc; |
slc = 0; |
tp->val_flag = 1; |
while( lastst != end) { |
if(ztype == bt_struct) |
slc += declare(&(tp->lst),sc_member,slc,ztype); |
else |
slc = imax(slc,declare(&tp->lst,sc_member,0,ztype)); |
} |
bit_offset = 0; |
bit_next = 0; |
bit_width = -1; |
tp->size = slc; |
NextToken(); |
} |
|
/Cglbdef.c
0,0 → 1,65
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
|
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
/* global definitions */ |
|
FILE *input = 0, |
*list = 0, |
*output = 0; |
|
int lineno = 0; |
int nextlabel = 0; |
int lastch = 0; |
int lastst = 0; |
char lastid[33] = ""; |
char laststr[MAX_STRLEN + 1] = ""; |
__int64 ival = 0; |
double rval = 0.0; |
|
TABLE gsyms[257],// = {0,0}, |
lsyms = {0,0}; |
SYM *lasthead = NULL; |
struct slit *strtab = 0; |
int lc_static = 0; |
int lc_auto = 0; |
struct snode *bodyptr = 0; |
int global_flag = 1; |
TABLE defsyms = {0,0}; |
int save_mask = 0; /* register save mask */ |
TYP tp_int, tp_econst; |
|
int isPascal = FALSE; |
int isOscall = FALSE; |
int isInterrupt = FALSE; |
int isNocall = FALSE; |
int optimize = TRUE; |
int exceptions = FALSE; |
SYM *currentFn = NULL; |
int callsFn = FALSE; |
|
/Cmain.c
0,0 → 1,130
#include <stdio.h> |
#include <string.h> |
#include "c.h" |
#include "expr.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
/******************************************************* |
Modified to support Raptor64 'C64' language |
by Robert Finch |
robfinch@opencores.org |
*******************************************************/ |
|
void makename(char *s, char *e); |
void summary(); |
int options(char *); |
int openfiles(char *); |
void closefiles(); |
|
char infile[20], |
listfile[20], |
outfile[20]; |
extern TABLE tagtable; |
int mainflag; |
extern int total_errors; |
int uctran_off; |
|
int main(int argc, char **argv) |
{ |
uctran_off = 0; |
while(--argc) { |
if( **++argv == '-') |
options(*argv); |
else if( openfiles(*argv)) { |
lineno = 0; |
initsym(); |
memset(gsyms,0,sizeof(gsyms)); |
getch(); |
NextToken(); |
compile(); |
summary(); |
ReleaseGlobalMemory(); |
closefiles(); |
} |
} |
getchar(); |
return 0; |
} |
|
int options(char *s) |
{ |
optimize =1; |
exceptions=1; |
if (s[1]=='o') |
optimize = 0; |
return 0; |
} |
|
int openfiles(char *s) |
{ |
int ofl; |
strcpy(infile,s); |
strcpy(listfile,s); |
strcpy(outfile,s); |
makename(listfile,".lis"); |
makename(outfile,".s"); |
if( (input = fopen(infile,"r")) == 0) { |
printf(" cant open %s\n",infile); |
return 0; |
} |
ofl = _creat(outfile,-1); |
if( ofl < 0 ) |
{ |
printf(" cant create %s\n",outfile); |
fclose(input); |
return 0; |
} |
if( (output = _fdopen(ofl,"w")) == 0) { |
printf(" cant open %s\n",outfile); |
fclose(input); |
return 0; |
} |
if( (list = fopen(listfile,"w")) == 0) { |
printf(" cant open %s\n",listfile); |
fclose(input); |
fclose(output); |
return 0; |
} |
return 1; |
} |
|
void makename(char *s, char *e) |
{ |
while(*s != 0 && *s != '.') |
++s; |
while(*s++ = *e++); |
} |
|
void summary() |
{ |
printf("\n -- %d errors found.",total_errors); |
fprintf(list,"\f\n *** global scope typedef symbol table ***\n\n"); |
ListTable(&gsyms,0); |
fprintf(list,"\n *** structures and unions ***\n\n"); |
ListTable(&tagtable,0); |
} |
|
void closefiles() |
{ |
fclose(input); |
fclose(output); |
fclose(list); |
} |
/GenerateShift.c
0,0 → 1,117
// ============================================================================ |
// (C) 2012 Robert Finch |
// All Rights Reserved. |
// robfinch<remove>@opencores.org |
// |
// C64 - Raptor64 'C' derived language compiler |
// - 64 bit CPU |
// |
// This source file is free software: you can redistribute it and/or modify |
// it under the terms of the GNU Lesser General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or |
// (at your option) any later version. |
// |
// This source file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public License |
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
// |
// ============================================================================ |
// |
#include <stdio.h> |
#include "c.h" |
#include "expr.h" |
#include "Statement.h" |
#include "gen.h" |
#include "cglbdec.h" |
|
|
AMODE *GenerateShift(ENODE *node,int flags, int size, int op) |
{ |
AMODE *ap1, *ap2; |
|
ap1 = GenerateExpression(node->p[0],F_REG,size); |
ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,8); |
switch(op) { |
case op_shru: |
switch (size) { |
case 8: GenerateTriadic(op_andi,0,ap1,ap1,make_immed(0xff)); break; |
case 16: GenerateTriadic(op_andi,0,ap1,ap1,make_immed(0xffff)); break; |
case 32: GenerateTriadic(op_andi,0,ap1,ap1,make_immed(0xffffffff)); break; |
default: ; |
} |
break; |
case op_shr: |
switch (size) { |
case 8: GenerateTriadic(op_sext8,0,ap1,ap1,NULL); break; |
case 16: GenerateTriadic(op_sext16,0,ap1,ap1,NULL); break; |
case 32: GenerateTriadic(op_sext32,0,ap1,ap1,NULL); break; |
default: ; |
} |
break; |
} |
if (ap2->mode==am_immed) { |
switch(op) |
{ |
case op_shl: op = op_shli; break; |
case op_shr: op = op_shri; break; |
case op_shru: op = op_shrui; break; |
} |
GenerateTriadic(op,0,ap1,ap1,make_immed(ap2->offset->i)); |
} |
else |
GenerateTriadic(op,0,ap1,ap1,ap2); |
ReleaseTempRegister(ap2); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
|
|
/* |
* generate shift equals operators. |
*/ |
struct amode *GenerateAssignShift(ENODE *node,int flags,int size,int op) |
{ |
struct amode *ap1, *ap2, *ap3; |
|
ap3 = GenerateExpression(node->p[0],F_ALL,size); |
ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,size); |
if (ap3->mode != am_reg) { |
ap1 = GetTempRegister(); |
GenerateDiadic(op_lw,0,ap1,ap3); |
} |
else |
ap1 = ap3; |
switch(op) { |
case op_shru: |
switch (size) { |
case 8: GenerateTriadic(op_andi,0,ap1,ap1,make_immed(0xff)); break; |
case 16: GenerateTriadic(op_andi,0,ap1,ap1,make_immed(0xffff)); break; |
case 32: GenerateTriadic(op_andi,0,ap1,ap1,make_immed(0xffffffff)); break; |
default: ; |
} |
break; |
case op_shr: |
switch (size) { |
case 8: GenerateTriadic(op_sext8,0,ap1,ap1,NULL); break; |
case 16: GenerateTriadic(op_sext16,0,ap1,ap1,NULL); break; |
case 32: GenerateTriadic(op_sext32,0,ap1,ap1,NULL); break; |
default: ; |
} |
break; |
} |
if (ap2->mode==am_immed) |
GenerateTriadic(op,0,ap1,ap1,make_immed(ap2->offset->i)); |
else |
GenerateTriadic(op,0,ap1,ap1,ap2); |
if (ap3->mode != am_reg) { |
GenerateDiadic(op_sw,0,ap1,ap3); |
} |
ReleaseTempRegister(ap2); |
MakeLegalAmode(ap1,flags,size); |
return ap1; |
} |
|
/Cglbdec.h
0,0 → 1,151
/* |
* 68000 C compiler |
* |
* Copyright 1984, 1985, 1986 Matthew Brandt. |
* all commercial rights reserved. |
* |
* This compiler is intended as an instructive tool for personal use. Any |
* use for profit without the written consent of the author is prohibited. |
* |
* This compiler may be distributed freely for non-commercial use as long |
* as this notice stays intact. Please forward any enhancements or questions |
* to: |
* |
* Matthew Brandt |
* Box 920337 |
* Norcross, Ga 30092 |
*/ |
|
/* global ParseSpecifierarations */ |
|
extern FILE *input, |
*list, |
*output; |
|
extern int lineno; |
extern int nextlabel; |
extern int lastch; |
extern int lastst; |
extern char lastid[33]; |
extern char laststr[MAX_STLP1]; |
extern __int64 ival; |
extern double rval; |
|
extern TABLE gsyms[257], |
lsyms; |
extern SYM *lasthead; |
extern struct slit *strtab; |
extern int lc_static; |
extern int lc_auto; |
extern struct snode *bodyptr; /* parse tree for function */ |
extern int global_flag; |
extern TABLE defsyms; |
extern int save_mask; /* register save mask */ |
extern int uctran_off; |
extern int isPascal; |
extern int isOscall; |
extern int isInterrupt; |
extern int isNocall; |
extern int asmblock; |
extern int optimize; |
extern int exceptions; |
extern SYM *currentFn; |
|
extern void error(int n); |
extern void needpunc(enum e_sym p); |
// Memmgt.c |
extern char *xalloc(int); |
extern SYM *allocSYM(); |
extern TYP *allocTYP(); |
extern AMODE *allocAmode(); |
|
// NextToken.c |
extern void initsym(); |
extern void NextToken(); |
extern int getch(); |
extern int isspace(char c); |
extern void getbase(b); |
extern void SkipSpaces(); |
|
// Stmt.c |
extern struct snode *ParseCompoundStatement(); |
|
extern void GenerateDiadic(int op, int len, struct amode *ap1,struct amode *ap2); |
// Symbol.c |
extern SYM *gsearch(char *na); |
extern SYM *search(char *na,SYM *thead); |
extern void insert(SYM* sp, TABLE *table); |
|
extern char *litlate(char *); |
// Decl.c |
extern void dodecl(int defclass); |
extern void ParseParameterDeclarations(int); |
extern void ParseAutoDeclarations(); |
extern void ParseSpecifier(TABLE *table); |
extern void ParseDeclarationPrefix(); |
extern void ParseStructDeclaration(int); |
extern void ParseEnumerationList(TABLE *table); |
|
extern void initstack(); |
extern int getline(int listflag); |
|
// Init.c |
extern void doinit(SYM *sp); |
// Func.c |
extern void funcbody(SYM *sp); |
// Intexpr.c |
extern int GetIntegerExpression(); |
// Expr.c |
extern ENODE *makenode(int nt, ENODE *v1, ENODE *v2); |
extern ENODE *makeinode(int nt, __int64 v1); |
extern TYP *expression(struct enode **node); |
extern int IsLValue(struct enode *node); |
// Optimize.c |
extern void opt4(struct enode **node); |
// GenerateStatement.c |
extern void GenerateStatement(struct snode *stmt); |
extern void GenerateFunction(struct snode *stmt); |
extern void GenerateIntoff(struct snode *stmt); |
extern void GenerateInton(struct snode *stmt); |
extern void GenerateStop(struct snode *stmt); |
extern void GenerateAsm(struct snode *stmt); |
extern void GenerateFirstcall(struct snode *stmt); |
extern void gen_regrestore(); |
extern AMODE *make_direct(__int64 i); |
// Outcode.c |
extern void GenerateByte(int val); |
extern void GenerateChar(int val); |
extern void genhalf(int val); |
extern void GenerateWord(__int64 val); |
extern void GenerateLong(int val); |
extern void genstorage(int nbytes); |
extern void GenerateReference(SYM *sp,int offset); |
extern void GenerateLabelReference(int n); |
extern void gen_strlab(char *s); |
extern void dumplits(); |
extern int stringlit(char *s); |
extern void nl(); |
extern void cseg(); |
extern void dseg(); |
extern void put_code(int op, int len,AMODE *aps, AMODE *apd, AMODE *); |
extern void put_label(int lab); |
// Peepgen.c |
extern void flush_peep(); |
extern void GenerateLabel(int labno); |
// Gencode.c |
extern AMODE *make_label(__int64 lab); |
extern AMODE *make_immed(__int64); |
extern AMODE *make_indirect(int i); |
extern AMODE *make_offset(struct enode *node); |
extern void swap_nodes(struct enode *node); |
extern int isshort(struct enode *node); |
// IdentifyKeyword.c |
extern int IdentifyKeyword(); |
// Preproc.c |
extern int preprocess(); |
// CodeGenerator.c |
extern AMODE *make_indirect(int i); |
extern AMODE *make_indexed(__int64 o, int i); |
extern void GenerateFalseJump(struct enode *node,int label); |
|
|