Robby - расширение языка Robot Warfare 1 (RW1)

Публичный форум для http://www.nedopc.org/nedopc

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Robby - расширение языка Robot Warfare 1 (RW1)

Post by Shaos »

Пришло время с нуля писать новую быструю виртуальную машину RW0 на голом C...

P.S. Это в том числе и для RW3D будет использовано

P.P.S. Использование слова "Robby" в качестве нового варианта названия языка RW1 началось с мая 2016,
соответственно теперь виртуальную машину можно обозвать RobbyVM


P.P.P.S. Исходники старых виртуальные машин RW0 можно посмотреть вот в этих репах:
https://gitlab.com/shaos/rw1o (версия байткода 1.99)
https://gitlab.com/shaos/rw2d (версия байткода 2.0)
И ещё был простой интерпретатор на PocketC
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Придётся поддержать в том числе и старую систему команд (см. про версию 1.99 тут):

Code: Select all

 Robot Warfare 1
 RW0 bytecode description
 Version 1.99

 Alexander A. Shabarshin (shaos@mail.ru)
 http://robots.ural.net

 November 1998 - January 2000

 Header:
 -------

0x0000: 0x00..0x02 // Version (0x00 for 1.*, 0x01 for 1.99)
0x0001: 2 bytes // CheckSum (simple adding of the bytes starting from 0x0005)
0x0003: 2 bytes // Offset to bytecode start point (in bytes)
0x0005: 1 byte  // Length of the robot name (strlen)
0x0006: N bytes // Robot name
0x????: 0x00    // Terminal character for robot name
0x????: 2 bytes // Number of variables (plus arrays length)
0x????: 2 bytes // Code length in bytes (beginning from start point)
0x????: 3 bytes // Robot color (R,G,B)
0x????: 4 bytes // Equipments on the FRONT,RIGHT,BACK,LEFT (0-empty,1-eye,2-gun)
0x????: 1 byte  // Image flag (0x00-image is absent, 0x20-image is present)
// if image present, then next 32 bytes describe the robot image (2pix/byte)
// after that follows bytecode (after start point)
0x????: N bytes // Author nickname
0x????: 0x00    // Terminal character for author nickname
0x????: ?? ...  // reserved for additional data
START:

-----------------------------------------------------------------
 B - byte (1 byte)
 W - word (2 bytes - low byte + high byte)
 M - variable or constant (3-5 bytes):
     0x00 W - signed integer (-32K..+32K)
     0x01 W - variable in W cell (array[constant] is compiled to it too)
     0x02 W1 W2 - array element (W1-begin of array, W2-variables with offset)
 Registers are variables (0x01 0x?? 0xFF) with the addresses:
 0xFF00 - X // register for relative X value
 0xFF01 - Y // register for relative Y value
 0xFF02 - D // register for distance value
 0xFF03 - N // register for object value
 0xFF04 - K // register for additional value
 0xFF05 - R // register for random value
 0xFF06 - T // register for timer value
 0xFF07 - E // register for our energy value
 0xFF08 - M // register for our missiles number
 0xFF09 - I // register for order number of robot
 0xFF0F - S // register for stack length

 labW - label with address W
-----------------------------------------------------------------

 DEF commands - array definition (minimal length is 5 bytes)
 ------------

 0x01 W1 W2 // DEF arr[len]  (W1-offset to array start, W2-len)
 0x02 W1 W2 W3 ... // DEF arr[len]={list}  (W3-number of words)

 IF commands - maximal length is 13 bytes
 -----------

 0x10 W M1 M2 // IF M1<M2 : labW
 0x11 W M1 M2 // IF M1>M2 : labW
 0x12 W M1 M2 // IF M1<=M2 : labW
 0x13 W M1 M2 // IF M1>=M2 : labW
 0x14 W M1 M2 // IF M1==M2 : labW
 0x15 W M1 M2 // IF M1!=M2 : labW
           // or IF M1<>M2 : labW

 Expressions - maximal length is 11-16 bytes
 -----------

 0x20 M1 M2 // M1=M2
 0x21 M1 M2 // M1=-M2
 0x22 M1 M2 M3 // M1=M2+M3
 0x23 M1 M2 M3 // M1=M2-M3
 0x24 M1 M2 M3 // M1=M2/M3
 0x25 M1 M2 M3 // M1=M2*M3
 0x26 M1 M2 M3 // M1=M2%M3
 0x27 M1 M2 M3 // M1=M2&M3 - binary AND
 0x28 M1 M2 M3 // M1=M2|M3 - binary OR
 0x29 M1 M2 M3 // M1=M2^M3 - binary XOR
 0x2A M1 M2 // M1=~M2 - binary NOT

 Simple commands - 1-5 bytes
 ---------------

 0x30 W // GOTO labW
 0x31 W // CALL labW
 0x33 // RET
 0x34 // STEP
 0x35 // LEFT
 0x36 // RIGHT
 0x37 string 0x00 // SAY "string"
 0x38 M // print M
 0x3A M // ACT M (FRONT=0,RIGHT=1,BACK=2,LEFT=3)
 0x3B   // SPY
 0x3C M // RADAR M
 0x3F 0x00 B // DUMP variables in the B columns  (3 bytes)

 0x51 W wildcard-string 0x00 // TEST "wildcard" : label

 0x60 M // SHOT var
 0x61 M1 M2 // SEND var1 var2 - send code var1 to robot var2
 0x62 M // RECV var - receive code and save it to var
 0x63   // POP

 0xFF // END - end of bytecode
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Предполагается, что код виртуальной машины будет собираться в большинстве существующих компиляторов C, как 32-битных:
- GCC 4
- DJGPP (GCC 2.81)
- Open Watcom C/C++ 1.9
- Borland C++Builder 5.5
- Visual C++ ?
- LCC 4.2 ?
- TCC 0.9.25 ?

так и 16-битных:
- Borland C++ 3.1
- Turbo C 2.01
- Pacific C 7.51
- SDCC 3.0.0 ?
- GCC for AVR ?
- GCC for HC11 ?
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Надо компилятор RW1C улучшать - добавить возможность использовать локальные переменные (через ключевое слово LOCAL, а не через задницу) и функции поддержать внутри выражений, причём байткод при этом не изменится - всё будет работать на старых виртуальных машинах, если сделать так, как я предположил в ноябре 2004:
Shaos wrote:Появится регистр H, означающий старшие 16 бит результата L (может оказаться полезным например при умножении).

Также появится возможность использовать функции - они будут преобразовываться в вызов подпрограмм препроцессором. Например:

res=2+fun1(2,3)/fun2(4)

преобразуется препроцессором в

A=2;B=3;CALL fun1;_1=L
A=4;CALL fun2;_2=L
res=2+_1/_2
Кстати регистр H был поддержан на уровне компилятора ещё в версии 2.1.3 (29 ноября 2005), а вот функций до сих пор нет :oops:
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Shaos wrote:Надо компилятор RW1C улучшать - добавить возможность использовать локальные переменные (через ключевое слово LOCAL, а не через задницу) и функции поддержать внутри выражений, причём байткод при этом не изменится - всё будет работать на старых виртуальных машинах...
инкремент-декремент через ++ и -- (оба префикс и постфикс) тоже можно на уровне препроцессора реализовать (без изменения байткода)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

По идее перейти с 16-битной арифметики на 32-битную в RW0-байткоде ничего не мешает т.к. мы просто все регистры и все ячейки памяти объявляем 32-битными и всё - разве что можно ещё инструкций добавить для непосредственного ввода в стек и копирования в переменные больших 32-битных чисел (а заодно 8-битных и 24-битных):

Code: Select all

 M - variable or constant (2-9 bytes):
     0x00 W - signed integer (-32768...+32767)
     0x01 W - variable in W cell (array[constant] is also compiled to this)
     0x02 W1 W2 - array element (W1-begin of array, W2-variables with offset) 
============== NEW if memory is still small (<64K)
     0x03 B - byte (0...255)
     0x04 BL BM BH - signed 24-bit integer (-8 millions ... +8 millions)
     0x05 WL WH - signed 32-bit integer (-2 billions ... +2 billions)
============== NEW if memory is bigger (>=64K)
     0x06 B - variable with tiny offset (<256)
     0x07 BL BM BH - variable with 3-byte offset (< 16 millions)
     0x08 WL WH - variable with long offset (< 4 billions)
     0x09 W0 W2 WL WH - long array with long offset
.....

 Expressions
 ----------- 
 
.....

     0xF5 W // PUSH W   . -> W 
     0xF6 // []         A,B -> A[B]
============== NEW to push signed 32-bit integer
     0xF7 W1 W2 // PUSH L  . -> L
Пару слов лучше наверное размещать по традиции как little-endian, т.е. младшие байты идут первыми...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Расширение RW1 (Robby)

Post by Shaos »

Вот наиболее полный список байткодов Robby VM версии 2.2:

Code: Select all

 Robot Warfare 1
 RW0 bytecode description
 Version 2.2

 Alexander A. Shabarshin (shaos@mail.ru)
 http://rwar.net

 November 1998 - December 2012

 Header:
 -------

0x0000: 0x00..0x02 // Version (0 for v1.*, 1 for v1.99, 2 for v2.*)
0x0001: 2 bytes // CheckSum (sum of bytes from 0x0005 to the end)
0x0003: 2 bytes // Offset to bytecode entry point (in bytes)
0x0005: 1 byte  // Length of the robot name (strlen)
0x0006: N bytes // Robot name
0x????: 0x00    // Terminal character for robot name
0x????: 2 bytes // Number of variables (plus arrays length)
0x????: 2 bytes // Code length in bytes (beginning from start point)
0x????: 3 bytes // Robot color (R,G,B)
0x????: 4 bytes // Equipments on the FRONT,RIGHT,BACK,LEFT (0-empty,1-eye,2-gun)
0x????: 1 byte  // Image flag (0x00-image is absent, 0x20-image is present)
// if image present, then next 32 bytes describe the robot image (2pix/byte)
0x????: N bytes // Author nickname
0x????: 0x00    // Terminal character for author nickname
0x????: ?? ...  // Reserved for additional data
// after that follows bytecode 
START: // Entry point

 Bytecode:
 -----------------------------------------------------------------
 B - byte (1 byte)
 W - word (2 bytes - low byte + high byte)
 M - variable or constant (3-5 bytes):
     0x00 W - signed integer (-32768...+32767)
     0x01 W - variable in W cell (array[constant] is also compiled to this)
     0x02 W1 W2 - array element (W1-begin of array, W2-variables with offset)
 Registers are variables (0x01 0x?? 0xFF) with the addresses:
 0xFF00 (-256) X // register for relative X value
 0xFF01 (-255) Y // register for relative Y value
 0xFF02 (-254) D // register for distance value
 0xFF03 (-253) N // register for object value
 0xFF04 (-252) K // register for additional value
 0xFF05 (-251) R // register for random value
 0xFF06 (-250) T // register for timer value
 0xFF07 (-249) E // register for our energy value
 0xFF08 (-248) M // register for our missiles number
 0xFF09 (-247) I // register for order number of robot
 0xFF0A (-246) A // A-register for read/write
 0xFF0B (-245) B // B-register for read/write
 0xFF0C (-244) C // C-register for read/write
 0xFF0D (-243) P // register for command pointer
 0xFF0E (-242) L // register for the last value
 0xFF0F (-241) S // register for stack length
 0xFF16 (-234) U // register for higher word of timer value
 0xFF1E (-226) H // register for higher word of the last value

 labW - label with address W
 *    - old commands - supported by interpreter only
 -    - free time commands during interpretation
-----------------------------------------------------------------

 0x01 W1 W2        // DEF arr[len]  (W1-offset to array start, W2-len)
 0x02 W1 W2 W3 ... // DEF arr[len]={list}  (W3-number of words)

*0x10 W M1 M2 // IF M1<M2 : labW
*0x11 W M1 M2 // IF M1>M2 : labW
*0x12 W M1 M2 // IF M1<=M2 : labW
*0x13 W M1 M2 // IF M1>=M2 : labW
*0x14 W M1 M2 // IF M1==M2 : labW
*0x15 W M1 M2 // IF M1!=M2 : labW

-0x20 M1 M2 // M1=M2
*0x21 M1 M2 // M1=-M2
*0x22 M1 M2 M3 // M1=M2+M3
*0x23 M1 M2 M3 // M1=M2-M3
*0x24 M1 M2 M3 // M1=M2/M3
*0x25 M1 M2 M3 // M1=M2*M3
*0x26 M1 M2 M3 // M1=M2%M3
*0x27 M1 M2 M3 // M1=M2&M3 - binary AND
*0x28 M1 M2 M3 // M1=M2|M3 - binary OR
*0x29 M1 M2 M3 // M1=M2^M3 - binary XOR
*0x2A M1 M2 // M1=~M2 - binary NOT

*0x30 W // GOTO labW
*0x31 W // CALL labW
-0x33 // RET
 0x34 // STEP
 0x35 // LEFT
 0x36 // RIGHT
 0x37 ... 0x00 // SAY "string and/or &var"
 0x38 M // PRINT var
 0x3A M // ACT var (FRONT=0,RIGHT=1,BACK=2,LEFT=3)
 0x3B   // SPY
 0x3C M // RADAR var
 0x3F 0x00 B // DUMP B (Dump variables in B columns)

 0x40 B ...  // var=expr (B bytes)
-0x41 M1 M2  // IFY var1 var2
-0x42 M1 M2  // IFN var1 var2
-0x43 M      // GOTO var
-0x44 M      // CALL var

*0x51 W ... 0x00 // TEST "wildcard" label
 0x52 ... 0x00   // TEST "wildcard" // result in L register

 0x60 M // SHOT avar // copy 16 registers values to [avar] 
 0x61 M1 M2 // SEND var1 var2 // send code var1 to robot var2
 0x62 M // RECV avar // receive code and save it to [avar]
-0x63   // POP // pop value from the stack and store it to register L
 0x64 M1 M2 // PIXEL varx vary // draw a pixel by foreground color
 0x65 M1 M2 // FILL vardx vardy // from last PIXEL with COLOR
 0x66 ... 00 // TEXT "string" // from last PIXEL with COLOR
 0x67 M // PLANE varn // set current plane for drawing (0 - default)
 0x68 M // COLOR varn // set current color
 0x69 M1 M2 // SELECT varx vary // select cell to draw
 0x6A M1 M2 // SET var_plane [var_side] // draw tile to selected sell (default var_side=0)
 0x6B M // GET [var_side] // get identifier of the drawn tile (default var_side=0)
 0x6C ... 00 // ASM "string" // send some string directly to the asm output (RW1P2)

 0x70 M1 M2 // COPYP avar1 avar2 // copy packet [avar2] to [avar1]
 0x71 M1 M2 // SENDP avar var // send packet [avar] to robot var
 0x72 M // RECVP avar // receive packet and save it to [avar]
 0x73   // PUSH // push value from register L to the stack
 0x74 M1 M2 // CLEAR varx vary // draw a pixel by background color
 0x7F M // COMMAND var // high-level command

 0xFF // END - end of bytecode


 Expressions
 -----------

 expr uses var,label,(,),?:,+,-,*,/,%,&,|,^,~,!,&&,||,=,==,>,<,>=,<=,!=,<<,>>

 0x80 // &&  A,B -> A&&B
 0x81 // ||  A,B -> A||B
 0x90 // ==  A,B -> A==B
 0x91 // !=  A,B -> A!=B
 0x92 // >   A,B -> A>B
 0x93 // <   A,B -> A<B
 0x94 // >=  A,B -> A>=B
 0x95 // <=  A,B -> A<=B
 0xA0 // +   A,B -> A+B
 0xA1 // -   A,B -> A-B
 0xB0 // *   A,B -> A*B
 0xB1 // /   A,B -> A/B
 0xB2 // %   A,B -> A%B
 0xC0 // &   A,B -> A&B
 0xC1 // |   A,B -> A|B
 0xC2 // ^   A,B -> A^B
 0xD0 // >>  A,B -> A>>B
 0xD1 // <<  A,B -> A<<B
 0xE0 // -   A -> -A (negative)
 0xE1 // ~   A -> ~A (bit inverse)
 0xE2 // !   A -> !A (logic NOT)
 0xF0 // ?:         A,B,C -> A?B:C
 0xF1 // DUP        A -> A,A
 0xF2 // ROL        A,B -> B,A
 0xF3 // LOAD       A -> mem[A]
 0xF4 // SAVE       A,B -> .  (mem[A]=B)
 0xF5 W // PUSH W   . -> W
 0xF6 // []         A,B -> A[B]


 Debug info
 ----------

 Debug info is added to RW0-file by option -d in RW1C v2.1 or above.
 After code compiler writes zero-terminated word "DEBUG" and list
 of source files in form zero-terminated names. Two zero bytes
 identify end of the list. Then we have list of variables:

 ? bytes - NAME,0
 2 bytes - size of variable in words
 2 bytes - index of variable

 Then we have a number of 5-bytes structures:

 1 byte - index of source file
 2 bytes - number of line in the source file
 2 bytes - address in code

 End of structures is #FF byte.
P.S. Байткод 0x39 затерялся где-то в анналах истории - не могу нигде найти его реализацию и даже описание...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re:

Post by Shaos »

Shaos wrote:Надо компилятор RW1C улучшать - добавить возможность использовать локальные переменные (через ключевое слово LOCAL, а не через задницу) и функции поддержать внутри выражений, причём байткод при этом не изменится - всё будет работать на старых виртуальных машинах...
А можно и без ключевого слова LOCAL обойтись - локальные переменные можно особым образом помечать, например если переменная начинается с подчеркивания, то компилятор с ней работает как с локальной переменной живущей только в пределах своего блока {} - для этого можно наделить команду DEF возможностью динамически аллоцировать массив в месте вызова (тогда надо будет еще завести команду UNDEF чтобы такой динамический массив освобождать) и компилятор будет вставлять DEF на соответствующее количество переменных в начале блока, где появляются локальные переменные.

Еще можно сделать переменные типа беззнаковый байт, добавляя к имени суффикс $ - внутри такие однобайтовые переменные будут представлены как половинки обычных переменных, соответственно надо будет добавить 2 постфиксных спецоператора, которые могут выделять младший байт переменной ' и старший байт переменной " - препроцессор будет их вставлять в выражения вместо вызова соответствующих байтовых переменных

Еще одна мысль - поддержать наряду с сишным for еще и более модный вариант for(var in 1..10), а также for(var in array) где array - объявленный ранее массив (и все это можно сделать на уровне препроцессора)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Robby - расширение языка RW1

Post by Shaos »

с суффиксом $ всё-таки логичнее объявлять строки т.к. сейчас
DEF ARR1[10]="abcd" // ARR1[0]=длина пакета ARR1[1]='a' ARR1[2]='b' и т.д.
DEF ARR2[10]='abcd' // ARR2[0]=длина пакета ARR2[1]='a'|('b'<<8| ARR2[2]='c'|('d'<<8)
то теперь вместо второго варианта можно будет просто писать
DEF ARR$="abcd" // размер массива будет вычисляться автоматически и $ будет означать что инициализирующая последовательность описывает байты, а не слова
в этом случае апострофы вновь будут только для обозначения символов использоваться
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Robby - расширение языка RW1

Post by Shaos »

В первую очередь надо поддержать вышепредложенный вариант DEF STRING$="aaa" (даже без квадратных скобок т.к. необходимый размер массива в словах будет вычисляться компилятором).
Во вторую очередь надо реализовать расширение for: for(A in 1..10) (как в аде или руби) и for(A in array) (как в джаваскрипте), причём на уровне препроцессора!
Также хочу количество регистров увеличить до 26, дабы охватить все буквы алфавита, а вот с локальнымм переменными надо подумать...
Я тут за главного - если что шлите мыло на me собака shaos точка net
Alekcandr
Doomed
Posts: 665
Joined: 01 Oct 2007 10:30
Location: Ukraine

Re: Robby - расширение языка RW1

Post by Alekcandr »

Вы придумали язык. А зачем? Столько уж кривых языков не придумали только. А Си, Паскаль, Бейсик и конечно Ява (новый язык) рулит.
Эмулятор OrionEXT:
http://www.orion-ext.narod.ru
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Robby - расширение языка RW1

Post by Shaos »

Alekcandr wrote:Вы придумали язык. А зачем? Столько уж кривых языков не придумали только. А Си, Паскаль, Бейсик и конечно Ява (новый язык) рулит.
О - дайте две явы для Intel 8080 пжалста :idea:

А вообще язык я придумал ещё в 1998 (т.е. он моложе этой вашей "новой" явы) и расширил в 2000 - с тех пор и тащу его везде ;)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Lavr
Supreme God
Posts: 16682
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Robby - расширение языка RW1

Post by Lavr »

Shaos wrote:...для Intel 8080 пжалста :idea:
А вообще язык я придумал ещё в 1998 (т.е. он моложе этой вашей "новой" явы)
и расширил в 2000 - с тех пор и тащу его везде ;)
А насколько эффективный код генерирует твой язык для Intel 8080 ?
iLavr
User avatar
Shaos
Admin
Posts: 24027
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Robby - расширение языка RW1

Post by Shaos »

Lavr wrote:
Shaos wrote:...для Intel 8080 пжалста :idea:
А вообще язык я придумал ещё в 1998 (т.е. он моложе этой вашей "новой" явы)
и расширил в 2000 - с тех пор и тащу его везде ;)
А насколько эффективный код генерирует твой язык для Intel 8080 ?
Ну по любому побыстрее бейсика будет ;)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Lavr
Supreme God
Posts: 16682
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Robby - расширение языка RW1

Post by Lavr »

Shaos wrote:
Lavr wrote:А насколько эффективный код генерирует твой язык для Intel 8080 ?
Ну по любому побыстрее бейсика будет ;)
А супротив С ?
iLavr