目次

中間言語方式検討

 スクリプト言語でBASICインタプリタを作成すると
 スクリプト言語を動かす環境が必要になります。

 テキストのカタチで、プログラムを保存すると
 マイコンのメモリを食潰していくので中間言語
 を利用して、メモリ容量を有効利用すべきだと
 多くの開発者が考えたことでしょう。




 NECのPC8001、SHARPのMZ80B、FUJITSUのFM-8、FM-7
 で採用されたBASICは、すべて中間言語に変換して
 実行されていました。

 中間言語を積極的に採用した言語はJavaでしょう。
 バイトコードと呼ばれるプログラムを利用すると
 バイトコードで記述されていれば、バイトコードを
 実行する環境の用意するだけで、どのコンピュータ
 でも同じプログラムが動くことになります。

 開発したBASICインタプリタでも、テキストファイル
 を中間言語に変換し、プログラムを実行できるように
 したいと考えました。

 ゼロから中間言語を定義するのは面倒なので
 N88BASICで使われた中間言語を利用します。

 N88BASICの中間言語は、1バイトと2バイトに分類されます。

 1バイト中間言語

  80hからFFhの128バイトで構成しています。

  80            81 END
  82 FOR        83 NEXT
  84 DATA       85 INPUT
  86 DIM        87 READ
  88 LET        89 GO TO
  8A RUN        8B IF
  8C RESTORE    8D GOSUB
  8E RETURN     8F REM
  90 STOP       91 PRINT
  92 CLEAR      93 LIST
  94 NEW        95 ON
  96 WAIT       97 DEF
  98 POKE       99 CONT
  9A OUT        9B LPRINT
  9C LLIST      9D CONSOLE
  9E WIDTH      9F ELSE
  A0 TRON       A1 TROFF
  A2 SWAP       A3 ERASE
  A4 EDIT       A5 ERROR
  A6 RESUME     A7 DELETE
  A8 AUTO       A9 RENUM
  AA DEFSTR     AB DEFINT
  AC DEFSNG     AD DEFDBL
  AE LINE       AF WHILE
  B0 WEND       B1 CALL
  B2            B3
  B4            B5 WRITE
  B6 COMMON     B7 CHAIN
  B8 OPTION     B9 RANDOMIZE
  BA DSKO$      BB OPEN
  BC FIELD      BD GET
  BE PUT        BF SET
  C0 CLOSE      C1 LOAD
  C2 MERGE      C3 FILES
  C4 NAME       C5 KILL
  C6 LSET       C7 RSET
  C8 SAVE       C9 LFILES
  CA MON        CB COLOR
  CC CIRCLE     CD COPY
  CE CLS        CF PSET
  D0 PRESET     D1 PAINT
  D2 TERM       D3 SCREEN
  D4 BLOAD      D5 BSAVE
  D6 LOCATE     D7 BEEP
  D8 ROLL       D9 HELP
  DA            DB KANJI
  DC TO         DD THEN
  DE TAB(       DF STEP
  E0 USR        E1 FN
  E2 SPC(       E3 NOT
  E4 ERL        E5 ERR
  E6 STRING$    E7 USING
  E8 INSTR      E9 '
  EA VARPTR     EB ATTR$
  EC DSKI$      ED SRQ
  EE OFF        EF INKEY$
  F0 >          F1 =
  F2 <          F3 +
  F4 -          F5 *
  F6 /          F7 ^
  F8 AND        F9 OR
  FA XOR        FB EQV
  FC IMP        FD MOD
  FE \          FF 

 2バイト中間言語

  FF80hからFFFFhの128ワードで構成しています。

  FF 80          FF 81 LEFT$
  FF 82 RIGHT$   FF 83 MID$
  FF 84 SGN      FF 85 INT
  FF 86 ABS      FF 87 SQR
  FF 88 RND      FF 89 SIN
  FF 8A LOG      FF 8B EXP
  FF 8C COS      FF 8D TAN
  FF 8E ATN      FF 8F FRE
  FF 90 INP      FF 91 POS
  FF 92 LEN      FF 93 STR$
  FF 94 VAL      FF 95 ASC
  FF 96 CHR$     FF 97 PEEK
  FF 98 SPACE$   FF 99 OCT$
  FF 9A HEX$     FF 9B LPOS
  FF 9C CINT     FF 9D CSNG
  FF 9E CDBL     FF 9F FIX
  FF A0 CVI      FF A1 CVS
  FF A2 CVD      FF A3 EOF
  FF A4 LOC      FF A5 LOF
  FF A6 FPOS     FF A7 MKI$
  FF A8 MKS$     FF A9 MKD$
  FF AA          FF AB
  FF AC          FF AD
  FF AE          FF AF
  FF B0          FF B1
  FF B2          FF B3
  FF B4          FF B5
  FF B6          FF B7
  FF B8          FF B9
  FF BA          FF BB
  FF BC          FF BD
  FF BE          FF BF
  FF C0          FF C1
  FF C2          FF C3
  FF C4          FF C5
  FF C6          FF C7
  FF C8          FF C9
  FF CA          FF CB
  FF CC          FF CD
  FF CE          FF CF
  FF D0 DSKF     FF D1 VIEW
  FF D2 WINDOW   FF D3 POINT
  FF D4 CSRLIN   FF D5 MAP
  FF D6 SEARCH   FF D7 MOTOR
  FF D8 PEN      FF D9 DATE$
  FF DA COM      FF DB KEY
  FF DC TIME$    FF DD WBYTE
  FF DE RBYTE    FF DF POLL
  FF E0 ISET     FF E1 IEEE
  FF E2 IRESET   FF E3 STATUS
  FF E4 CMD      FF E5
  FF E6          FF E7
  FF E8          FF E9
  FF EA          FF EB
  FF EC          FF ED
  FF EE          FF EF
  FF F0          FF F1
  FF F2          FF F3
  FF F4          FF F5
  FF F6          FF F7
  FF F8          FF F9
  FF FA          FF FB
  FF FC          FF FD
  FF FE          FF FF

 今回作成したBASICインタプリタでは、命令数が少ないので
 すべて1バイトで表現することにします。

  80            81 END
  82 FOR        83 NEXT
  84            85 INPUT
  86            87
  88 LET        89 GOTO
  8A            8B IF
  8C            8D GOSUB
  8E RETURN     8F REM
  90            91 PRINT
  92            93
  94            95
  96            97
  98            99
  9A OUT        9B
  9C            9D
  9E            9F ELSE
  A0            A1
  A2            A3
  A4            A5
  A6            A7
  A8            A9
  AA            AB
  AC            AD
  AE            AF WHILE
  B0 WEND       B1
  B2 ENDIF      B3
  B4            B5
  B6            B7
  B8            B9
  BA            BB
  BC            BD
  BE            BF
  C0            C1
  C2            C3
  C4            C5
  C6            C7
  C8            C9
  CA            CB
  CC            CD
  CE            CF
  D0            D1
  D2            D3
  D4            D5
  D6            D7
  D8            D9
  DA            DB
  DC TO         DD THEN
  DE            DF STEP
  E0            E1
  E2            E3
  E4            E5
  E6            E7
  E8            E9 '
  EA            EB
  EC            ED
  EE            EF
  F0 >          F1 =
  F2 <          F3 +
  F4 -          F5 *
  F6 /          F7 ^
  F8 &          F9 |
  FA ?          FB ,
  FC            FD
  FE            FF


 1バイトでBASICのコードが表現できれば
 中間言語に変換してメモリに格納するのと
 中間言語のコードを実行するインタプリタ
 を作成すれば、原理上は、どんなマイコン
 でも同じプログラムが動くことになります。

 AWKのスクリプトで、BASICプログラムを中間コードに
 変換してみました。インデントした方が中間コード。

10 '
 10 E9 
12 LET <0>,100
 12 88 <0> 100
13 LET C,3
 13 88 43 33
14 LET <98>,89,90
 14 88 <98> 89 90
15 LET A,10
 15 88 41 10
17 LET B,20
 17 88 42 20
20 LET <3>,10,20,A%3,B/3,<99>
 20 88 <3> 10 20 A%3 B/3 <99>
30 Let A,A+10
 30 88 41 A+10
35 Let a,a*3
 35 88 41 A*3
40 print A
 40 91 41
42 ? A,B,C,<0>,<3>,<4>,<5>,<6>,<7>
 42 FA 41 42 43 <0> <3> <4> <5> <6> <7>
45 ? A,B+2
 45 FA 41 B+2
50 GOTO 30
 50 89 GOTO 30 
60 IF A = 0 THEN LET <10>,<10>+1 ELSE LET <10>,<10>-1 ENDIF
 60 8B  41 F1 0 0 DD  88 <10> <10>+1  
65 IF A > 0 THEN LET <11>,<11>+1 ENDIF
 65 8B  41 F0 0 0 DD  88 <11> <11>+1  
70 WHILE B > 10
 70 AF  42 F0 0 10 
72   ? A
 72 FA 41
74   ? B
 74 FA 42
75   LET B,B-1
 75 88 42 B-1
76   ? C
 76 FA 43
78 WEND
 78 B0  
80 FOR I = 0 TO 4
 80 82  49 F1 0 0 DC  4
82   ? A
 82 FA 41
84   ? I
 84 FA 49
86 NEXT
 86 83  
85 ? <10>,<11>
 85 FA <10> <11>  
90 END
 90 81  

 スクリプトは、以下。

function isalpha(x) {
  result = 0
  # 'A' -> 'Z'
  if ( "A" <= x && x <= "Z" ) { result = 1 }
  # 'a' -> 'z'
  if ( "a" <= x && x <= "z" ) { result = 1 }

  return result
}

function get_hex(x) {
  # convert capital letter
  xtmp = toupper(x)
  # default
  result = xtmp
  # reserved word
  if ( xtmp == "IF"    ) { result = "" }
  if ( xtmp == "THEN"  ) { result = "" }
  if ( xtmp == "ENDIF" ) { result = "" }
  if ( xtmp == "TO"    ) { result = "" }
  if ( xtmp == "END"   ) { result = "" }
  if ( xtmp == "FOR"   ) { result = "" }
  if ( xtmp == "NEXT"  ) { result = "" }
  if ( xtmp == "WHILE" ) { result = "" }
  if ( xtmp == "WEND"  ) { result = "" }
  # judge
  if ( length( xtmp ) == 1 ) {
    if ( xtmp ~ /0/ ) { result = "30" }
    if ( xtmp ~ /1/ ) { result = "31" }
    if ( xtmp ~ /2/ ) { result = "32" }
    if ( xtmp ~ /3/ ) { result = "33" }
    if ( xtmp ~ /4/ ) { result = "34" }
    if ( xtmp ~ /5/ ) { result = "35" }
    if ( xtmp ~ /6/ ) { result = "36" }
    if ( xtmp ~ /7/ ) { result = "37" }
    if ( xtmp ~ /8/ ) { result = "38" }
    if ( xtmp ~ /9/ ) { result = "39" }
    if ( xtmp == "A" ) { result = "41" }
    if ( xtmp == "B" ) { result = "42" }
    if ( xtmp == "C" ) { result = "43" }
    if ( xtmp == "D" ) { result = "44" }
    if ( xtmp == "E" ) { result = "45" }
    if ( xtmp == "F" ) { result = "46" }
    if ( xtmp == "G" ) { result = "47" }
    if ( xtmp == "H" ) { result = "48" }
    if ( xtmp == "I" ) { result = "49" }
    if ( xtmp == "J" ) { result = "4A" }
    if ( xtmp == "K" ) { result = "4B" }
    if ( xtmp == "L" ) { result = "4C" }
    if ( xtmp == "M" ) { result = "4D" }
    if ( xtmp == "N" ) { result = "4E" }
    if ( xtmp == "O" ) { result = "4F" }
    if ( xtmp == "P" ) { result = "50" }
    if ( xtmp == "Q" ) { result = "51" }
    if ( xtmp == "R" ) { result = "52" }
    if ( xtmp == "S" ) { result = "53" }
    if ( xtmp == "T" ) { result = "54" }
    if ( xtmp == "U" ) { result = "55" }
    if ( xtmp == "V" ) { result = "56" }
    if ( xtmp == "W" ) { result = "57" }
    if ( xtmp == "X" ) { result = "58" }
    if ( xtmp == "Y" ) { result = "59" }
    if ( xtmp == "Z" ) { result = "5A" }
  }

  return result
}

{
  printf("%s\n",$0)
  printf(" %s ",$1)
  for ( i = 2 ; i <= NF ; i++ ) {
    #
    tmp = toupper($i)
    # set flag
    flag = 0
    # REM
    if ( tmp == "REM" ) { printf("8F ") }
    #
    if ( tmp == "END" ) { printf("81 ") }
    # FOR
    if ( tmp == "FOR" ) {
      printf("82 ") 
      flag = 3
    }
    # NEXT
    if ( tmp == "NEXT" ) { printf("83 ") }
    # LET
    if ( tmp == "LET" ) {
      printf("88 ")
      flag = 1
    }
    # GOTO
    if ( tmp == "GOTO" ) { printf("89 ") }
    # IF
    if ( tmp == "IF" ) {
      printf("8B ")
    }
    # GOSUB
    if ( tmp == "GOSUB" ) { printf("8D ") }
    # RETURN
    if ( tmp == "RETURN" ) { printf("8E ") }
    # REM
    if ( tmp == "REM" ) { printf("8F ") }
    # PRINT
    if ( tmp == "PRINT" ) {
      printf("91 ")
      flag = 2
    }
    # OUT
    if ( tmp == "OUT" ) { printf("9A ") }
    # ELSE
    if ( tmp == "ELSE" ) { printf("9F ") }
    # WHILE
    if ( tmp == "WHILE" ) { printf("AF ") }
    # WEND
    if ( tmp == "WEND" ) { printf("B0 ") }
    # ENDIF
    if ( tmp == "ENDIF" ) { printf("B2 ") }
    # TO
    if ( tmp == "TO" ) { printf("DC ") }
    # THEN
    if ( tmp == "THEN" ) { printf("DD ") }
    # STEP
    if ( tmp == "STEP" ) { printf("DF ") }
    # '
    if ( tmp == "\'" ) { printf("E9 ") }
    # >
    if ( tmp == ">" ) { printf("F0 ") }
    # =
    if ( tmp == "=" ) { printf("F1 ") }
    # <
    if ( tmp == "<" ) { printf("F2 ") }
    # +
    if ( tmp == "\+" ) { printf("F3 ") }
    # -
    if ( tmp == "\-" ) { printf("F4 ") }
    # *
    if ( tmp == "\*" ) { printf("F5 ") }
    # /
    if ( tmp == "\/" ) { printf("F6 ") }
    # ^
    if ( tmp == "^" ) { printf("F7 ") }
    # &
    if ( tmp == "&" ) { printf("F8 ") }
    # |
    if ( tmp == "\|" ) { printf("F9 ") }
    # ?
    if ( tmp == "\?" ) {
      printf("FA ")
      flag = 2
    }
    # 
    if ( flag == 1 || flag == 2 ) {
      # get next field
      j = i+1
      # have commad
      xx = $j
      if ( index(xx,",") > 0 ) {
        n = split($j,a,",")
        for ( i = 1 ; i <= n+1 ; i++ ) {
          printf("%s ",get_hex(a[i]))
        }
      } else {
        ytmp = get_hex(xx)
        printf("%s",ytmp)
      }
      break
    }
    #
    if ( isalpha( tmp ) == 1 ) {
      printf("%s ",get_hex( tmp ))
    } else {
      if ( tmp >= 0 ) { printf("%d ",tmp) }
    }
  }
  printf("\n")
}


目次

inserted by FC2 system