📄 st.c
字号:
#include <stdlib.h>#include <stdio.h>#include <ctype.h>#include <string.h>#include "io.h"#include "ex.h"#include "op.h"#include "res.h"#define MAX_ST 20typedef 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();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -