#SEPARATOR = "," #MAX_ARGUMENTS = 256 #EXE_FILE_SIZE = 30720 Enumeration #OP_SET #OP_ADD #OP_SUB #OP_MUL #OP_DIV #OP_AND #OP_OR #OP_XOR #OP_MOD #OP_SHL #OP_SHR #OP_LABEL #OP_GOTO #OP_CreateThread #OP_PauseThread #OP_ResumeThread #OP_KillThread #OP_ThreadPriority #OP_OpenConsole #OP_Print #OP_Input #OP_INT #OP_FRAC #OP_SIN #OP_COS #OP_TAN #OP_ARCSIN #OP_ARCCOS #OP_ARCTAN #OP_ROUND #OP_RANDOM #OP_ELAPSED EndEnumeration Enumeration #TYPE_INT #TYPE_FLOAT #TYPE_STRING EndEnumeration Structure COMMAND_STRUCT Operation.i Count.i Arg$[#MAX_ARGUMENTS] EndStructure Global Dim Command.COMMAND_STRUCT(1) Global *LastCommand Global NewMap Var$() Global NewMap Label() Macro SetStr(Value) *Command\Arg$[1] = Value EndMacro Macro SetInt(Value) *Command\Arg$[1] = Str(Value) EndMacro Macro SetFloat(Value) *Command\Arg$[1] = StrD(Value) EndMacro Procedure$ Expr(String$) Length = Len(String$) ch$ = Left(String$, 1) If ch$ = "$" ProcedureReturn Right(String$, Length - 1) ElseIf (ch$ >= Chr(49) And ch$ <= Chr(57)) Or ch$ = "-" ProcedureReturn StrD(ValD(String$)) EndIf ProcedureReturn Var$(String$) EndProcedure Macro GetInt(Index) Val(Expr(*Command\Arg$[Index])) EndMacro Macro GetStr(Index) Expr(*Command\Arg$[Index]) EndMacro Macro GetFloat(Index) ValD(Expr(*Command\Arg$[Index])) EndMacro Macro Count() *Command\Count EndMacro Procedure Interpreter(*Command.COMMAND_STRUCT) Repeat If (*Command > *LastCommand) Break EndIf Select *Command\Operation Case #OP_LABEL *Command + SizeOf(COMMAND_STRUCT) Continue Case #OP_GOTO *Command = Label(GetStr(1)) Continue Case #OP_SET SetStr(GetStr(1)) Case #OP_ADD Float.d = GetFloat(1) For i = 2 To Count() Float + GetFloat(i) Next SetFloat(Float) Case #OP_SUB Float.d = GetFloat(1) For i = 2 To Count() Float - GetFloat(i) Next SetFloat(Float) Case #OP_MUL Float.d = GetFloat(1) For i = 2 To Count() Float * GetFloat(i) Next SetFloat(Float) Case #OP_DIV Float.d = GetFloat(1) For i = 2 To Count() Float / GetFloat(i) Next SetFloat(Float) Case #OP_LABEL *Command + SizeOf(COMMAND_STRUCT) Continue Case #OP_GOTO *Command = Label(GetStr(1)) Continue Case #OP_AND Integer.i = GetInt(1) For i = 2 To Count() Integer & GetInt(i) Next SetInt(Integer) Case #OP_OR Integer.i = GetInt(1) For i = 2 To Count() Integer | GetInt(i) Next SetInt(Integer) Case #OP_XOR Integer.i = GetInt(1) For i = 2 To Count() Integer ! GetInt(i) Next SetInt(Integer) Case #OP_MOD Integer.i = GetInt(1) For i = 2 To Count() Integer % GetInt(i) Next SetInt(Integer) Case #OP_SHL Integer.i = GetInt(1) For i = 2 To Count() Integer << GetInt(i) Next SetInt(Integer) Case #OP_SHR Integer.i = GetInt(1) For i = 2 To Count() Integer >> GetInt(i) Next SetInt(Integer) Case #OP_CreateThread SetInt(CreateThread(@Interpreter(), Label(GetStr(2)))) Case #OP_PauseThread PauseThread(GetInt(1)) Case #OP_ResumeThread ResumeThread(GetInt(1)) Case #OP_KillThread KillThread(GetInt(1)) Case #OP_ThreadPriority ThreadPriority(Getint(1), GetInt(2)) Case #OP_OpenConsole OpenConsole(GetStr(1)) Case #OP_Print Print(GetStr(1)) Case #OP_Input SetStr(Input()) EndSelect *Command + SizeOf(COMMAND_STRUCT) ForEver EndProcedure Macro GetCmdName() StringField(Line$, 1, #SEPARATOR) EndMacro Macro GetCmdVal(Index) StringField(Line$, Index+1, #SEPARATOR) EndMacro Procedure GenerateByteCode(String$) Lines = CountString(String$, #CRLF$)+1 ReDim Command(Lines) *LastCommand = @Command(Lines) For i = 1 To Lines Line$ = StringField(String$, i, #CRLF$) Count = CountString(Line$, #SEPARATOR) With Command(i) Select GetCmdName() Case "ПРИСВОИТЬ" \Operation = #OP_SET Case "СЛОЖИТЬ" \Operation = #OP_ADD Case "УМНОЖИТЬ" \Operation = #OP_MUL Case "ДЕЛИТЬ" \Operation = #OP_DIV Case "МЕТКА" \Operation = #OP_LABEL Label(GetCmdVal(1)) = (i - 1) * SizeOf(COMMAND_STRUCT) Case "ПЕРЕЙТИ" \Operation = #OP_GOTO Case "ОТКРЫТЬКОНСОЛЬ" \Operation = #OP_OpenConsole Case "ВЫВОД" \Operation = #OP_Print Case "ВВОД" \Operation = #OP_Input Case "СОЗДАТЬПОТОК" \Operation = #OP_CreateThread Case "ПОСТАВИТЬПОТОКНАПАУЗУ" \Operation = #OP_PauseThread Case "ПРОДОЛЖИТЬПОТОК" \Operation = #OP_ResumeThread Case "ЗАВЕРШИТЬПОТОК" \Operation = #OP_KillThread Case "ПРИОРИТЕТПОТОКА" \Operation = #OP_ThreadPriority Case "СИНУС" \Operation = #OP_SIN Case "КОСИНУС" \Operation = #OP_COS Case "ТАНГЕНС" \Operation = #OP_TAN Case "АРКСИНУС" \Operation = #OP_ARCSIN Case "АРККОСИНУС" \Operation = #OP_ARCCOS Case "АРКТАНГЕНС" \Operation = #OP_ARCTAN Case "ОКРГУЛИТЬ" \Operation = #OP_ROUND Case "ЦЕЛОЕ" \Operation = #OP_INT EndSelect For j = 1 To Count \Arg$[j] = GetCmdVal(j) Next EndWith Next EndProcedure Procedure$ ReadProgramFromExe() *Buffer = AllocateMemory(1024) If *Buffer GetModuleFileName_(0, *Buffer, 1024) ThisFileName$ = PeekS(*Buffer) FreeMemory(*Buffer) ThisFile = ReadFile(#PB_Any, ThisFileName$) If ThisFile ThisFileSize = Lof(ThisFile) *Buffer = AllocateMemory(ThisFileSize) If *Buffer ReadData (ThisFile, *Buffer, ThisFileSize) CloseFile (ThisFile) ProgramData$ = PeekS(*Buffer + #EXE_FILE_SIZE, ThisFileSize - #EXE_FILE_SIZE, #PB_Ascii) FreeMemory(*Buffer) ProcedureReturn ProgramData$ EndIf EndIf EndIf EndProcedure Procedure$ FormatPath(String$) l$ = Left(String$, 1) r$ = Right(String$, 1) If (l$ = "'" And r$ = "'") Or (l$ = Chr(34) And r$ = Chr(34)) ProcedureReturn Mid(String$, 2, Len(String$) - 2) EndIf ProcedureReturn String$ EndProcedure Select CountProgramParameters() Case 1 ProgramFileName$ = FormatPath(ProgramParameter(0)) Select FileSize(ProgramFileName$) Case 0 MessageRequester("", "Указан пустой файл программы.") End Case -1, -2 MessageRequester("", "Указанный файл программы не найден.") End Default ProgramFile = ReadFile(#PB_Any, ProgramFileName$) If Not ProgramFile MessageRequester("", "Невозможно прочитать файл программы.") End EndIf ProgramFileSize = Lof(ProgramFile) *Buffer = AllocateMemory(ProgramFileSize) If *Buffer ReadData (ProgramFile, *Buffer, ProgramFileSize) CloseFile (ProgramFile) ProgramData$ = PeekS(*Buffer, ProgramFileSize, #PB_Ascii) FreeMemory(*Buffer) GenerateByteCode(ProgramData$) Interpreter(@Command(1)) EndIf EndSelect Default EndSelect
На входе файл содержания:
ОТКРЫТЬКОНСОЛЬ,$Мояпрограмма
СОЗДАТЬПОТОК,А,ПЕЧАТЬА
СОЗДАТЬПОТОК,Б,ПЕЧАТЬБ
ВВОД,А
МЕТКА,А
ВЫВОД,0
ПЕРЕЙТИ,А
МЕТКА,Б
ВЫВОД,1
ПЕРЕЙТИ,Б