Тот же текст, но в структуре NODE вместо индексов
используются ссылки:
define @emNOMEMORY "Недостаточно памяти"
define @emSIZE "Слишком длинный идентификатоp"
define @emEOF "Конец файла"
define @emNUMBER "Ошибка в константе"
define @emNAME "Пpопущено имя"
define @emEMPTY "Пустой массив"
define @emBRACKET "Пpопущена скобка"
define @emCOMMA "Пpопущена запятая"
define @emSEMICOLON "Пpопущена точка с запятой"
define @emTHENEXP "Пpопущено then"
define @emDOEXP "Пpопущено do"
define @emDUP "Повтоpное описание"
define @emLVALUE "Пpопущена пеpеменная"
define @emTYPE "Несоответствие типов"
define @emUNDEFINED "Пеpеменная не опpеделена"
define @emUNDEFOPR "Опеpация не опpеделена"
define @emASSIGN "Пpопущено ="
define ntSIZE 4096
define tbSIZE 4096
define dtSIZE 128
define idSIZE 16
define ttWORD 0
define ttBOOL 1
define ptZERO 0
define ptBOOL 1
define ptCOMP 2
define ptADD 3
define ptMUL 4
define ptLVALUE 5
define idEMPTY 0
define idNUMBER 1
define idVARIABLE 2
define idOR 3
define idAND 4
define idLT 5
define idLE 6
define idEQ 7
define idNE 8
define idGE 9
define idGT 10
define idADD 11
define idSUB 12
define idMUL 13
define idDIV 14
define idIF 15
define idWHILE 16
define idWRITE 17
define idBLANK 18
define idASSIGN 19
struct NODE
word ID;
word Value;
NODE @Left;
NODE @Right;
end
struct DATA
char Name [idSIZE];
word Ofs;
word Index;
end
NODE Node [ntSIZE];
word nNode;
DATA Data [dtSIZE];
word nData;
char Text [tbSIZE];
word hText;
word nText;
word pText;
char Name [128];
word Line;
void @Ptr(word Seg, Ofs)
void @P1=@Ofs;
void @@P2=@P1;
return @P2;
end
word isalpha(char Ch)
if ('A'<=Ch & Ch<='Z') | ('a'<=Ch & Ch<='z') | (Ch='_') then
return 0;
end
return 1;
end
word isdigit(char Ch)
if ('0'<=Ch & Ch<='9') then
return 0;
end
return 1;
end
word strlen(char @Buff)
word P=0;
while Buff[P]!=#0 do
inc P;
end
return P;
end
word strcmp(char @St1, @St2)
word P=0;
while St1[P]=St2[P] do
if St1[P]=#0 then
return 0;
end
inc P;
end
return 1;
end
char @strcpy(char @Dst, @Src)
word P=0;
while Src[P]!=#0 do
Dst[P]=Src[P];
inc P;
end
Dst[P]=#0;
return @Dst;
end
char @strcat(char @Dst, @Src)
word P=strlen(@Dst);
word Q=0;
while Src[Q]!=#0 do
Dst[P]=Src[Q];
inc P;
inc Q;
end
Dst[P]=#0;
return @Dst;
end
word GetPSP()
asm mov AH,62H
asm int 21H
asm mov AX,BX
end
word open(char @Name)
asm push DS
asm mov AH,3DH
asm mov AL,00H
asm mov DX,SS:[BP+6]
asm mov DS,DX
asm mov DX,SS:[BP+4]
asm int 21H
asm pop DS
end
word create(char @Name)
asm push DS
asm mov AH,3CH
asm mov CX,00H
asm mov DX,SS:[BP+6]
asm mov DS,DX
asm mov DX,SS:[BP+4]
asm int 21H
asm pop DS
end
word read(word F; void @Buff; word N)
asm push DS
asm mov AH,3FH
asm mov BX,SS:[BP+10]
asm mov CX,SS:[BP+4]
asm mov DX,SS:[BP+8]
asm mov DS,DX
asm mov DX,SS:[BP+6]
asm int 21H
asm pop DS
end
word write(word F; void @Buff; word N)
asm push DS
asm mov AH,40H
asm mov BX,SS:[BP+10]
asm mov CX,SS:[BP+4]
asm mov DX,SS:[BP+8]
asm mov DS,DX
asm mov DX,SS:[BP+6]
asm int 21H
asm pop DS
end
void close(word F)
asm mov AH,3EH
asm mov BX,SS:[BP+4]
asm int 21H
end
void putc(char Ch)
asm mov AH,2
asm mov DL,SS:[BP+4]
asm int 21H
end
void puts(char @St)
word P=0;
while St[P]!=#0 do
putc(St[P]);
inc P;
end
end
word str(word N; word S; char @Buff)
if S>0 then
dec S;
end
word P=0;
if N>=10 | S>0 then
P=str(N/10,S,@Buff);
end
char @D = "0123456789";
Buff [P]=D[N%10];
return P+1;
end
char @Str(word N; word S)
char @P="00000";
P[str(N,S,@P)]=#0;
return @P;
end
void Stop(char @EM)
putc(#13);
puts(@Name);
putc('(');
puts(@Str(Line,0));
putc(')');
if (strlen(@EM)>0) then
puts(": ");
puts(@EM);
end
close (hText);
asm mov AX,4C00H
asm int 21H
end
word Val(char @Buff)
char @D = "0123456789";
word P = 0;
word L = 0;
word H = 0;
while Buff[P]!=#0 do
word S=0;
while D[S]!=Buff[P] do
inc S;
if S>=10 then
Stop(@emNUMBER);
end
end
S=10*L+S;
L=S%256;
S=10*H+S/256;
H=S%256;
S=S/256;
if S>0 then
Stop(@emNUMBER);
end
inc P;
end
return 256*H+L;
end
char Read()
if pText>=nText then
nText=read(hText,@Text,tbSIZE);
if nText<1 then
Stop(@emEOF);
end
pText=0;
end
return Text[pText];
end
void Next()
inc pText;
end
char @Scan(char @Buff)
while Read()=#09 | Read()=#10 | Read()=#13 | Read()=#32 do
if Read()=#10 then
inc Line;
end
Next();
end
word P=0;
while isalpha(Read())=0 | isdigit(Read())=0 do
Buff[P]=Read();
inc P;
if P>=idSIZE then
Stop(@emSIZE);
end
Next();
end
if P=0 then
Buff[P]=Read();
inc P;
Next();
select
case Buff[0]='<':
if Read()='=' then
Next();
return @strcpy(@Buff,"<=");
end
case Buff[0]='!':
if Read()='=' then
Next();
return @strcpy(@Buff,"!=");
end
case Buff[0]='>':
if Read()='=' then
Next();
return @strcpy(@Buff,">=");
end
end
end
Buff[P]=#0;
return @Buff;
end
word Find(char @Name)
word P=0;
while P=ntSIZE then
Stop(@emNOMEMORY);
end
@Node [nNode].Left =NULL;
@Node [nNode].Right=NULL;
inc nNode;
return @Node[N];
end
NODE @Expr(word Prty; word @pType; char @Buff)
NODE @P1;
select
case strcmp(@Buff,"(")=0:
if Prty>=ptLVALUE then
Stop(@emLVALUE);
end
@P1=@Expr(0,@pType,@Scan(@Buff));
if strcmp(@Buff,")")!=0 then
Stop(@emBRACKET);
end
case isdigit(Buff)=0:
if Prty>=ptLVALUE then
Stop(@emLVALUE);
end
@P1=@Peek();
P1.ID =idNUMBER;
P1.Value=Val(@Buff);
pType =ttWORD;
default:
word N=Find(@Buff);
if N>=nData then
Stop(@emNAME);
end
@P1=@Peek();
P1.ID =idVARIABLE;
P1.Value =N;
if Data[N].Index>0 then
if strcmp(@Scan(@Buff),"[")!=0 then
Stop(@emBRACKET);
end
word pType2;
@P1.Left=@Expr(0,@pType2,@Scan(@Buff));
if strcmp(@Buff,"]")!=0 then
Stop(@emBRACKET);
end
if pType2!=ttWORD then
Stop(@emTYPE);
end
end
pType=ttWORD;
end
Scan(@Buff);
while TRUE do
word ID;
word P;
select
case strcmp(@Buff,"|")=0:
ID=idOR;
P =ptBOOL;
case strcmp(@Buff,"&")=0:
ID=idAND;
P =ptBOOL;
case strcmp(@Buff,"<")=0:
ID=idLT;
P =ptCOMP;
case strcmp(@Buff,"<=")=0:
ID=idLE;
P =ptCOMP;
case strcmp(@Buff,"=")=0:
ID=idEQ;
P =ptCOMP;
case strcmp(@Buff,"!=")=0:
ID=idNE;
P =ptCOMP;
case strcmp(@Buff,">=")=0:
ID=idGE;
P =ptCOMP;
case strcmp(@Buff,">")=0:
ID=idGT;
P =ptCOMP;
case strcmp(@Buff,"+")=0:
ID=idADD;
P =ptADD;
case strcmp(@Buff,"-")=0:
ID=idSUB;
P =ptADD;
case strcmp(@Buff,"*")=0:
ID=idMUL;
P =ptMUL;
case strcmp(@Buff,"/")=0:
ID=idDIV;
P =ptMUL;
default:
P =ptZERO;
end
if P<=Prty then
exit
end
word pType2;
NODE @P2=@Peek();
P2.ID = ID;
@P2.Left =@P1;
@P2.Right=@Expr(P,@pType2,@Scan(@Buff));
if pType2!=pType then
Stop(@emTYPE);
end
select
case ID=idOR | ID=idAND:
if pType!=ttBOOL then
Stop(@emUNDEFOPR);
end
case idLT<=ID & ID<=idGT:
if pType!=ttWORD then
Stop(@emUNDEFOPR);
end
pType=ttBOOL;
default:
if pType!=ttWORD then
Stop(@emUNDEFOPR);
end
end
@P1=@P2;
end
return @P1;
end
NODE @Ctrl(char @Buff)
NODE @P1=@Peek();
select
case strcmp(@Buff,"if")=0:
NODE @P2=@Peek();
P1 .ID =idIF;
@P1.Left =@P2;
word pType;
P2 .ID =idEMPTY;
@P2.Left =@Expr(ptZERO,@pType,@Scan(@Buff));
if strcmp(@Buff,"then")!=0 then
Stop(@emTHENEXP);
end
if pType!=ttBOOL then
Stop(@emTYPE);
end
NODE @@P3=@@P2.Right;
while strcmp(@Scan(@Buff),"end")!=0 do
@P3 =@Ctrl(@Buff);
@@P3=@@P3.Right;
end
case strcmp(@Buff,"while")=0:
NODE @P2=@Peek();
NODE @P3=@Peek();
P1 .ID =idWHILE;
@P1.Left=@P2;
P2. ID =idEMPTY;
@P2.Left=@P3;
P3.ID =idEMPTY;
word pType;
@P3.Right=@Expr(ptZERO,@pType,@Scan(@Buff));
if strcmp(@Buff,"do")!=0 then
Stop(@emDOEXP);
end
if pType!=ttBOOL then
Stop(@emTYPE);
end
NODE @@P4=@@P2.Right;
while strcmp(@Scan(@Buff),"end")!=0 do
@P4 =@Ctrl(@Buff);
@@P4=@@P4.Right;
end
case strcmp(@Buff,"write")=0:
P1.ID=idWRITE;
NODE @@P2=@@P1.Left;
while TRUE do
word pType;
NODE @P3=@Peek();
P3 .ID =idEMPTY;
@P3.Left=@Expr(ptZERO,@pType,@Scan(@Buff));
if pType!=ttWORD then
Stop(@emTYPE);
end
@P2 = @P3;
@@P2=@@P3.Right;
if strcmp(@Buff,";")=0 then
exit
end
if strcmp(@Buff,",")!=0 then
Stop(@emCOMMA);
end
end
case strcmp(@Buff,"blank")=0:
P1.ID=idBLANK;
default:
NODE @P2=@Peek();
P1. ID =idASSIGN;
@P1.Left=@P2;
P2.ID =idEMPTY;
word pType1, pType2;
@P2.Left=@Expr(ptLVALUE,@pType1,@Buff);
if pType1!=ttWORD then
Stop(@emTYPE);
end
if strcmp(@Buff,"=")!=0 then
Stop(@emASSIGN);
end
@P2.Right=@Expr(ptZERO, @pType2,@Scan(@Buff));
if strcmp(@Buff,";")!=0 then
Stop(@emSEMICOLON);
end
if pType2!=pType1 then
Stop(@emTYPE);
end
end
return @P1;
end
void Save(char Ch)
if pText>=tbSIZE then
write(hText,@Text,pText);
pText=0;
end
Text[pText]=Ch;
inc pText;
end
void Decl(char @Inst)
word I=0;
while Inst[I]!=#0 do
Save(Inst[I]);
inc I;
end
Save(#13);
Save(#10);
end
void Emit(word L; char @Inst)
if L!=0 then
Save('@');
char @P=@Str(L,5);
word I=0;
while P[I]!=#0 do
Save(P[I]);
inc I;
end
Save(':');
Save(' ');
else
word I=0;
while I<8 do
Save(' ');
inc I;
end
end
Decl(@Inst);
end
word Lbl (word ID)
select
case ID=idNUMBER:
return 0;
case ID=idVARIABLE:
return 0;
case ID=idADD:
return 0;
case ID=idSUB:
return 0;
case ID=idMUL:
return 0;
case ID=idDIV:
return 0;
case ID=idASSIGN:
return 0;
end
return 1;
end
void Enum(NODE @P; word @L)
if @P=NULL then
return
end
Enum(@P.Left, @L);
if Lbl(P.ID)!=0 then
P.Value=L;
inc L;
end
Enum(@P.Right,@L);
end
void Code(NODE @P; word F, T, M)
char Buff[128];
select
case P.ID=idNUMBER:
Emit(0,@strcat(@strcpy(@Buff,"mov AX,"),@Str(P.Value,0)));
case P.ID=idVARIABLE:
if @P.Left!=NULL then
Code(@P.Left,0,0,0);
Emit(0,"shl AX,1");
Emit(0,"mov DI,AX");
Emit(0,@strcat(@strcat(@strcpy(@Buff,"mov AX,DS:[DI+"),@Str(Data[P.Value].Ofs,0)),"]"));
else
Emit(0,@strcat(@strcat(@strcpy(@Buff,"mov AX,DS:["),@Str(Data[P.Value].Ofs,0)),"]"));
end
case P.ID=idOR:
if T=0 then
Code(@P.Left, 0,M,P.Value);
Emit(P.Value,"nop");
Code(@P.Right,F,0,M);
else
Code(@P.Left, 0,T,P.Value);
Emit(P.Value,"nop");
Code(@P.Right,0,T,M);
end
case P.ID=idAND:
if T=0 then
Code(@P.Left, F,0,P.Value);
Emit(P.Value,"nop");
Code(@P.Right,F,0,M);
else
Code(@P.Left, M,0,P.Value);
Emit(P.Value,"nop");
Code(@P.Right,0,T,M);
end
case idLT<=P.ID & P.ID<=idDIV:
Code(@P.Right,0,0,0);
Emit(0,"push AX");
Code(@P.Left, 0,0,0);
Emit(0,"pop BX");
select
case idLT<=P.ID & P.ID<=idGT:
Emit(0,"cmp AX, BX");
word ID=P.ID;
if T=0 then
select
case ID=idLT:
ID=idGE;
case ID=idLE:
ID=idGT;
case ID=idEQ:
ID=idNE;
case ID=idNE:
ID=idEQ;
case ID=idGE:
ID=idLT;
case ID=idGT:
ID=idLE;
end
T=F;
F=0;
end
select
case ID=idLT:
Emit(0,@strcat(@strcpy(@Buff,"jae @"),@Str(P.Value,5)));
case ID=idLE:
Emit(0,@strcat(@strcpy(@Buff,"ja @"),@Str(P.Value,5)));
case ID=idEQ:
Emit(0,@strcat(@strcpy(@Buff,"jne @"),@Str(P.Value,5)));
case ID=idNE:
Emit(0,@strcat(@strcpy(@Buff,"je @"),@Str(P.Value,5)));
case ID=idGE:
Emit(0,@strcat(@strcpy(@Buff,"jb @"),@Str(P.Value,5)));
case ID=idGT:
Emit(0,@strcat(@strcpy(@Buff,"jbe @"),@Str(P.Value,5)));
end
Emit(0,@strcat(@strcpy(@Buff,"jmp @"),@Str(T,5)));
Emit(P.Value,"nop");
case P.ID=idADD:
Emit(0,"add AX,BX");
case P.ID=idSUB:
Emit(0,"sub AX,BX");
case P.ID=idMUL:
Emit(0,"mul BX");
case P.ID=idDIV:
Emit(0,"xor DX,DX");
Emit(0,"div BX");
end
case P.ID=idIF:
F = P.Value;
@P=@P.Left;
Code(@P.Left, F,0,P.Value);
Emit( P.Value,"nop");
@P=@P.Right;
while @P!=NULL do
Code(@P,0,0,0);
@P=@P.Right;
end
Emit(F,"nop");
case P.ID=idWHILE:
F = P.Value;
@P=@P.Left;
T = P.Value;
word L=P.Left.Value;
Emit(L,"nop");
Code(@P.Left.Right,F,0,T);
Emit(T,"nop");
NODE @P=@P.Right;
while @P!=NULL do
Code(@P,0,0,0);
@P=@P.Right;
end
Emit(0,@strcat(@strcpy(@Buff,"jmp @"),@Str(L,5)));
Emit(F,"nop");
case P.ID=idWRITE:
@P=@P.Left;
while @P!=NULL do
Code(@P.Left,0,0,0);
Emit(0,"mov CX,8");
Emit(0,"call @WRITE");
@P=@P.Right;
end
Emit(0,"mov AH, 2");
Emit(0,"mov DL,13");
Emit(0,"int 21H");
Emit(0,"mov AH, 2");
Emit(0,"mov DL,10");
Emit(0,"int 21H");
case P.ID=idBLANK:
Emit(0,"mov AH, 2");
Emit(0,"mov DL,13");
Emit(0,"int 21H");
Emit(0,"mov AH, 2");
Emit(0,"mov DL,10");
Emit(0,"int 21H");
case P.ID=idASSIGN:
@P=@P.Left;
Code(@P.Right,0,0,0);
if @P.Left.Left!=NULL then
Emit(0,"push AX");
Code(@P.Left.Left,0,0,0);
Emit(0,"shl AX,1");
Emit(0,"mov DI,AX");
Emit(0,"pop AX");
Emit(0,@strcat(@strcat(@strcpy(@Buff,"mov DS:[DI+"),@Str(Data[P.Left.Value].Ofs,0)),"],AX"));
else
Emit(0,@strcat(@strcat(@strcpy(@Buff,"mov DS:["),@Str(Data[P.Left.Value].Ofs,0)),"],AX"));
end
end
end
begin
byte @Size=@Ptr(GetPSP(),128);
char @Parm=@Ptr(GetPSP(),129);
char name [128];
word I=0;
while I=dtSIZE then
Stop(@emNOMEMORY);
end
Data[nData].Index=0; strcpy(@Data[nData].Name,@Buff);
word N=1;
if strcmp(@Scan(@Buff),"[")=0 then
N=Val(@Scan(@Buff));
if N<1 then
Stop(@emEMPTY);
end
Data[nData].Index=N;
if strcmp(@Scan(@Buff),"]")!=0 then
Stop(@emBRACKET);
end
Scan(@Buff);
end
inc nData;
if strcmp(@Buff,";")=0 then
exit
end
if strcmp(@Buff,",")!=0 then
Stop(@emCOMMA);
end
end
case strcmp(@Buff,"begin")=0:
NODE @@P=@@Node;
while strcmp(@Scan(@Buff),"end")!=0 do
@P =@Ctrl(@Buff);
@@P=@@P.Right;
end
exit
default:
Stop(@emUNDEFINED);
end
end
close (hText);
word Ofs=0;
I=0;
while I0 then
Ofs=Ofs+2*Data[I].Index;
else
Ofs=Ofs+2;
end
inc I;
end
word L=1;
Enum (@Node,@L);
strcpy(@name[E],".asm");
hText=create(@name);
pText=0;
Emit(0,"mov AX,DS");
Emit(0,"add AX,4096");
Emit(0,"mov DS,AX");
while @Node!=NULL do
Code(@Node, 0,0,0);
@Node=@Node.Right;
end
Emit(0,"mov AX,4C00H");
Emit(0,"int 21H");
Decl("@WRITE: dec CX");
Decl(" xor DX,DX");
Decl(" mov BX,10");
Decl(" div BX");
Decl(" push DX");
Decl(" or AX,AX");
Decl(" jz @SPACE");
Decl(" call @WRITE");
Decl(" jmp @DIGIT");
Decl("@SPACE: mov AH, 2");
Decl(" mov DL,32");
Decl(" int 21H");
Decl(" dec CX");
Decl(" jnz @SPACE");
Decl("@DIGIT: mov AH, 2");
Decl(" pop DX");
Decl(" add DL,48");
Decl(" int 21H");
Decl(" retn");
if pText>0 then
write(hText,@Text,pText);
end
Stop ("");
end