Простой интерпретатор

Приведенный ниже интерпретатор загружает в память весь текст подлежащей исполнению программы и выполняет ее.

Для тестирования можно использовать следующую нерекурсивную программу вычисления числа Фибоначчи с заданным номером (в тексте с номером 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 P<S do Buff[P]=' '; inc P; end else //P=Str(N/10,S-1,@Buff); if S>0 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 pText<nText do Ch=Text[pText]; if isalpha(Ch)!=0 & isdigit(Ch)!=0 then exit end Buff[P]=Ch; inc P; inc pText; end Buff[P]=#0; return end if isdigit(Ch)=0 then while pText<nText do Ch=Text[pText]; if isdigit(Ch)!=0 then exit end Buff[P]=Ch; inc P; inc pText; end Buff[P]=#0; return end if Ch='<' | Ch='>' | Ch='!' then if pText<nText then if Text[pText]='=' then Buff[P]='='; inc P; inc pText; end end end Buff[P]=#0; end int ID(char Name) /*asm mov AL,SS:[BP+4] asm xor AH,AH asm sub AX,65*/ return int(Name) - 65; end int Expr(int Prty) int R=ID(Buff[0]); int Op1; select case isdigit(Buff[0])=0: Op1=Val(); case Buff[1]!=#0: Stop(@emERROR); case Buff[0]='(': Scan(); Op1=Expr(0); if strcmp(")")!=0 then Stop(@emBRACKET); end case Buff[0]='-': if Prty>0 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=2: if Op1<=Op2 then R=1; end case S=3: if Op1=Op2 then R=1; end case S=4: if Op1!=Op2 then R=1; end case S=5: 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<nText do if Text[pText]='"' then exit end if P>=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<regs[R].nData) then Stop(@emRANGE); end Scan(); Data[regs[R].pData+N]=Expr(0); else Scan(); if strcmp("=")!=0 then Stop(@emASSIGN); end Scan(); regs[R].pData=Expr(0); end else /*while TRUE*/ do Scan(); if strcmp(";")=0 then exit end end end if strcmp(";")!=0 then Stop(@emEXPR); end end begin //byte @Size=@Ptr(GetPSP(),128); //char @Parm=@Ptr(GetPSP(),129); //char @Parm=@GetCommandLine(); word nArg; inline 0x8B, 0x45, 0x04; // mov EAX, [EBP+ 4] inline 0x89, 0x45, 0xFC; // mov [nArg], EAX char @Parm=""; if nArg>=2 then inline 0x8B, 0x45, 0x0C; // mov EAX, [EBP+12] inline 0x89, 0x45, 0xF8; // mov [Parm], EAX end int I=0; /*while /*I<Size*/ Parm[I]!='~0' & Parm[I]!=' ' do inc I; end while /*I<Size &*/ Parm[I] =' ' do inc I; end*/ int K=0; while /*I<Size*/ Parm[I]!='~0' & Parm[I]!=' ' do Name[K]=Parm[I]; inc K; inc I; end Name[K]=#00; if K<1 then return end word F=open(@Name); //if F=$FFFF then if F=0xFFFFFFFF then puts("Can't open file"); return end nText=read(F,@Text,nTEXT); nLine=1; pText=0; close(F); if !(nText<nTEXT) then puts("Source too long"); return end nData=0; I =0; while I<26 do regs[I].nData=-1; inc I; end Scan(); if strcmp("int")=0 then /*while TRUE*/ do Scan(); if !(('A'<=Buff[0] & Buff[0]<='Z') & Buff[1]=#0) then Stop(@emLETTER); end int R=ID(Buff[0]); /*if regs[R].nData>=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

Рейтинг@Mail.ru
Сайт создан в системе uCoz