Анализатор вершины стека (пример того, как не надо делать)
Приведенный ниже компилятор использует стек для временного хранения
символов, грамматика преобразована так,
чтобы выбор подходящего правила мог быть основан на порядке их следования.
Файл c.def:
symb ;
numb ;
name ;
type ;
var ;
array ;
fn ;
lsb "[" 0 0;
rsb "]" 0 0;
lcb "(" 0 0;
rcb ")" 0 0;
assign ":=" 0 0;
plus "+" 0 0;
minus "-" 0 1;
star "*" 0 2;
slash "/" 0 3;
pct "%" 0 4;
lt "<" 0 0;
le "<=" 0 1;
eq "=" 0 2;
ne "!=" 0 3;
ge ">=" 0 4;
gt ">" 0 5;
comma "," 0 0;
semi ";" 0 0;
is 0 0;
begin 0 0;
if 0 0;
then 0 0;
while 0 0;
do 0 0;
inline 0 0;
return 0 0;
end 0 0;
char 1 1;
byte 1 1;
word 1 2.
Program : 10 Declarations Main Stmts end
| 10 Main Stmts end
;
Declarations : 0 Declarations Declaration
| 0 Declaration
;
Declaration : 20 TypeName semi
| 30 TypeName lsb numb rsb semi
| 10 Header Stmts end
;
Header : 40 TypeName lcb Args TypeName rcb is
| 50 TypeName lcb TypeName rcb is
| 0 TypeName lcb rcb is
;
Args : 0 Args Arg
| 0 Arg
;
Arg : 60 TypeName comma
;
TypeName : 70 type name
;
Main : 80 begin
;
Stmts : 90 Stmts Stmt
| 90 Stmt
;
Stmt : 100 IfBlk
| 100 WhileBlk
| 100 Inlines
| 110 Ret
| 100 Local
| 100 Assign
| 100 PCall
;
IfBlk : 120 IfHdr Stmts end
;
IfHdr : 130 if Comp symb then
| 130 if Comp numb then
| 140 if Comp Ref then
| 150 if Comp Call then
| 150 if Comp Cast then
| 150 if Comp Expr then
;
WhileBlk : 160 WhileHdr Stmts end
;
WhileHdr : 130 Loop Comp symb do
| 130 Loop Comp numb do
| 140 Loop Comp Ref do
| 150 Loop Comp Call do
| 150 Loop Comp Cast do
| 150 Loop Comp Expr do
;
Loop : 170 while
;
Inlines : 0 Opcodes semi
;
Opcodes : 180 Opcodes comma numb
| 190 inline numb
;
Ret : 200 return symb semi
| 200 return numb semi
| 210 return Ref semi
| 220 return Call semi
| 220 return Cast semi
| 220 return Expr semi
;
Local : 230 TypeName assign symb semi
| 230 TypeName assign numb semi
| 240 TypeName assign Ref semi
| 250 TypeName assign Call semi
| 250 TypeName assign Cast semi
| 250 TypeName assign Expr semi
;
Assign : 260 Ref assign symb semi
| 260 Ref assign numb semi
| 270 Ref assign Ref semi
| 280 Ref assign Call semi
| 280 Ref assign Cast semi
| 280 Ref assign Expr semi
;
PCall : 0 Call semi
;
Comp : 290 symb RelOp
| 290 numb RelOp
| 300 Ref RelOp
| 310 Call RelOp
| 310 Cast RelOp
| 310 Expr RelOp
;
Left : 290 numb Op
| 300 Ref Op
| 310 Call Op
| 310 Cast Op
| 310 Expr Op
| 310 Value Op
;
Ref : 0 var
| 320 array lsb numb rsb
| 330 array lsb Ref rsb
| 340 array lsb Call rsb
| 340 array lsb Cast rsb
| 340 array lsb Expr rsb
;
Call : 350 Fn2 lcb Params symb rcb
| 350 Fn2 lcb Params numb rcb
| 360 Fn2 lcb Params Ref rcb
| 370 Fn2 lcb Params Call rcb
| 370 Fn2 lcb Params Cast rcb
| 370 Fn2 lcb Params Expr rcb
| 380 Fn2 lcb symb rcb
| 380 Fn2 lcb numb rcb
| 390 Fn2 lcb Ref rcb
| 370 Fn2 lcb Call rcb
| 370 Fn2 lcb Cast rcb
| 370 Fn2 lcb Expr rcb
| 400 Fn2 lcb rcb
;
Params : 0 Params Param
| 0 Param
;
Param : 410 symb comma
| 410 numb comma
| 420 Ref comma
| 430 Call comma
| 430 Cast comma
| 430 Expr comma
;
Fn2 : 440 fn
;
Cast : 450 type lcb symb rcb
| 450 type lcb numb rcb
| 460 type lcb Ref rcb
| 0 type lcb Call rcb
| 0 type lcb Expr rcb
;
Expr : 470 Left numb
| 480 Left Ref
| 490 Left Call
| 490 Left Cast
| 490 Left Value
;
Value : 0 lcb Expr rcb
;
RelOp : 0 lt
| 0 le
| 0 eq
| 0 ne
| 0 ge
| 0 gt
;
Op : 0 plus
| 0 minus
| 0 star
| 0 slash
| 0 pct
.
Файл c.prg, компилятор не умещается в тысячу строк:
char Text [16384];
word pText;
word nText;
word nLine;
byte Code [16384];
word nCode;
word hFile;
char Heap [ 2048];
word nHeap;
word Jx [ 6];
word nData;
word Name [ 256];
word Cls [ 256];
word Sub [ 256];
word Type [ 256];
word Size [ 256];
word Ofs [ 256];
word nName;
word Sym [ 96];
word nSym;
word Left [ 192];
word Id [ 192];
word pRight [ 192];
word Len [ 192];
word nLeft;
word Right [ 640];
word pLeft [ 640];
word nRight;
word Stk [ 32];
word Val [ 32];
word Ptr [ 32];
word Frame [ 32];
word nStk;
char Buff [ 32];
word open() is
inline 0xB4, 0x3D; // mov AH, 3DH
inline 0xB0, 0x00; // mov AL, 0
inline 0xBA, 0x4A, 0xC1; // mov DX, @@DATA+Ofs(Heap[64])
inline 0xCD, 0x21; // int 21H
end
word create() is
inline 0xB4, 0x3C; // mov AH, 3CH
inline 0xB9, 0x00, 0x00; // mov CX, 0
inline 0xBA, 0x4A, 0xC1; // mov DX, @@DATA+Ofs(Heap[64])
inline 0xCD, 0x21; // int 21H
end
word read() is
inline 0xB4, 0x3F; // mov AH, 3FH
inline 0x8B, 0x1E, 0x08, 0xC1; // mov BX, word [@@DATA+Ofs(hFile)]
inline 0xB9, 0x00, 0x40; // mov CX, 16384
inline 0xBA, 0x00, 0x41; // mov DX, @@DATA+Ofs(Text)
inline 0xCD, 0x21; // int 21H
end
word write() is
inline 0xB4, 0x40; // mov AH, 40H
inline 0x8B, 0x1E, 0x08, 0xC1; // mov BX, word [@@DATA+Ofs(hFile)]
inline 0x8B, 0x0E, 0x06, 0xC1; // mov CX, word [@@DATA+Ofs(nCode)]
inline 0xBA, 0x06, 0x81; // mov DX, @@DATA+Ofs(Code)
inline 0xCD, 0x21; // int 21H
end
word close() is
inline 0xB4, 0x3E; // mov AH, 3EH
inline 0x8B, 0x1E, 0x08, 0xC1; // mov BX, word [@@DATA+Ofs(hFile)]
inline 0xCD, 0x21; // int 21H
end
char putc(char C) is
char C1:=C;
inline 0x92; // xchg DX, AX
inline 0xB4, 0x02; // mov AH, 2
inline 0xCD, 0x21; // int 21H
end
word halt() is
inline 0xB8, 0x00, 0x4C; // mov AX, 4C00H
inline 0xCD, 0x21; // int 21H
end
word Init() is
Heap [ 0]:='0';
Heap [ 1]:='1';
Heap [ 2]:='2';
Heap [ 3]:='3';
Heap [ 4]:='4';
Heap [ 5]:='5';
Heap [ 6]:='6';
Heap [ 7]:='7';
Heap [ 8]:='8';
Heap [ 9]:='9';
Heap [ 10]:='A';
Heap [ 11]:='B';
Heap [ 12]:='C';
Heap [ 13]:='D';
Heap [ 14]:='E';
Heap [ 15]:='F';
Heap [ 16]:='#';
Heap [ 17]:= char(0);
Heap [ 64]:='c';
Heap [ 65]:='.';
Heap [ 66]:='d'; // p
Heap [ 67]:='e'; // r
Heap [ 68]:='f'; // g
Heap [ 69]:= char(0);
nHeap := 70;
Sym [ 1]:= 16; // #
nSym := 2;
Jx [ 0]:= 0x72;
Jx [ 1]:= 0x76;
Jx [ 2]:= 0x74;
Jx [ 3]:= 0x75;
Jx [ 4]:= 0x73;
Jx [ 5]:= 0x77;
end
word Stop() is
nStk:=0;
while nLine!=0 do
Stk[nStk]:=nLine%10;
nStk :=nStk+1;
nLine :=nLine/10;
end
while nStk !=0 do
nStk :=nStk-1;
putc(char(Stk[nStk]+48));
end
close();
halt ();
end
word val () is
word E:=10;
word J:= 0;
if Buff[0]='0' then
if Buff[1]='x' then
E:=16;
J:= 2;
end
end
word N:=0;
while Buff[J]!=char(0) do
word K:=0;
while Heap[K]!=Buff[J] do
if K=E then
Stop();
end
K:=K+1;
end
N:=E*N;
N:=N+K;
J:=J+1;
end
return N;
end
word Copy() is
word pHeap:=nHeap;
word pBuff:=0;
while Buff[pBuff]!=char(0) do
Heap[nHeap]:= Buff[pBuff];
nHeap :=nHeap+1;
pBuff :=pBuff+1;
end
Heap[nHeap]:=char(0);
nHeap :=nHeap+1;
return pHeap;
end
word Comp(word pHeap) is
word pBuff:=0;
while Buff[pBuff]=Heap[pHeap] do
if Buff[pBuff]=char(0) then
return 0;
end
pHeap:=pHeap+1;
pBuff:=pBuff+1;
end
return 1;
end
char Look() is
if pText>=nText then
pText:=0;
nText:=read();
if pText>=nText then
return char(0);
end
end
return Text[pText];
end
char Read() is
char C:=Look();
pText :=pText+1;
return C;
end
word isalpha (char C) is
if 'A'<=C then
if C<='Z' then
return 0;
end
end
if 'a'<=C then
if C<='z' then
return 0;
end
end
return 1;
end
word isnumber(char C) is
if '0'<=C then
if C<='9' then
return 0;
end
end
return 1;
end
word isalnum (char C) is
if isalpha (C)=0 then
return 0;
end
if isnumber(C)=0 then
return 0;
end
return 1;
end
word Digraph(char C1, char C2) is
if Buff[0]=C1 then
if Look()=C2 then
Buff[1]:=Read();
Buff[2]:=char(0);
end
end
end
char Scan() is
word pBuff:=0;
while pBuff =0 do
word sFlag:=0;
while sFlag =0 do
if Look()!=char( 9) then
if Look()!=char(10) then
if Look()!=char(13) then
if Look()!=char(32) then
sFlag:=1;
end
end
end
end
if sFlag=0 then
if Read()=char(10) then
nLine:=nLine+1;
end
end
end
//if pBuff=0 then
while isalnum(Look())=0 do
Buff[pBuff]:= Read();
pBuff :=pBuff+1;
end
//end
if pBuff=0 then
Buff[pBuff]:= Read();
pBuff :=pBuff+1;
end
if Buff[0]=''' then
Buff[pBuff]:=Read(); // char
pBuff :=pBuff+1;
Buff[pBuff]:=Read(); // '
pBuff :=pBuff+1;
end
Buff[pBuff] :=char(0);
Digraph('<', '=');
Digraph('!', '=');
Digraph('>', '=');
Digraph(':', '=');
if Buff[0]='/' then
if Look()='/' then
while Look()!=char(10) do
if Read()=char( 0) then
Stop();
end
end
pBuff:=0;
end
end
end
end
word pSymb;
word pProg;
word L;
word V;
word Alter() is
L:=1;
word pName:=0;
while pName =3 then
Emi1(0x93); // xchg BX, AX
Emi1(0x33); // xor DX, DX
Emi1(0xD2);
Emi1(0xF7); // div BX
Emi1(0xF3);
end
if Op=4 then
Emi1(0x92); // xchg DX, AX
end
end
word Cond() is
Pop ();
Emi1(0x3B); // cmp BX, AX
Emi1(0xD8);
Emi1(Jx[Val[nStk+1]]);// jxx Ofs
Emi1(0x03);
Ptr[nStk]:= Val[nStk];
Val[nStk]:=nCode;
Emi1(0xE9); // jmp ?
nCode :=nCode+2;
lFlag :=0;
end
word Shl () is
if Size[Type[Val[nStk]]]!=1 then
Emi1(0xD1); // shl AX, 1
Emi1(0xE0);
end
end
word Save(word I) is
if Cls[I]=3 then
Pop ();
end
byte C:=0x89; // mov [(BX+)Ofs], AX
if Size[Type[I]]=1 then
C:=0x88; // mov [(BX+)Ofs], AL
end
Move(I, C);
end
word pParm;
word Pass() is
if pParm>=nName then
Stop();
end
if Sub[pParm]!=1 then
Stop();
end
Save(pParm);
pParm:=pParm+1;
lFlag:=0;
end
word Call() is
if pParm=Len[I] then
word J:=nStk-Len[I];
word K:=pRight[I];
while Stk[J]=Right[K] do
if Stk[J]=0 then
return I;
end
J:=J+1;
K:=K+1;
end
end
I:=I+1;
end
return I;
end
word Compile() is
Heap [ 66]:='p';
Heap [ 67]:='r';
Heap [ 68]:='g';
hFile := open();
pText := 0;
nText := 0;
nLine := 1;
lFlag := 0;
rFlag := 0;
nCode := 0;
nData :=16640;
Emi1(0xE9); // jmp ?
Emi2(0x00);
Stk [0] := 1; // #
nStk := 0;
while Stk[0]!=pProg do
Scan ();
Alter();
if nStk>=32 then
Stop();
end
Stk [nStk]:=L;
Val [nStk]:=V;
nStk :=nStk+1;
word I:=CheckTop();
while I< nLeft do
nStk :=nStk-Len[I];
Stk[nStk]:=Left[I];
Action(Id[I]);
nStk :=nStk+1;
I:=CheckTop();
end
end
close();
Heap [ 66]:='c';
Heap [ 67]:='o';
Heap [ 68]:='m';
hFile:=create();
write();
close();
end
begin
Init();
LoadGrammar();
Compile();
end