PSY написал(а):Программа простейшая - заменяет команды на опкод и выполняет действия в зависимости от команды. Разбор строки проще некуда. Память течёт при приведении типов и ассоциативном массиве. Ставишь переходы по меткам - а выполнение начинается откуда попало или пропускаются условия...
Так то простейшая. Но "чёрт ногу сломит", чего вы там накодировали (воспринимать, как шутку, в которой есть правда )
1. В первом вашем примере, в процедуре Interpreter, требуется указатель. Но в Label вы записываете смещение, относительно начального адреса массива а не указатель. Решение:
2. В поток на процедуру Interpreter у вас отправляется не указатель, и даже не смещение, а значение некой переменной, которая даже не записана. В итоге в потоке, Interpreter получает указатель 0. Решение:
3. В #OP_GOTO интерпретатор снова пытается получить указатель не там, где надо и снова в *Command оказывается 0. Решение:
4. Что значит ПЕРЕЙТИ,А? Если, это значит перейти на МЕТКА,А то, в приведённом вами коде - это вечный цикл..............
5. Непонятно, как устроена логика операндов ПЕЧАТЬА, ПЕЧАТЬБ, они теряются, так как в интерпретаторе, ничего не сделано для того, чтобы их обработать.
6. Вот это, я тоже не понял в Interpreter ( кажется это фундментальная штука и у меня сложилось впечатление, что это всё портировано с другого языка, но неправильно понята портируемая структура данных ):
В данном случае, изменяется операнд собранного для интерпретации массива, на номер потока. Для чего это? Лучше оставьлять собранный массив команд неизменным. Но, если вам нужны связи, то создавайте эти связи отдельно.
7. В вашем примере, не логичны макросы SetStr и GetStr.
SetStr - пишет в одну область, в массив команд; GetStr - читает, совсем из другой области, вообще из хэш карты переменных. Как так, почему!?
8. В общем вот пример, на сколько я понял эту логику:
только, я заменил ПЕРЕЙТИ,А на ПЕРЕЙТИ,Выход для выхода, а в конце добавил МЕТКА,Выход, добавил дополнительный ВВОД,Б для основного потока:
Файл данных:
Интерпретатор из первого поста. Изменённое, обозначено !!!:
Код:
;- Constants
#SEPARATOR = ","
#MAX_ARGUMENTS = 256
#EXE_FILE_SIZE = 30720
#MARKER = 194782711 ; маркер, по которому будет определено, что указатель является нужной нам структурой (может быть любым)
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
;- Struct and Vars
Structure COMMAND_STRUCT
Marker.i
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\Operation <> #OP_LABEL
Static numDebug = 0
Debug Str(numDebug) + ">" + *Command\Arg$[0]+","+*Command\Arg$[1]+","+*Command\Arg$[2] ; промотр этапов, для отладки
numDebug+1
EndIf
If (*Command > *LastCommand)
Break
EndIf
Select *Command\Operation
Case #OP_LABEL ; 11
*Command + SizeOf(COMMAND_STRUCT)
Continue
Case #OP_GOTO ; 12
; *Command = Label( GetStr(1) ) ; !!! тут надо получать указатель на метку
*Command = Label( *Command\Arg$[1] ) ; вот так
Continue
Case #OP_SET ; 0
SetStr(GetStr(1))
Case #OP_ADD ; 1
Float.d = GetFloat(1)
For i = 2 To Count()
Float + GetFloat(i)
Next
SetFloat(Float)
Case #OP_SUB ; 2
Float.d = GetFloat(1)
For i = 2 To Count()
Float - GetFloat(i)
Next
SetFloat(Float)
Case #OP_MUL ; 3
Float.d = GetFloat(1)
For i = 2 To Count()
Float * GetFloat(i)
Next
SetFloat(Float)
Case #OP_DIV ; 4
Float.d = GetFloat(1)
For i = 2 To Count()
Float / GetFloat(i)
Next
SetFloat(Float)
; Case #OP_LABEL ; 11 !!! - это не нужно, уже есть, в начале
; *Command + SizeOf(COMMAND_STRUCT)
; Continue
; Case #OP_GOTO ; 12 !!! - это не нужно, уже есть, в начале
; *Command = Label(GetStr(1))
; Continue
Case #OP_AND ; 5
Integer.i = GetInt(1)
For i = 2 To Count()
Integer & GetInt(i)
Next
SetInt(Integer)
Case #OP_OR ; 6
Integer.i = GetInt(1)
For i = 2 To Count()
Integer | GetInt(i)
Next
SetInt(Integer)
Case #OP_XOR ; 7
Integer.i = GetInt(1)
For i = 2 To Count()
Integer ! GetInt(i)
Next
SetInt(Integer)
Case #OP_MOD ; 8
Integer.i = GetInt(1)
For i = 2 To Count()
Integer % GetInt(i)
Next
SetInt(Integer)
Case #OP_SHL ; 9
Integer.i = GetInt(1)
For i = 2 To Count()
Integer << GetInt(i)
Next
SetInt(Integer)
Case #OP_SHR ; 10
Integer.i = GetInt(1)
For i = 2 To Count()
Integer >> GetInt(i)
Next
SetInt(Integer)
Case #OP_CreateThread ; 13
; !!! в поток, нужно отправлять указатель на структуру COMMAND_STRUCT
; SetInt( CreateThread(@Interpreter(), Label(GetStr(2) ) ) )
PrintN( "Начало потока" )
SetInt( CreateThread(@Interpreter(), Label(*Command\Arg$[1]) ) )
Case #OP_PauseThread ; 14
PauseThread(GetInt(1))
Case #OP_ResumeThread ; 15
ResumeThread(GetInt(1))
Case #OP_KillThread ; 16
KillThread(GetInt(1))
Case #OP_ThreadPriority ; 17
ThreadPriority(Getint(1), GetInt(2))
Case #OP_OpenConsole ; 18
OpenConsole(GetStr(1))
Case #OP_Print ; 19
; !!! не понял, для чего здесь GetStr, возможно не понял логику этой команды. Если тут нужно показывать данные из указанной переменной, то да, тогда правильно.
; непонятно только причём здесь ВЫВОД,0 и ВЫВОД,1 в коде файла.
; PrintN(GetStr(1))
PrintN( "ВЫВОД:"+*Command\Arg$[1])
Case #OP_Input ; 20
SetStr(Input())
EndSelect
*Command + SizeOf(COMMAND_STRUCT)
; Until здесь для более удобной отладки. Использование While усложнит отладку
Until *Command\Marker <> #MARKER ; если указатель не является нужной нам структурой, выходим из обработчика
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)
\Marker = #MARKER
Select GetCmdName() ; имя команды, первый элемент в строке
Case "ПРИСВОИТЬ"
\Operation = #OP_SET
\Arg$[0] = "ПРИСВОИТЬ" ; !!! - для удобной отладки
Case "СЛОЖИТЬ"
\Operation = #OP_ADD
\Arg$[0] = "СЛОЖИТЬ"
Case "УМНОЖИТЬ"
\Operation = #OP_MUL
\Arg$[0] = "УМНОЖИТЬ"
Case "ДЕЛИТЬ"
\Operation = #OP_DIV
\Arg$[0] = "ДЕЛИТЬ"
Case "МЕТКА"
\Operation = #OP_LABEL
\Arg$[0] = "МЕТКА"
;!!! Если в Interpreter нужен указатель, то и записывать в Label нужно указатель, а не смещение
; Label(GetCmdVal(1)) = (i - 1) * SizeOf(COMMAND_STRUCT)
Label(GetCmdVal(1)) = @Command() + i * SizeOf(COMMAND_STRUCT)
Case "ПЕРЕЙТИ"
\Operation = #OP_GOTO
\Arg$[0] = "ПЕРЕЙТИ"
Case "ОТКРЫТЬКОНСОЛЬ"
\Operation = #OP_OpenConsole
\Arg$[0] = "ОТКРЫТЬКОНСОЛЬ"
Case "ВЫВОД"
\Operation = #OP_Print
\Arg$[0] = "ВЫВОД"
Case "ВВОД"
\Operation = #OP_Input
\Arg$[0] = "ВВОД"
Case "СОЗДАТЬПОТОК"
\Operation = #OP_CreateThread
\Arg$[0] = "СОЗДАТЬПОТОК"
Case "ПОСТАВИТЬПОТОКНАПАУЗУ"
\Operation = #OP_PauseThread
\Arg$[0] = "ПОСТАВИТЬПОТОКНАПАУЗУ"
Case "ПРОДОЛЖИТЬПОТОК"
\Operation = #OP_ResumeThread
\Arg$[0] = "ПРОДОЛЖИТЬПОТОК"
Case "ЗАВЕРШИТЬПОТОК"
\Operation = #OP_KillThread
\Arg$[0] = "ЗАВЕРШИТЬПОТОК"
Case "ПРИОРИТЕТПОТОКА"
\Operation = #OP_ThreadPriority
\Arg$[0] = "ПРИОРИТЕТПОТОКА"
Case "СИНУС"
\Operation = #OP_SIN
\Arg$[0] = "СИНУС"
Case "КОСИНУС"
\Operation = #OP_COS
\Arg$[0] = "КОСИНУС"
Case "ТАНГЕНС"
\Operation = #OP_TAN
\Arg$[0] = "ТАНГЕНС"
Case "АРКСИНУС"
\Operation = #OP_ARCSIN
\Arg$[0] = "АРКСИНУС"
Case "АРККОСИНУС"
\Operation = #OP_ARCCOS
\Arg$[0] = "АРККОСИНУС"
Case "АРКТАНГЕНС"
\Operation = #OP_ARCTAN
\Arg$[0] = "АРКТАНГЕНС"
Case "ОКРГУЛИТЬ"
\Operation = #OP_ROUND
\Arg$[0] = "ОКРГУЛИТЬ"
Case "ЦЕЛОЕ"
\Operation = #OP_INT
\Arg$[0] = "ЦЕЛОЕ"
EndSelect
; пишем все элементы строки в массив
For j = 1 To Count
\Arg$[j] = GetCmdVal(j)
Next
EndWith
Next
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
;- LoadFile
; Select CountProgramParameters()
; Case 1
; ProgramFileName$ = FormatPath(ProgramParameter(0))
; файл D:\test1.txt, следующего содержания
; ОТКРЫТЬКОНСОЛЬ,$Мояпрограмма
; СОЗДАТЬПОТОК,А,ПЕЧАТЬА
; СОЗДАТЬПОТОК,Б,ПЕЧАТЬБ
; ВВОД,А
; ВВОД,Б
; ПЕРЕЙТИ,Выход
; МЕТКА,А
; ВЫВОД,0
; ПЕРЕЙТИ,Выход
; МЕТКА,Б
; ВЫВОД,1
; МЕТКА,Выход
Define ProgramFileName$ = "D:\test1.txt" ; !!! просто подгрузим файл в Ascii кодировке
Select FileSize(ProgramFileName$)
Case 0
MessageRequester("", "Указан пустой файл программы.")
End
Case -1, -2
MessageRequester("", "Указанный файл программы не найден.")
End
Default
Define ProgramFile = ReadFile(#PB_Any, ProgramFileName$, #PB_Ascii)
If Not ProgramFile
MessageRequester("", "Невозможно прочитать файл программы.")
End
EndIf
Define ProgramData$ = ""
While Not Eof(ProgramFile)
ProgramData$ = ReadString(ProgramFile, #PB_File_IgnoreEOL)
Wend
CloseFile(ProgramFile)
If ProgramData$
GenerateByteCode(ProgramData$)
Interpreter( @Command(1) )
EndIf
EndSelect
; Default
;
; EndSelect
Больше отладочной информации по потокам:
Код:;- Constants
#SEPARATOR = ","
#MAX_ARGUMENTS = 256
#EXE_FILE_SIZE = 30720
#MARKER = 194782711 ; маркер, по которому будет определено, что указатель является нужной нам структурой (может быть любым)
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
;- Struct and Vars
Structure COMMAND_STRUCT
Marker.i
Operation.i
Count.i
Arg$[#MAX_ARGUMENTS]
EndStructure
Structure INTERPRETER ; такая структура будет помогать в отладке. Будем видеть в каком потоке работает интерпретатор
*Command.COMMAND_STRUCT
NumThread.a
EndStructure
Global NewList thrInterpreter.INTERPRETER()
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( *Interpreter.INTERPRETER ) ; *Command.COMMAND_STRUCT )
Protected *Command.COMMAND_STRUCT = *Interpreter\Command
Repeat
If *Command\Operation <> #OP_LABEL
Static numDebug = 1
Protected NumThread = *Interpreter\NumThread
Debug Str(numDebug) + ") Поток" + Str(NumThread) + ": " + *Command\Arg$[0]+","+*Command\Arg$[1]+","+*Command\Arg$[2] ; промотр этапов, для отладки
numDebug+1
EndIf
If (*Command > *LastCommand)
Break
EndIf
Select *Command\Operation
Case #OP_LABEL ; 11
*Command + SizeOf(COMMAND_STRUCT)
Continue
Case #OP_GOTO ; 12
; *Command = Label( GetStr(1) ) ; !!! тут надо получать указатель на метку
*Command = Label( *Command\Arg$[1] ) ; вот так
Continue
Case #OP_SET ; 0
SetStr(GetStr(1))
Case #OP_ADD ; 1
Float.d = GetFloat(1)
For i = 2 To Count()
Float + GetFloat(i)
Next
SetFloat(Float)
Case #OP_SUB ; 2
Float.d = GetFloat(1)
For i = 2 To Count()
Float - GetFloat(i)
Next
SetFloat(Float)
Case #OP_MUL ; 3
Float.d = GetFloat(1)
For i = 2 To Count()
Float * GetFloat(i)
Next
SetFloat(Float)
Case #OP_DIV ; 4
Float.d = GetFloat(1)
For i = 2 To Count()
Float / GetFloat(i)
Next
SetFloat(Float)
; Case #OP_LABEL ; 11 !!! - это не нужно, уже есть, в начале
; *Command + SizeOf(COMMAND_STRUCT)
; Continue
; Case #OP_GOTO ; 12 !!! - это не нужно, уже есть, в начале
; *Command = Label(GetStr(1))
; Continue
Case #OP_AND ; 5
Integer.i = GetInt(1)
For i = 2 To Count()
Integer & GetInt(i)
Next
SetInt(Integer)
Case #OP_OR ; 6
Integer.i = GetInt(1)
For i = 2 To Count()
Integer | GetInt(i)
Next
SetInt(Integer)
Case #OP_XOR ; 7
Integer.i = GetInt(1)
For i = 2 To Count()
Integer ! GetInt(i)
Next
SetInt(Integer)
Case #OP_MOD ; 8
Integer.i = GetInt(1)
For i = 2 To Count()
Integer % GetInt(i)
Next
SetInt(Integer)
Case #OP_SHL ; 9
Integer.i = GetInt(1)
For i = 2 To Count()
Integer << GetInt(i)
Next
SetInt(Integer)
Case #OP_SHR ; 10
Integer.i = GetInt(1)
For i = 2 To Count()
Integer >> GetInt(i)
Next
SetInt(Integer)
;- #OP_CreateThread
Case #OP_CreateThread ; 13
; !!! в поток, нужно отправлять указатель на структуру COMMAND_STRUCT
; SetInt( CreateThread(@Interpreter(), Label(GetStr(2) ) ) )
; для отладки
AddElement( thrInterpreter() )
thrInterpreter()\Command = Label( *Command\Arg$[1] )
thrInterpreter()\NumThread = ListSize( thrInterpreter() )
; PrintN( "Начало потока " + Str( ListSize( thrInterpreter() ) ) )
;
SetInt( CreateThread(@Interpreter(), @thrInterpreter() ) )
Case #OP_PauseThread ; 14
PauseThread(GetInt(1))
Case #OP_ResumeThread ; 15
ResumeThread(GetInt(1))
Case #OP_KillThread ; 16
KillThread(GetInt(1))
Case #OP_ThreadPriority ; 17
ThreadPriority(Getint(1), GetInt(2))
Case #OP_OpenConsole ; 18
OpenConsole(GetStr(1))
Case #OP_Print ; 19
; !!! не понял, для чего здесь GetStr. Возможно тут нужно извлекать данные из переменной.
; PrintN(GetStr(1))
PrintN( "ВЫВОД:"+*Command\Arg$[1])
Case #OP_Input ; 20
SetStr(Input())
EndSelect
*Command + SizeOf(COMMAND_STRUCT)
; Until здесь для более удобной отладки. Использование While усложнит отладку
Until *Command\Marker <> #MARKER ; если указатель не является нужной нам структурой, выходим из обработчика
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)
\Marker = #MARKER
Select GetCmdName() ; имя команды, первый элемент в строке
Case "ПРИСВОИТЬ"
\Operation = #OP_SET
\Arg$[0] = "ПРИСВОИТЬ" ; !!! - для удобной отладки
Case "СЛОЖИТЬ"
\Operation = #OP_ADD
\Arg$[0] = "СЛОЖИТЬ"
Case "УМНОЖИТЬ"
\Operation = #OP_MUL
\Arg$[0] = "УМНОЖИТЬ"
Case "ДЕЛИТЬ"
\Operation = #OP_DIV
\Arg$[0] = "ДЕЛИТЬ"
Case "МЕТКА"
\Operation = #OP_LABEL
\Arg$[0] = "МЕТКА"
;!!! Если в Interpreter нужен указатель, то и записывать в Label нужно указатель, а не смещение
; Label(GetCmdVal(1)) = (i - 1) * SizeOf(COMMAND_STRUCT)
Label(GetCmdVal(1)) = @Command() + i * SizeOf(COMMAND_STRUCT)
Case "ПЕРЕЙТИ"
\Operation = #OP_GOTO
\Arg$[0] = "ПЕРЕЙТИ"
Case "ОТКРЫТЬКОНСОЛЬ"
\Operation = #OP_OpenConsole
\Arg$[0] = "ОТКРЫТЬКОНСОЛЬ"
Case "ВЫВОД"
\Operation = #OP_Print
\Arg$[0] = "ВЫВОД"
Case "ВВОД"
\Operation = #OP_Input
\Arg$[0] = "ВВОД"
Case "СОЗДАТЬПОТОК"
\Operation = #OP_CreateThread
\Arg$[0] = "СОЗДАТЬПОТОК"
Case "ПОСТАВИТЬПОТОКНАПАУЗУ"
\Operation = #OP_PauseThread
\Arg$[0] = "ПОСТАВИТЬПОТОКНАПАУЗУ"
Case "ПРОДОЛЖИТЬПОТОК"
\Operation = #OP_ResumeThread
\Arg$[0] = "ПРОДОЛЖИТЬПОТОК"
Case "ЗАВЕРШИТЬПОТОК"
\Operation = #OP_KillThread
\Arg$[0] = "ЗАВЕРШИТЬПОТОК"
Case "ПРИОРИТЕТПОТОКА"
\Operation = #OP_ThreadPriority
\Arg$[0] = "ПРИОРИТЕТПОТОКА"
Case "СИНУС"
\Operation = #OP_SIN
\Arg$[0] = "СИНУС"
Case "КОСИНУС"
\Operation = #OP_COS
\Arg$[0] = "КОСИНУС"
Case "ТАНГЕНС"
\Operation = #OP_TAN
\Arg$[0] = "ТАНГЕНС"
Case "АРКСИНУС"
\Operation = #OP_ARCSIN
\Arg$[0] = "АРКСИНУС"
Case "АРККОСИНУС"
\Operation = #OP_ARCCOS
\Arg$[0] = "АРККОСИНУС"
Case "АРКТАНГЕНС"
\Operation = #OP_ARCTAN
\Arg$[0] = "АРКТАНГЕНС"
Case "ОКРГУЛИТЬ"
\Operation = #OP_ROUND
\Arg$[0] = "ОКРГУЛИТЬ"
Case "ЦЕЛОЕ"
\Operation = #OP_INT
\Arg$[0] = "ЦЕЛОЕ"
EndSelect
; пишем все элементы строки в массив
For j = 1 To Count
\Arg$[j] = GetCmdVal(j)
Next
EndWith
Next
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
;- LoadFile
; Select CountProgramParameters()
; Case 1
; ProgramFileName$ = FormatPath(ProgramParameter(0))
; файл D:\test1.txt, следующего содержания
; ОТКРЫТЬКОНСОЛЬ,$Мояпрограмма
; СОЗДАТЬПОТОК,А,ПЕЧАТЬА
; СОЗДАТЬПОТОК,Б,ПЕЧАТЬБ
; ВВОД,А
; ВВОД,Б
; ПЕРЕЙТИ,Выход
; МЕТКА,А
; ВЫВОД,0
; ПЕРЕЙТИ,Выход
; МЕТКА,Б
; ВЫВОД,1
; МЕТКА,Выход
Define ProgramFileName$ = "D:\test1.txt" ; !!! просто подгрузим файл в Ascii кодировке
Select FileSize(ProgramFileName$)
Case 0
MessageRequester("", "Указан пустой файл программы.")
End
Case -1, -2
MessageRequester("", "Указанный файл программы не найден.")
End
Default
Define ProgramFile = ReadFile(#PB_Any, ProgramFileName$, #PB_Ascii)
If Not ProgramFile
MessageRequester("", "Невозможно прочитать файл программы.")
End
EndIf
Define ProgramData$ = ""
While Not Eof(ProgramFile)
ProgramData$ = ReadString(ProgramFile, #PB_File_IgnoreEOL)
Wend
CloseFile(ProgramFile)
If ProgramData$
GenerateByteCode(ProgramData$)
Define Interpreter.INTERPRETER
Interpreter\Command = @Command(1)
Debug "--- Программа:" + #CRLF$
Debug ProgramData$ + #CRLF$
Debug "--- Работа: " + #CRLF$
Interpreter( @Interpreter )
EndIf
EndSelect
; Default
;
; EndSelect
Отредактировано Webarion (07.09.2023 05:29:38)