Category : Assembly Language Source Code
Archive   : CAS8051.ZIP
Filename : ST.C

 
Output of file : ST.C contained in archive : CAS8051.ZIP

#include
#include
#include
#include
#include "io.h"
#include "ex.h"
#include "op.h"
#include "res.h"

#define MAX_ST 20
typedef enum { BotS, IfS, ElseS, GroupS } StTag;
byte Active;
int Phase;

StTag SStack[MAX_ST], *SP;
byte IStack[MAX_ST], *IP;

void PUSH(StTag Tag) {
if (SP >= SStack + MAX_ST) FATAL("Statement too complex");
*SP++ = Tag;
}

void SetColon(byte Glo, Symbol Sym) {
if (!Active) return;
if (Sym->Defined) {
if (*Sym->Name != '#') {
ERROR("Attempting to redefine %s.", Sym->Name); return;
} else if (Glo) {
ERROR("Attempting to make local label global."); return;
} else {
Sym->Address = 1, Sym->Global = 0, Sym->Variable = 1;
}
} else if (Sym->Global) {
if (!Glo) {
ERROR("Symbol %s already declared as external.", Sym->Name); return;
} else if (!Sym->Address) {
ERROR("Symbol %s already declared as number.", Sym->Name); return;
} else if (Sym->Seg->Type != SegP->Type) {
ERROR("Type mismatch: %s.", Sym->Name); return;
}
} else
Sym->Address = 1, Sym->Global = Glo, Sym->Variable = 0;
Sym->Defined = 1, Sym->Seg = SegP, Sym->Offset = LOC;
}

void SetVar(byte Glo, Symbol Sym, Exp E) {
if (!Active) return;
if (Sym->Defined && !Sym->Variable)
ERROR("Symbol %s already defined as constant.", Sym->Name);
else if (Glo)
ERROR("Variables cannot be made global.");
else if (Sym->Global)
ERROR("Symbol %s already declared as external.", Sym->Name);
else if (!Sym->Defined) {
if (E->Tag == AddrX)
Sym->Address = 1, Sym->Seg = SEG(E), Sym->Offset = OFFSET(E);
else
Sym->Address = 0, Sym->Offset = VALUE(E);
Sym->Variable = 1, Sym->Defined = 1;
} else if (Sym->Address) {
if (E->Tag != AddrX)
Sym->Seg = SegTab + Sym->Seg->Type, Sym->Offset = VALUE(E);
else if (SEG(E)->Type != Sym->Seg->Type)
ERROR("Type mismatch: %s.", Sym->Name);
else
Sym->Seg = SEG(E), Sym->Offset = OFFSET(E);
} else if (E->Tag == AddrX) {
if (SEG(E)->Rel)
ERROR("Symbol %s cannot be set to relative address.", Sym->Name);
else
Sym->Offset = SEG(E)->Base + OFFSET(E);
} else
Sym->Offset = VALUE(E);
}

void SetConst(byte Glo, byte Addr, byte Type, Symbol Sym, Exp E) {
if (!Active) return;
if (Addr && E->Tag == AddrX && SEG(E)->Type != Type) {
ERROR("Expression type does not match."); return;
} else if (Sym->Defined) {
ERROR("Symbol %s already defined.", Sym->Name); return;
} else if (!Sym->Global)
Sym->Global = Glo, Sym->Variable = 0, Sym->Address = (E->Tag == AddrX);
else if (!Glo) {
ERROR("Symbol %s already declared as external.", Sym->Name); return;
} else if (Sym->Address) {
if (Addr && Sym->Seg->Type != Type) {
ERROR("Symbol %s's type does not match.", Sym->Name); return;
} else if (E->Tag != AddrX) {
Sym->Defined = 1, Sym->Offset = VALUE(E); return;
} else if (SEG(E)->Type != Sym->Seg->Type) {
ERROR("Type mismatch: %s.", Sym->Name); return;
}
} else if (Addr) {
ERROR("Symbol %s already declared as external number.", Sym->Name);
return;
} else if (E->Tag == AddrX) {
if (SEG(E)->Rel) {
ERROR("Symbol %s cannot be equated to relative address.", Sym->Name);
return;
} else {
Sym->Defined = 1, Sym->Offset = SEG(E)->Base + OFFSET(E); return;
}
}
Sym->Defined = 1;
if (E->Tag == AddrX)
Sym->Seg = SEG(E), Sym->Offset = OFFSET(E);
else
Sym->Offset = VALUE(E);
}

FILE *OpenObj(char *Obj) {
FILE *FP; word MAGIC = 0x55aa;
unsigned long L = 0; int I;
FP = fopen(Obj, "wb");
if (FP == 0) return 0;
PutW(MAGIC, FP);
for (I = 0; I < 8; I++) PutL(L, FP); /* Empty the header */
fclose(FP);
FP = fopen(Obj, "rb+");
if (FP == 0) return 0;
fseek(FP, 34L, SEEK_SET); /* Skip the header */
return FP;
}

void Assemble(char *Path) {
Lexical L; Exp E; byte Glo, Addr, Type; Symbol Label;
Phase = 0;
SymInit(), FileInit(), SegInit(), ExpInit(), ResInit();
IP = IStack, SP = SStack;
Active = 1; RegInit(); OpenF(Path); L = Scan();
START:
if (L == 0) { EndSeg(); return; }
PUSH(BotS);
STATEMENT:
StartLine = Line, StartF = CurF;
switch (L) {
case IF:
L = Scan();
if (L != LPAR) ERROR("Missing '(' in 'if (...)'"); else Scan();
E = Parse(0);
PUSH(IfS), *IP++ = Active;
if (Active) Active = VALUE(E);
L = OldL;
if (L != RPAR) ERROR("Missing ')' in 'if (...)'."); else L = Scan();
goto STATEMENT;
case LCURL:
L = Scan();
if (L == RCURL) { L = Scan(); goto END_ST; }
PUSH(GroupS);
goto STATEMENT;
case SEMI: L = Scan(); goto END_ST;
case RB:
Scan(), InSemi = 1, E = Parse(0);
Space(VALUE(E));
goto SEM;
case RW:
Scan(), InSemi = 1, E = Parse(0);
Space(2*VALUE(E));
goto SEM;
case SEG:
L = Scan();
if (L != TYPE) { ERROR("Expected segment type."); goto PURGE; }
if (Value != CODE && Value != XDATA && Value != DATA) {
ERROR("Only code, xdata, or data segments allowed."); goto PURGE;
}
Type = Value;
InSemi = 1, L = Scan();
if (L == ORG) { InSemi = 0; goto DoOrg; }
if (Active) EndSeg(), StartSeg(Type, 1, 0);
goto SEM;
case ORG:
Type = SegP->Type;
DoOrg:
Scan(), InSemi = 1, E = Parse(0);
if (Active) EndSeg(), StartSeg(Type, 0, VALUE(E));
goto SEM;
case INCLUDE: {
char *S;
L = Scan();
if (L != STRING) FATAL("Missing filename in 'include'.");
S = CopyS(Text);
InSemi = 1, L = Scan();
if (L != SEMI) FATAL("Missing ';' after include statement.");
OpenF(S), free(S);
InSemi = 0, L = Scan();
}
goto END_ST;
case GLOBAL:
Glo = 1;
L = Scan();
if (L != SYMBOL) {
ERROR("Expected symbol after 'global'"); goto PURGE;
}
goto DEFINE;
case SYMBOL:
Glo = 0;
DEFINE:
Label = Sym; L = Scan();
switch (L) {
case COLON:
SetColon(Glo, Label);
InSemi = 1, L = Scan(), InSemi = 0;
goto STATEMENT;
case SET:
Scan(), InSemi = 1, E = Parse(1), SetVar(Glo, Label, E);
goto SEM;
case TYPE: Type = Value, Addr = 1; goto DoEqu;
case EQU: Type = 0, Addr = 0;
DoEqu:
Scan(), InSemi = 1, E = Parse(1);
SetConst(Glo, Addr, Type, Label, E);
goto SEM;
default: ERROR("Undefined symbol: %s.", Label->Name); goto PURGE;
}
break;
case EXTERN:
L = Scan();
if (L == EQU) Addr = 0;
else if (L == TYPE) Addr = 1, Type = Value;
else {
ERROR("Expected type or 'equ' after 'extern'."); goto PURGE;
}
InSemi = 1;
do {
L = Scan();
if (L != SYMBOL) {
ERROR("Expected symbol in 'extern'"); goto PURGE;
}
if (Active) {
if (Sym->Global) {
byte Addr1 = Sym->Address;
if (!Addr && Addr1)
ERROR("Redeclaring number %s as address.", Sym->Name);
else if (Addr && !Addr1)
ERROR("Redeclaring address %s as number.", Sym->Name);
else if (Addr && Addr1 && Type != Sym->Seg->Type)
ERROR("Type mismatch: %s.", Sym->Name);
} else if (Sym->Defined)
ERROR("Redeclaring local symbol %s as external.", Sym->Name);
else {
Sym->Global = 1;
if (Addr) Sym->Address = 1, Sym->Seg = SegTab + Type;
}
}
Scan();
} while (OldL == COMMA);
goto SEM;
case DB:
InSemi = 1;
do {
L = Scan();
if (L == STRING) PString(Text), Scan();
else Reloc(0, 'b', Parse(2));
} while (OldL == COMMA);
goto SEM;
case DW:
InSemi = 1;
do
Scan(), Reloc(0, 'w', Parse(2));
while (OldL == COMMA);
goto SEM;
case END:
if (Active) { EndSeg(); return; }
InSemi = 1, Scan();
goto SEM;
case MNEMONIC: InSemi = 1, ParseArgs((byte)Value); goto SEM;
default: ERROR("Syntax error"); goto PURGE;
}
PURGE:
InSemi = 1;
while (L != SEMI) {
if (L == 0) { InSemi = 0; goto END_ST; }
L = Scan();
}
SEM:
InSemi = 0; L = OldL;
if (L != SEMI) ERROR("Missing ';'"); else L = Scan();
END_ST:
switch (*--SP) {
case BotS: goto START;
case IfS:
if (L == ELSE) {
if (IP == IStack || IP[-1]) Active = !Active;
*SP++ = ElseS, L = Scan(); goto STATEMENT;
}
case ElseS: EndIf:
if (*--IP && !Active) {
Active = 1;
if (L == SYMBOL) Sym = LookUp(Text);
}
goto END_ST;
case GroupS:
if (L == RCURL) { L = Scan(); goto END_ST; }
if (L == 0) { ERROR("Missing '}'."); goto END_ST; }
*SP++ = GroupS;
goto STATEMENT;
}
}

static void Purge(void) {
Symbol Sym, NextS; Exp E, NextE; char **F;
for (Sym = NIL->Next[0]; Sym != NIL; Sym = NextS)
NextS = Sym->Next[0], free(Sym->Name), free(Sym);
for (F = FileTab; F < FileTab + Files; F++) free(*F);
free(FileTab);
free(NIL);
for (E = ExpHead; E != 0; E = NextE) NextE = E->Next, free(E);
free(RTab);
}

void Generate(void) {
Symbol S; Segment Seg; Exp E; Item IP; word Value, File; Gap G;
unsigned long SegLoc, Segs, Gaps, Syms, Exps, Relocs, Sum;
Phase = 1;
SegLoc = ftell(OutF), Segs = SegP - SegTab, Gaps = GapP - GapTab;
for (IP = RTab; IP < RTab + RCur; IP++) Resolve(IP);
fseek(OutF, SegLoc, SEEK_SET); /* Skip the code image */
for (File = 0; File < Files; File++) {
word L = strlen(FileTab[File]);
PutW(L, OutF), fwrite(FileTab[File], 1, L, OutF);
}
for (Seg = SegTab + TYPES; Seg < SegP; Seg++) {
word U = (Seg->Rel&1) << 8 | Seg->Type&0xff;
PutW(Seg->Line, OutF), PutW(Seg->File, OutF),
PutW(U, OutF), PutW(Seg->Size, OutF),
PutW(Seg->Base, OutF), PutL(Seg->Loc, OutF);
}
for (G = GapTab; G < GapP; G++)
PutW(G->Seg - SegTab, OutF), PutW(G->Offset, OutF), PutW(G->Size, OutF);
for (Syms = 0, S = NIL->Next[0]; S != NIL; S = S->Next[0])
if (S->Map || S->Global && S->Defined) {
byte B = (S->Global&1) << 3 | (S->Defined&1) << 2 |
(S->Address&1) << 1 | (S->Variable&1);
word U = S->Seg - SegTab, L = strlen(S->Name);
if (!S->Global && !S->Defined)
ERROR("Undefined symbol: %s.", S->Name);
S->Index = Syms++;
PutB(B, OutF), PutW(U, OutF), PutW(S->Offset, OutF), PutW(L, OutF);
if (L > 0) fwrite(S->Name, 1, L, OutF);
}
for (Exps = 0, E = ExpHead; E != 0; E = E->Next)
if (E->Map) {
byte Tag = E->Tag, Op; word U;
E->Hash = Exps++;
PutW(E->Line, OutF), PutW(E->File, OutF), PutB(Tag, OutF);
switch (Tag) {
case NumX: PutW(VALUE(E), OutF); break;
case AddrX:
PutW(SEG(E) - SegTab, OutF), PutW(OFFSET(E), OutF);
break;
case SymX: PutW(SYM(E)->Index, OutF); break;
case UnX:
Op = OP(E);
PutB(Op, OutF), PutW(ARG1(E)->Hash, OutF);
break;
case BinX:
Op = OP(E);
PutB(Op, OutF), PutW(ARG1(E)->Hash, OutF),
PutW(ARG2(E)->Hash, OutF);

break;
case CondX:
PutW(ARG1(E)->Hash, OutF), PutW(ARG2(E)->Hash, OutF),
PutW(ARG3(E)->Hash, OutF);
break;
}
}
for (Relocs = 0, IP = RTab; IP < RTab + RCur; IP++)
if (IP->Map) {
word U = IP->Seg - SegTab;
Relocs++;
PutW(IP->Line, OutF), PutW(IP->File, OutF),
PutB(IP->Tag, OutF), PutW(IP->E->Hash, OutF),
PutW(U, OutF),
PutW(IP->Offset, OutF);
}
fseek(OutF, 2L, SEEK_SET); /* Do the header */
PutL(SegLoc, OutF), PutL(Files, OutF), PutL(Segs, OutF),
PutL(Gaps, OutF), PutL(Syms, OutF), PutL(Exps, OutF), PutL(Relocs, OutF);
Sum = SegLoc + Files + Segs + Gaps + Syms + Exps + Relocs;
PutL(Sum, OutF);
fclose(OutF);
Purge();
}