Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

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

126139a2ee6a8e441e12208d0b6be790?s=128

Ushitora Anqou

October 22, 2018
Tweet

Transcript

  1. 10 εςοϓͰͭ͘Δ ͓खܰΠϯλϓϦλ։ൃ ࠡ ᲒᲶ @ushitora anqou 1

  2. ΍Δ͜ͱ • ؆୯ͳΠϯλϓϦλΛ C ݴޠͰॻ͘ɻ • ϑΟϘφον਺ྻΛܭࢉͰ͖Δɻ • Strongly inspired

    by https://youtu.be/JAtN0TGrNE4 2
  3. Θ͔ͬͯ΄͍͜͠ͱ • ݴޠॲཧܥ͸ݴ͏΄Ͳ೉͘͠ͳ͍ɻ • ཧ࿦͸൥ࡶ͕࣮ͩ૷͢Ε͹Θ͔Δɻ • ΈΜͳ΋ C ίϯύΠϥΛͭ͘Ζ͏ʂ 3

  4. ιʔε https://github.com/ ushitora-anqou/ simplinterp 4

  5. 5

  6. 6

  7. 7

  8. ΠϯλϓϦλͬͯͳΜͩΖ͏ ΠϯλϓϦλʢӳ: interpreterʣͱ ͸ɺϓϩάϥϛϯάݴޠͰॻ͔Ε ͨιʔείʔυͳ͍͠தؒදݱΛ ஞ࣍ղऍ͠ͳ͕Β࣮ߦʢӳޠ൛ʣ ͢ΔϓϩάϥϜͷ͜ͱɻ ʢWikipedia ΑΓʣ 8

  9. ΠϯλϓϦλͬͯͳΜͩΖ͏ ͭ͘Ε͹Θ͔Δ 9

  10. Step

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

    \0 char *p = "Hello"; • C ݴޠʹ͓͍ͯจࣈྻ͸ʮจࣈ͕ϝϞ Ϧ্ʹฒͼɺऴ୺͕\0 ͷ΋ͷʯ • ϙΠϯλͰจࣈྻͷઌ಄ཁૉΛࢦ͢ɻ 10
  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
  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
  14. Step 1 ಈ͘ίʔυΛॻ͘ ςετΛॻ͘ɻ #!/bin/sh # ʢதུʣ runtest "0" 0

    runtest ͰϓϩάϥϜͷਖ਼ৗ࣮ߦΛ͔֬ ΊΔɻ 13
  15. Step 2 ࣗવ਺ΛಡΉ ੔਺ΛҰݸಡΈࠐΜͰɺͦΕΛฦ͢ɻ runtest "0" 0 runtest "1" 1

    runtest "42" 42 ͜ͷΑ͏ͳग़ྗΛಘΔʹ͸ʁ 14
  16. Step 2 ࣗવ਺ΛಡΉ ੔਺ΛҰݸಡΈࠐΜͰɺͦΕΛฦ͢ɻ int eval(char *p) { int ival

    = 0; while (isdigit (*p)) { ival = ival * 10 + *p - ’0’; p++; } return ival; } ٙ໰఺͸ϗϫΠτϘʔυͰղઆɻ 15
  17. Step 3 ଍͠ࢉΛ଍͢ ଍͠ࢉͬͯԿͩΖ͏ɻ runtest "1+42" 43 runtest "23+42" 65

    runtest "1+2+4" 7 runtest "1+2+4+10" 17 ͜ͷΑ͏ͳग़ྗΛಘΔʹ͸ʁ 16
  18. Step 3 ଍͠ࢉΛ଍͢ ʮ଍͠ࢉʯͱ͸ 1. ॳΊʹ੔਺͕དྷΔɻ 2. ͦͷޙʹʮ+ ੔਺ʯ͕ 0

    ճҎ্܁Γ ฦ͢ɻ e.g. 42, 1+2, 1+2+3 17
  19. Step 3 ଍͠ࢉΛ଍͢ 1. ॳΊʹ੔਺͕དྷΔɻ 2. ͦͷޙʹʮ+ ੔਺ʯ͕ 0 ճҎ্܁Γ

    ฦ͢ɻ ଍͠ࢉ := ੔਺ ( ‘+’ ੔਺ )* 18
  20. Step 3 ଍͠ࢉΛ଍͢ ଍͠ࢉ := ੔਺ ( ‘+’ ੔਺ )*

    int ival = parse_integer (); while (*p++ == ’+’) ival += parse_integer (); return ival; ٙ໰఺͸ϗϫΠτϘʔυͰղઆɻ 19
  21. Step 4 Ҿ͖ࢉΛ଍͢ ಉ͡Α͏ʹ଍ͯ͠ΈΔɻ runtest "1+2 -3+5" 5 ͜ͷΑ͏ͳग़ྗΛಘΔʹ͸ʁ 20

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

    ‘-’ ) ੔਺ )* e.g. 42, 1+3, 12-3, 4+2-5+4-1 ଍͠ࢉ :thinking face: 21
  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
  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
  25. Step 5 ֻ͚ࢉɾׂΓࢉΛ଍͢ ଍͠ࢉ:= ੔਺ ( ( ‘+’ | ‘-’

    | ‘*’ | ‘/’) ੔਺ )* 2*3+4 ͸Αͦ͞͏ɻ 24
  26. Step 5 ֻ͚ࢉɾׂΓࢉΛ଍͢ ଍͠ࢉ:= ੔਺ ( ( ‘+’ | ‘-’

    | ‘*’ | ‘/’) ੔਺ )* 2*3+4 ͸Αͦ͞͏ɻ 4+2*3 ͸ʁ 24
  27. Step 5 ֻ͚ࢉɾׂΓࢉΛ଍͢ ԋࢉࢠͷ༏ઌॱҐͱ͸ʁ 4 + (2 * 3) -

    (6 / 3) ଍͠ࢉͷཁૉͱֻ͚ͯ͠ࢉΛ࢖͑Δɻ ੔਺ͱֻ͚ࢉ͸ಉ͡ѻ͍ɻ 25
  28. Step 5 ֻ͚ࢉɾׂΓࢉΛ଍͢ ֻ͚ࢉ:= ੔਺ ( ( ‘*’ | ‘/’

    ) ੔਺ )* ଍͠ࢉ:= ֻ͚ࢉ ( ( ‘+’ | ‘-’ ) ֻ͚ࢉ )* શͯͷϓϩάϥϜ͸ʮ଍͠ࢉʯ e.g. 42, 1+2-3, 2*3/2, 2*3+4*5-10/3 26
  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
  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
  31. Step 6 ؔ਺ݺͼग़͠Λ࣮૷ ੔਺ͷग़ྗΛߦ͏ؔ਺ P() Λͭ͘Δɻ ؔ਺ͷ໭Γ஋͸ 0 ͱ͓ͯ͘͠ɻ runtest

    "P(1)" 0 # 1 on screen 29
  32. Step 6 ؔ਺ݺͼग़͠Λ࣮૷ F(2) / 2 + G(3+4*2) * H(0)

    - 5 • ؔ਺ͷ໭Γ஋͸੔਺ͱಉ͡ѻ͍ɻ • ؔ਺ͷҾ਺͸ʮ଍͠ࢉʯ 30
  33. Step 6 ؔ਺ݺͼग़͠Λ࣮૷ ؔ਺ݺग़:= ‘P’ ‘(’ ଍͠ࢉ ‘)’ | ੔਺

    ֻ͚ࢉ:= ؔ਺ݺग़ ( ( ‘*’ | ‘/’ ) ؔ਺ݺग़ )* ଍͠ࢉ:= ֻ͚ࢉ ( ( ‘+’ | ‘-’ ) ֻ͚ࢉ )* 31
  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
  35. int parse_funccall () { if (*p == ’P’) { p++;

    expect(’(’); int ival = parse_add (); expect(’)’); printf("%d\n", ival ); return 0; } return parse_integer (); } 33
  36. Step 7 ࣜͷ۠੾ΓΛ௥Ճ ‘;’ ͰࣜΛ۠੾ΕΔΑ͏ʹ͢Δɻ runtest "P(1);10+2;3" 3 ࠷ऴతͳ஋͸Ұ൪࠷ޙͷࣜͷ஋ɻ 34

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

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

    == ’;’) { p++; ival = parse_add (); } return ival; } 36
  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
  40. Step 8 Ҿ਺ͳؔ͠਺ఆٛΛ௥Ճ F{5/2+99/3-3*4;100-24} • ؔ਺໊͕࢝ΊʹདྷΔɻ • {ͱ}Ͱؔ਺ຊମΛғΉɻ • ؔ਺ຊମ͸ࣜΛ;

    Ͱ۠੾ͬͨ΋ͷɻ • ؔ਺ͷ໭Γ஋͸ؔ਺ຊମΛධՁ͠ ͨ஋ɻ 38
  41. Step 8 Ҿ਺ͳؔ͠਺ఆٛΛ௥Ճ F{5/2+99/3-3*4;100-24} ؔ਺ఆٛ := [ ‘A’-‘Z’ ] ‘{’

    ࣜ ‘}’ ؔ਺ݺग़ := ‘P’ ‘(’ ࣜ ‘)’ | [ ‘A’-‘Z’ ] ‘(’ ‘)’ | ੔਺ 39
  42. int eval() { while (1) { if (’A’ <= *p

    && *p <= ’Z’ && *(p + 1) == ’{’) { parse_funcdef (); continue; } return parse_exprs (); } } 40
  43. char *funcbuf [256]; void parse_funcdef () { int n =

    *p++; expect(’{’); funcbuf[n] = p; while (*p != ’\0’ && *p++ != ’}’) ; } 41
  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
  45. Step 9 Ҿ਺͋Γؔ਺ఆٛΛ௥Ճ Ҿ਺͋Γͷؔ਺ఆ͕ٛͰ͖ΔΑ͏ʹ͢Δɻ runtest "F{a}F(42)" 42 runtest "F{a+b;a*b}F(1 ,1+1)"

    2 Ҿ਺͸খจࣈΞϧϑΝϕοτ 1 จࣈɻ ݺͼग़͠ଆ͸ΧϯϚͰ۠੾ͬͯ౉͢ɻ 43
  46. Step 9 Ҿ਺͋Γؔ਺ఆٛΛ௥Ճ F{a+b;a*b} • ੔਺ͱҾ਺Λಉ౳ʹѻ͏ɻ • ؔ਺ͷத਎ΛධՁ͢Δͱ͖ʹɺҾ਺Λ ରԠ͢Δ஋ʹ͢Γସ͑Δɻ ͺͦ͜ΜΘ͔ΒΜʂ͆ͷͰҾ਺Λม਺

    ʢvariableʣͱ͍͏໊લͰ࣮૷ͨ͠ɻ 44
  47. Step 9 Ҿ਺͋Γؔ਺ఆٛΛ௥Ճ F{a+b;a*b} ม਺ := [ ‘a’-‘z’ ] |

    ੔਺ ؔ਺ݺग़ := ‘P’ ‘(’ ࣜ ‘)’ | [ ‘A’-‘Z’ ] ‘(’ ‘)’ | ม਺ 45
  48. int *varbuf; int parse_variable () { if (’a’ <= *p

    && *p <= ’z’) return varbuf [(int)*p++]; return parse_integer (); } 46
  49. Step 9 Ҿ਺͋Γؔ਺ఆٛΛ௥Ճ parse funccall() ͷղઆ 1. ؔ਺໊ͱ (ΛಡΉɻ 2.

    ม਺ςʔϒϧΛ࡞ΔɻҾ਺ΛධՁͯ͠ tmpbuf ʹೖΕΔɻ 3. ) ΛಡΉɻ 4. p ͱ funcbuf[name] ΛೖΕସ͑Δɻ 5. tmpbuf ͱ varbuf ΛೖΕସ͑Δɻ 47
  50. Step 9 Ҿ਺͋Γؔ਺ఆٛΛ௥Ճ parse funccall() ͷղઆ 6. parse exprs() ΛݺͿ͜ͱͰؔ਺ຊମΛಡ

    Ήɻ͜ͷ஋͕໭Γ஋ɻ 7. ্ͰೖΕସ͑ͨ p ͱ varbuf Λݩʹ໭͢ɻ 8. ໭Γ஋Λฦ͢ɻ 47
  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
  52. Step 10 ϑΟϘφον਺ྻΛग़ྗ͢Δ F{P(a);F(b,a+b)}F(1,1) % ./main "F{P(a);F(b,a+b)}F(1,1)" | head -25

    2 ͷྦྷ৐ͱ͔΋ܭࢉͰ͖Δɻ 49
  53. ·ͱΊ 50

  54. ·ͱΊ ݴޠॲཧܥ͸ ΍Δ͚ͩ 50

  55. ͝ਗ਼ௌ ͋Γ͕ͱ͏͟͝ ͍·ͨ͠ 51