10ステップで作るお手軽インタプリタ開発

 10ステップで作るお手軽インタプリタ開発

10ステップで、フィボナッチ数列が再帰により計算できる程度のインタプリタをつくります。レポジトリは以下です。https://github.com/ushitora-anqou/simplinterp

126139a2ee6a8e441e12208d0b6be790?s=128

Ushitora Anqou

October 22, 2018
Tweet

Transcript

  1. 5.

    5

  2. 6.

    6

  3. 7.

    7

  4. 10.
  5. 11.

    Step 0 C ݴޠͷจࣈྻॲཧ ↓ H e l l o

    \0 char *p = "Hello"; • C ݴޠʹ͓͍ͯจࣈྻ͸ʮจࣈ͕ϝϞ Ϧ্ʹฒͼɺऴ୺͕\0 ͷ΋ͷʯ • ϙΠϯλͰจࣈྻͷઌ಄ཁૉΛࢦ͢ɻ 10
  6. 12.

    Step 0 C ݴޠͷจࣈྻॲཧ ↓ H e l l o

    \0 char *p = "Hello"; p; // address *p; // ’H’ *(p + 1); // ’e’ p[1]; // ’e’ *p++; // ’H’ *p; // ’e’ 11
  7. 13.

    Step 1 ಈ͘ίʔυΛॻ͘ #include <stdio.h> int eval(char *p) { return

    0; } int main(int argc , char ** argv) { return eval(argv [1]); } eval() ͰϓϩάϥϜͷ࣮ߦΛߦ͏ɻ ./main "program" 12
  8. 14.

    Step 1 ಈ͘ίʔυΛॻ͘ ςετΛॻ͘ɻ #!/bin/sh # ʢதུʣ runtest "0" 0

    runtest ͰϓϩάϥϜͷਖ਼ৗ࣮ߦΛ͔֬ ΊΔɻ 13
  9. 16.

    Step 2 ࣗવ਺ΛಡΉ ੔਺ΛҰݸಡΈࠐΜͰɺͦΕΛฦ͢ɻ int eval(char *p) { int ival

    = 0; while (isdigit (*p)) { ival = ival * 10 + *p - ’0’; p++; } return ival; } ٙ໰఺͸ϗϫΠτϘʔυͰղઆɻ 15
  10. 17.

    Step 3 ଍͠ࢉΛ଍͢ ଍͠ࢉͬͯԿͩΖ͏ɻ runtest "1+42" 43 runtest "23+42" 65

    runtest "1+2+4" 7 runtest "1+2+4+10" 17 ͜ͷΑ͏ͳग़ྗΛಘΔʹ͸ʁ 16
  11. 20.

    Step 3 ଍͠ࢉΛ଍͢ ଍͠ࢉ := ੔਺ ( ‘+’ ੔਺ )*

    int ival = parse_integer (); while (*p++ == ’+’) ival += parse_integer (); return ival; ٙ໰఺͸ϗϫΠτϘʔυͰղઆɻ 19
  12. 22.

    Step 4 Ҿ͖ࢉΛ଍͢ ଍͠ࢉ := ੔਺ ( ( ‘+’ |

    ‘-’ ) ੔਺ )* e.g. 42, 1+3, 12-3, 4+2-5+4-1 ଍͠ࢉ :thinking face: 21
  13. 23.

    int ival = parse_integer (); while (*p != ’\0’) {

    switch (*p) { case ’+’: p++; ival += parse_integer (); break; case ’-’: p++; ival -= parse_integer (); break; default: goto end; } } end: return ival; 22
  14. 24.

    Step 5 ֻ͚ࢉɾׂΓࢉΛ଍͢ ಉ͡Α͏ʹ࣮૷͢Δʁ runtest "1*2+3" 5 runtest "13/3+4" 8

    runtest "1+2*3" 7 runtest "1*2+3*4" 14 runtest "5/2+99/3" 35 ͜ͷΑ͏ͳग़ྗΛಘΔʹ͸ʁ 23
  15. 25.

    Step 5 ֻ͚ࢉɾׂΓࢉΛ଍͢ ଍͠ࢉ:= ੔਺ ( ( ‘+’ | ‘-’

    | ‘*’ | ‘/’) ੔਺ )* 2*3+4 ͸Αͦ͞͏ɻ 24
  16. 26.

    Step 5 ֻ͚ࢉɾׂΓࢉΛ଍͢ ଍͠ࢉ:= ੔਺ ( ( ‘+’ | ‘-’

    | ‘*’ | ‘/’) ੔਺ )* 2*3+4 ͸Αͦ͞͏ɻ 4+2*3 ͸ʁ 24
  17. 27.

    Step 5 ֻ͚ࢉɾׂΓࢉΛ଍͢ ԋࢉࢠͷ༏ઌॱҐͱ͸ʁ 4 + (2 * 3) -

    (6 / 3) ଍͠ࢉͷཁૉͱֻ͚ͯ͠ࢉΛ࢖͑Δɻ ੔਺ͱֻ͚ࢉ͸ಉ͡ѻ͍ɻ 25
  18. 28.

    Step 5 ֻ͚ࢉɾׂΓࢉΛ଍͢ ֻ͚ࢉ:= ੔਺ ( ( ‘*’ | ‘/’

    ) ੔਺ )* ଍͠ࢉ:= ֻ͚ࢉ ( ( ‘+’ | ‘-’ ) ֻ͚ࢉ )* શͯͷϓϩάϥϜ͸ʮ଍͠ࢉʯ e.g. 42, 1+2-3, 2*3/2, 2*3+4*5-10/3 26
  19. 29.

    int parse_add () { int ival = parse_mul (); while

    (*p != ’\0’) { switch (*p) { case ’+’: p++; ival += parse_mul (); continue; case ’-’: p++; ival -= parse_mul (); continue; } break; } return ival; } 27
  20. 30.

    int parse_mul () { int ival = parse_integer (); while

    (*p != ’\0’) { switch (*p) { case ’*’: p++; ival *= parse_integer (); continue; case ’/’: p++; ival /= parse_integer (); continue; } break; } return ival; } 28
  21. 32.

    Step 6 ؔ਺ݺͼग़͠Λ࣮૷ F(2) / 2 + G(3+4*2) * H(0)

    - 5 • ؔ਺ͷ໭Γ஋͸੔਺ͱಉ͡ѻ͍ɻ • ؔ਺ͷҾ਺͸ʮ଍͠ࢉʯ 30
  22. 33.

    Step 6 ؔ਺ݺͼग़͠Λ࣮૷ ؔ਺ݺग़:= ‘P’ ‘(’ ଍͠ࢉ ‘)’ | ੔਺

    ֻ͚ࢉ:= ؔ਺ݺग़ ( ( ‘*’ | ‘/’ ) ؔ਺ݺग़ )* ଍͠ࢉ:= ֻ͚ࢉ ( ( ‘+’ | ‘-’ ) ֻ͚ࢉ )* 31
  23. 34.

    int parse_mul () { int ival = parse_funccall (); while

    (*p != ’\0’) { switch (*p) { case ’*’: p++; ival *= parse_funccall (); continue; case ’/’: p++; ival /= parse_funccall (); continue; } break; } return ival; } 32
  24. 35.

    int parse_funccall () { if (*p == ’P’) { p++;

    expect(’(’); int ival = parse_add (); expect(’)’); printf("%d\n", ival ); return 0; } return parse_integer (); } 33
  25. 37.

    Step 7 ࣜͷ۠੾ΓΛ௥Ճ ؔ਺ݺग़:= ‘P’ ‘(’ ࣜ ‘)’ | ੔਺

    ֻ͚ࢉ:= ؔ਺ݺग़ ( ( ‘*’ | ‘/’ ) ؔ਺ݺग़ )* ଍͠ࢉ:= ֻ͚ࢉ ( ( ‘+’ | ‘-’ ) ֻ͚ࢉ )* ࣜ:= ଍͠ࢉ ( ‘;’ ଍͠ࢉ )* શͯͷϓϩάϥϜ͸ʮࣜʯ 35
  26. 38.

    int eval() { int ival = parse_add (); while (*p

    == ’;’) { p++; ival = parse_add (); } return ival; } 36
  27. 39.

    Step 8 Ҿ਺ͳؔ͠਺ఆٛΛ௥Ճ Ҿ਺ͳ͠ͷؔ਺ఆ͕ٛͰ͖ΔΑ͏ʹ͢Δɻ runtest "F{1}F()" 1 runtest "F{5/2+99/3 -3*4}F()"

    23 runtest "F{5/2+99/3 -3*4;100 -24}F()"\ 76 ؔ਺໊͸େจࣈΞϧϑΝϕοτ 1 จࣈɻ ؔ਺ఆٛ͸ϓϩάϥϜͷઌ಄ͷΈͰՄೳɻ 37
  28. 41.

    Step 8 Ҿ਺ͳؔ͠਺ఆٛΛ௥Ճ F{5/2+99/3-3*4;100-24} ؔ਺ఆٛ := [ ‘A’-‘Z’ ] ‘{’

    ࣜ ‘}’ ؔ਺ݺग़ := ‘P’ ‘(’ ࣜ ‘)’ | [ ‘A’-‘Z’ ] ‘(’ ‘)’ | ੔਺ 39
  29. 42.

    int eval() { while (1) { if (’A’ <= *p

    && *p <= ’Z’ && *(p + 1) == ’{’) { parse_funcdef (); continue; } return parse_exprs (); } } 40
  30. 43.

    char *funcbuf [256]; void parse_funcdef () { int n =

    *p++; expect(’{’); funcbuf[n] = p; while (*p != ’\0’ && *p++ != ’}’) ; } 41
  31. 44.

    int parse_funccall () { // ... process of P()... //

    then other functions if (’A’ <= *p && *p <= ’Z’) { int name = *p; p++; expect(’(’); expect(’)’); char *old_p = p; p = funcbuf[name ]; int ival = parse_exprs (); p = old_p; return ival; } return parse_integer (); } 42
  32. 45.

    Step 9 Ҿ਺͋Γؔ਺ఆٛΛ௥Ճ Ҿ਺͋Γͷؔ਺ఆ͕ٛͰ͖ΔΑ͏ʹ͢Δɻ runtest "F{a}F(42)" 42 runtest "F{a+b;a*b}F(1 ,1+1)"

    2 Ҿ਺͸খจࣈΞϧϑΝϕοτ 1 จࣈɻ ݺͼग़͠ଆ͸ΧϯϚͰ۠੾ͬͯ౉͢ɻ 43
  33. 47.

    Step 9 Ҿ਺͋Γؔ਺ఆٛΛ௥Ճ F{a+b;a*b} ม਺ := [ ‘a’-‘z’ ] |

    ੔਺ ؔ਺ݺग़ := ‘P’ ‘(’ ࣜ ‘)’ | [ ‘A’-‘Z’ ] ‘(’ ‘)’ | ม਺ 45
  34. 48.

    int *varbuf; int parse_variable () { if (’a’ <= *p

    && *p <= ’z’) return varbuf [(int)*p++]; return parse_integer (); } 46
  35. 49.

    Step 9 Ҿ਺͋Γؔ਺ఆٛΛ௥Ճ parse funccall() ͷղઆ 1. ؔ਺໊ͱ (ΛಡΉɻ 2.

    ม਺ςʔϒϧΛ࡞ΔɻҾ਺ΛධՁͯ͠ tmpbuf ʹೖΕΔɻ 3. ) ΛಡΉɻ 4. p ͱ funcbuf[name] ΛೖΕସ͑Δɻ 5. tmpbuf ͱ varbuf ΛೖΕସ͑Δɻ 47
  36. 50.

    Step 9 Ҿ਺͋Γؔ਺ఆٛΛ௥Ճ parse funccall() ͷղઆ 6. parse exprs() ΛݺͿ͜ͱͰؔ਺ຊମΛಡ

    Ήɻ͜ͷ஋͕໭Γ஋ɻ 7. ্ͰೖΕସ͑ͨ p ͱ varbuf Λݩʹ໭͢ɻ 8. ໭Γ஋Λฦ͢ɻ 47
  37. 51.

    Step 10 ϑΟϘφον਺ྻΛग़ྗ͢Δ ඞཁͳݴޠػೳ͸શ࣮ͯ૷ɻ runtest "1*2+3" 5 runtest "13/3+4" 8

    runtest "P(1);10+2;3" 3 runtest "F{a+b;a*b}F(1 ,1+1)" 2 ͜ΕΒΛ༻͍ͯϑΟϘφον਺ྻΛग़ྗ͢ Δʹ͸ʁ 48
  38. 53.