Приведенный ниже интерпретатор загружает в память весь
текст подлежащей исполнению программы и выполняет ее.
Для тестирования можно использовать следующую нерекурсивную
программу вычисления числа Фибоначчи с заданным номером
(в тексте с номером 29). На компьютере с процессором
Intel Core i5-4690S/3200МГц она выполняется около 20 секунд!
Для сравнения, эта же скомпилированная программа
выполняется примерно за 30 миллисекунд, ее рекурсивный
эквивалент (также скомпилированный) - примерно за 5 миллисекунд.
Естественно, существует гораздо более быстрый и более простой
способ вычисления чисел Фибоначчи, программа предназначена
только для оценки скорости работы интерпретатора.
int S[100],
C[100],
P,
M,
N,
F;
begin
P = 0;
S[P] = 29;
C[P] = 0;
P = P + 1;
while P > 0 do
P = P - 1;
F = 0;
if C[P] = 0 then
if S[P] < 2 then
C[P] = 1;
P = P + 1;
F = 1;
end
if F = 0 then
N = S[P];
S[P] = N - 1;
C[P] = 0;
P = P + 1;
S[P] = N - 2;
C[P] = 0;
P = P + 1;
F = 1;
end
end
if F = 0 then
if P > 0 then
M = S[P];
P = P - 1;
if C[P] = 0 then
N = S[P];
S[P] = M;
C[P] = 1;
P = P + 1;
S[P] = N;
C[P] = 0;
P = P +1;
F = 1;
end
if F = 0 then
S[P] = S[P] + M;
P = P + 1;
end
end
end
end
write S[0];
blank
end
Цикл в этой программе делает то же самое, что и следующая
рекурсивная функция:
int Fib(int N) is
if N < 2 then
return N;
else
return Fib(N - 1) + Fib(N - 2);
end
end
Текст интерпретатора:
include "sys4lnx.inc"
/*int 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 jae @OK
asm mov AX,0FFFFH
asm @OK:
asm pop DS
end
word read(int 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
void close(int F)
asm mov AH,3EH
asm mov BX,SS:[BP+4]
asm int 21H
end
word GetPSP()
asm mov AH,62H
asm int 21H
asm mov AX,BX
end
void @Ptr(word Seg, Ofs)
void @P1=@Ofs;
void @@P2=@P1;
return @P2;
end*/
int isalpha(char Ch)
if 'A'<=Ch & Ch <='Z' then
return 0;
end
if 'a'<=Ch & Ch <='z' then
return 0;
end
return 1;
end
int isdigit(char Ch)
if '0'<=Ch & Ch <='9' then
return 0;
end
return 1;
end
char Buff [128];
int strcmp(char @St2)
word P = 0;
while Buff [P] = St2[P] do
if Buff [P] = '~0' then
return 0;
end
inc P;
end
return 1;
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*/
define @emEOF "End of file"
define @emLETTER "Letter expected"
define @emNUMBER "Digit expected"
define @emBRACKET "Bracket expected"
define @emEMPTY "Empty array"
define @emARRAY "Array too large"
define @emCOMMA "Comma expected"
define @emDUP "Duplicate name usage"
define @emBEGIN "begin expected"
define @emTHENEXP "then expected"
define @emDOEXP "do expected"
define @emUNDEF "Undefined variable"
define @emASSIGN "Assign expected"
define @emEXPR "Semicolon expected"
define @emRANGE "Index out of range"
define @emERROR "Error"
define nTEXT 16384
define nDATA 16384
char Name [128];
char Text [nTEXT];
int nText;
int nLine;
int pText;
int Data [nDATA];
int nData;
struct REGS
int pData;
int nData;
end
REGS regs[26];
int Str(word N; word S; char @Buff)
word P=0;
if N<10 then
while P0 then
dec S;
end
P=Str(N/10,S, @Buff);
end
char @D ="0123456789";
Buff [P]= D[N%10];
return P+1;
end
void Stop(char @Msg)
char Buff [128];
Buff[Str(nLine,0,@Buff)]=#0;
//putc(#13);
//putc(#10);
puts(@Name);
puts("(");
puts(@Buff);
puts("): ");
puts(@Msg);
//asm mov AX,4C00H
//asm int 21H
halt(1);
end
int Val()
char @D="0123456789";
int V=0;
int P=0;
while (Buff[P]!=#0) do
int S=0;
/*while TRUE*/ do
if D[S]=#0 then
Stop(@emNUMBER);
end
if (D[S]=Buff[P]) then
exit
end
inc S;
end
V =10*V+S;
inc P;
end
return V;
end
void Scan()
char Ch;
/*while TRUE*/ do
if pText>=nText then
Stop(@emEOF);
end
Ch=Text[pText];
if Ch=#10 then
inc nLine;
end
if Ch!=#09 & Ch!=#10 & Ch!=#13 & Ch!=#32 then
exit
end
inc pText;
/*int Flag;
asm mov DX,1
asm mov AL,SS:[BP-2]
asm cmp AL,9
asm je @SCN01
asm cmp AL,10
asm je @SCN01
asm cmp AL,13
asm je @SCN01
asm cmp AL,32
asm je @SCN01
asm mov DX,0
asm @SCN01:
asm mov SS:[BP-4],DX
if Ch=#10 then
inc nLine;
end
if Flag=0 then
exit
end
inc pText;*/
end
inc pText;
word P=0;
Buff [P]=Ch;
inc P;
if isalpha(Ch)=0 then
while pText0 then
Stop(@emERROR);
end
Scan();
Op1=-Expr(5);
case 0<=R & R<26:
if regs[R].nData<0 then
Stop(@emUNDEF);
end
if regs[R].nData>0 then
Scan();
if strcmp("[")!=0 then
Stop(@emBRACKET);
end
Scan();
int N=Expr(0);
Op1=Data[regs[R].pData+N];
if strcmp("]")!=0 then
Stop(@emBRACKET);
end
else
Op1=regs[R].pData;
end
default:
Stop(@emERROR);
end
if Prty>4 then
return Op1;
end
Scan();
/*while TRUE*/ do
word S=0;
word P=0;
select
case Buff[1]!=#0:
return Op1;
case Buff[0]='+':
S=1;
P=3;
case Buff[0]='-':
S=2;
P=3;
case Buff[0]='*':
S=3;
P=4;
case Buff[0]='/':
S=4;
P=4;
default:
return Op1;
end
if P<=Prty then
exit
end
Scan();
select
case S=1:
Op1=Op1+Expr(P);
case S=2:
Op1=Op1-Expr(P);
case S=3:
Op1=Op1*Expr(P);
case S=4:
Op1=Op1/Expr(P);
default:
Stop(@emERROR);
end
end
return Op1;
end
int Comp()
int Op1=Expr(0);
int S =0;
select
case Buff[1]=#0:
select
case Buff[0]='<':
S=1;
case Buff[0]='=':
S=3;
case Buff[0]='>':
S=6;
end
case Buff[1]='=':
select
case Buff[2]!=#0:
S=0;
case Buff[0]='<':
S=2;
case Buff[0]='!':
S=4;
case Buff[0]='>':
S=5;
end
end
Scan();
int Op2=Expr(0);
int R =0;
select
case S=1:
if Op1=Op2 then
R=1;
end
case S=6:
if Op1>Op2 then
R=1;
end
default:
Stop(@emERROR);
end
return R;
end
int Bool(int Prty)
int Op1;
select
case Buff[1]!=#0:
Op1=Comp();
case Buff[0]='(':
Scan();
Op1=Bool(0);
if strcmp(")")!=0 then
Stop(@emBRACKET);
end
Scan();
case Buff[0]='!':
Scan();
if Bool(3)=0 then
Op1=1;
else
Op1=0;
end
default:
Op1=Comp();
end
/*while TRUE*/ do
word S=0;
word P=0;
select
case Buff[1]!=#0:
return Op1;
case Buff[0]='|':
S=1;
P=1;
case Buff[0]='&':
S=2;
P=2;
default:
return Op1;
end
if P<=Prty then
exit
end
Scan();
select
case S=1:
if Bool(P)!=0 then
Op1=1;
end
case S=2:
if Bool(P) =0 then
Op1=0;
end
default:
Stop(@emERROR);
end
end
return Op1;
end
void Ctrl(int Lock)
if strcmp("if")=0 then
int Lock1=Lock;
if Lock1=0 then
Scan();
if Bool(0)=0 then
inc Lock1;
end
if strcmp("then")!=0 then
Stop(@emTHENEXP);
end
else
/*while TRUE*/ do
Scan();
if strcmp("then")=0 then
exit
end
end
end
/*while TRUE*/ do
Scan();
if strcmp("end")=0 then
exit
end
Ctrl(Lock1);
end
return
end
if strcmp("while")=0 then
int pText1=pText;
int nLine1=nLine;
/*while TRUE*/ do
int Lock1=Lock;
if Lock1=0 then
Scan();
if Bool(0)=0 then
inc Lock1;
end
if strcmp("do")!=0 then
Stop(@emDOEXP);
end
else
/*while TRUE*/ do
Scan();
if strcmp("do")=0 then
exit
end
end
end
/*while TRUE*/ do
Scan();
if strcmp("end")=0 then
exit
end
Ctrl(Lock1);
end
if Lock1!=0 then
exit
end
pText=pText1;
nLine=nLine1;
end
return
end
if strcmp("repeat")=0 then
int pText1=pText;
int nLine1=nLine;
/*while TRUE*/ do
int Lock1=Lock;
/*while TRUE*/ do
Scan();
if strcmp("until")=0 then
exit
end
Ctrl(Lock1);
end
if Lock1=0 then
Scan();
if Bool(0)!=0 then
inc Lock1;
end
if strcmp(";")!=0 then
Stop(@emEXPR);
end
else
/*while TRUE*/ do
Scan();
if strcmp(";")=0 then
exit
end
end
end
if Lock1!=0 then
exit
end
pText=pText1;
nLine=nLine1;
end
return
end
if strcmp("print")=0 | strcmp("write")=0 then
if Lock=0 then
/*while TRUE*/ do
char Temp [128];
Scan();
select
case Buff[0]='"' & Buff[1]=#0:
int P=0;
while pText=64 then
Stop(@emERROR);
end
Temp[P]=Text[pText];
inc P;
inc pText;
end
inc pText;
Temp[P]=#0;
Scan();
default:
int N=Expr(0);
int S=1;
if N<0 then
N=-N;
S= 0;
end
Temp[Str(N,5,@Temp)]=#0;
if S=0 then
while Temp[S+1]=' ' do
inc S;
end
Temp[S]='-';
end
end
puts(@Temp);
if strcmp(";")=0 then
exit
end
if strcmp(",")!=0 then
Stop(@emCOMMA);
end
end
//putc(#13);
//putc(#10);
//puts("~r~n");
else
/*while TRUE*/ do
Scan();
if strcmp(";")=0 then
exit
end
end
end
return
end
if strcmp("blank")=0 then
if Lock=0 then
puts("~r~n");
end
return
end
if Buff[1]!=#0 then
Stop(@emLETTER);
end
int R=ID(Buff[0]);
if !(0<=R & R<26) then
Stop(@emLETTER);
end
if regs[R].nData<0 then
Stop(@emUNDEF);
end
if Lock=0 then
if regs[R].nData>0 then
Scan();
if strcmp("[")!=0 then
Stop(@emBRACKET);
end
Scan();
int N=Expr(0);
if strcmp("]")!=0 then
Stop(@emBRACKET);
end
Scan();
if strcmp("=")!=0 then
Stop(@emASSIGN);
end
if !(0<=N & N=2 then
inline 0x8B, 0x45, 0x0C; // mov EAX, [EBP+12]
inline 0x89, 0x45, 0xF8; // mov [Parm], EAX
end
int I=0;
/*while /*I=0 then
Stop(@emDUP);
end*/
Scan();
if strcmp("[")=0 then
Scan();
int N=Val();
if N=0 then
Stop(@emEMPTY);
end
Scan();
if strcmp("]")!=0 then
Stop(@emBRACKET);
end
regs[R].pData=nData; nData=nData+N;
regs[R].nData=N;
if nData>=nDATA then
Stop(@emARRAY);
end
Scan();
else
regs[R].nData=0;
end
if strcmp(";")=0 then
exit
end
if strcmp(",")!=0 then
Stop(@emCOMMA);
end
end
Scan();
end
if strcmp("begin")!=0 then
Stop(@emBEGIN);
end
/*while TRUE*/ do
Scan();
if strcmp("end")=0 then
exit
end
Ctrl(0);
end
end