ゲヌト通蚳

2幎生の埌に教育が終了し、語圙が制限され、スピヌチが䞍明瞭な堎合、単玔に愚かである堎合、これらのあいたいなラテン文字を知らないが、プログラマヌになりたい堎合は、牛語Yobaが圹立ちたす。 ペヌバは本物の男の子のための蚀語です



しかし、真剣に、ある日、仕事で誰かが冗談でgop蚀語を曞くこずを提案しお、だれでもプログラマヌのように感じるこずができるようにしたした。 「cho」ずいう単語ずそのすべおで構築を開始したす。 ここで、コンピュヌタサむ゚ンスの分野で私の人生の道のりの教育に出䌚っおいないので、コンパむラビルディング、正匏な文法、および2幎目たたは3幎目に普通の孊生が食べるその他の興味深いコヌスすべおを芋逃したこずに泚意しおください。 コンパむラの構築に関するWirthの本は、BNFなどのあらゆる皮類の巧劙な甚語の知識を远加したしたが、実際的な利点はありたせんでした-私は単䞀のコンパむラを曞いたこずがありたせん。 したがっお、このタスクは私にずっお非垞に興味深いものでした。

あなたが18歳以䞊の堎合、私たちの母囜語のわいせ぀な語圙を適切に認識しおおり、どこから始めたいかに興味があるなら、猫にようこそ。



文法を操䜜するためのすべおのツヌルの䞭で、私はほんの少しだけ蚀及したした。 たず第䞀に、これらはもちろんlex、flex、yacc、bison、antlrであり、䞻にC / C ++コンパむラヌに䜿甚されたす。 第二に、それはocamllexずocamlyaccです。これらは、ご想像のずおり、okamlaでコンパむラヌを開発するために蚭蚈されおいたす。 そしお第䞉に、それはfslexxずfsyaccです-F蚀語に぀いおのみ同じこずです。これはocamlから完党に少しコピヌされたすが、その埌かなり倚くのグッズで生い茂りたす。 F私は自分のシステムに欠垭しおいるずしお华䞋したした。 はい、時には幅広い遞択が悪いこずもありたす。これらすべおのレクサヌずパヌサヌで混乱するのを恐れおいたした。



ちなみに、これは私にずっおかなり奇劙で䞍快な発芋でした。蚀語の分析は、異なるツヌルで実行される2぀の別々の段階で構成されおいるこずがわかりたした。 しかし、悲しいかな。



蚀語の皮類


嘘を぀くこずはありたせん。すぐに蚀語のアヌキテクチャ党䜓を考えたわけではなく、埐々に機胜を埐々に仕䞊げおいきたした。 しかし、玠材のサむズを小さくするためにそしお、6぀の矎しい日曜日の朝の時間に私を連れお行った道に玠早く行くために、すべおが事前に蚈画されたふりをしたす。 私たちの蚀語の各呜什は、䟋えば、オブゞェクトです。 C ++では、特定の呜什基本クラスの子孫の1぀ずしお、耇雑な構造ずしお、たたは䞀般的にはナニオンずしお衚珟できたす。 幞いなこずに、okamlを䜿甚するず、できるだけ簡単にすべおを実行できたす。 最初のファむル、yobaType.mlは、考えられるすべおのタむプの指瀺を蚘述しおおり、可胜な限りシンプルに蚭蚈されおいたす。

type action =

DoNothing

| AddFunction of string * action list

| CallFunction of string

| Stats

| Create of string

| Conditional of int * string * action * action

| Decrement of int * string

| Increment of int * string;;






各蚀語構成䜓は、これらのタむプのいずれかにキャストされたす。 DoNothingは単なるNOPステヌトメントであり、たったく䜕もしたせん。 Createは倉数を䜜成したすこれらは垞に敎数です。DecrementずIncrementはそれぞれ、指定された倉数をある数だけ増枛したす。 さらに、䜜成されたすべおの倉数ず条件付きの統蚈情報を衚瀺する統蚈がありたす。if実装では、特定の倉数に必芁な倀たたは倧きな倀が含たれおいるかどうかを確認できたす。 最埌に、AddFunctionずCallFunctionを远加したした。これは、実際には非垞にプロシヌゞャである独自の関数を䜜成しお呌び出す機胜です。



蚀語の文法


次のステップは、文法、぀たりある皮の指瀺に倉わる蚀語の構成を蚘述するこずです。



コヌドを衚瀺する前に、私たちの蚀語がどのように機胜するかを説明したす。 統蚈のク゚リこれはサヌビスチヌムのようなものですず関数の䜜成を陀くすべおのデザむンは、キヌワヌドで始たり、キヌワヌドで終わりたす。 これにより、必芁に応じお安党に改行ずむンデントを配眮できたす。 これに加えおロシア語で䜜業しおいたす、倉数ず倀の䞡方を枡す必芁がある堎合のために、いく぀かの手順を具䜓的に䜜成したした。 なぜこれが必芁だったのかは埌でわかりたす。 そのため、yobaParser.mlyファむル

%{

open YobaType

%}



%token <string> ID

%token <int> INT



%token RULEZ

%token GIVE TAKE

%token WASSUP DAMN

%token CONTAINS THEN ELSE

%token FUCKOFF

%token STATS

%token MEMORIZE IS

%token CALL



%start main

%type <YobaType.action> main



%%



main:

expr { $1 }

expr:

fullcommand { $1 }

| MEMORIZE ID IS fullcommandlist DAMN { AddFunction($2, $4) }

fullcommandlist:

fullcommand { $1 :: [] }

| fullcommand fullcommandlist { $1 :: $2 }

fullcommand:

WASSUP command DAMN { $2 }

| STATS { Stats }

command:

FUCKOFF { DoNothing }

| GIVE ID INT { Increment($3, $2) }

| GIVE INT ID { Increment($2, $3) }

| TAKE ID INT { Decrement($3, $2) }

| TAKE INT ID { Decrement($2, $3) }

| RULEZ ID { Create($2) }

| CALL ID { CallFunction($2) }

| CONTAINS ID INT THEN command ELSE command { Conditional($3, $2, $5, $7) }

| CONTAINS INT ID THEN command ELSE command { Conditional($2, $3, $5, $7) }

%%






最初に行うこずは、芋出しを挿入するこずです。最初に説明したアクションタむプを含むYobaTypeモゞュヌルを開きたす。 蚀語倉数のキヌワヌドではない数字ず文字列の堎合、2぀の特別な型を宣蚀したす。これらは、それらが䜕を含むかを正確に瀺したす。 トヌクンディレクティブを䜿甚するキヌワヌドごずに、文法でこの単語を識別する独自のタむプも䜜成したす。 それらのすべおを少なくずも1行で瀺すこずができたす。そのようなレコヌドは、呜什のタむプに埓っおすべおをグルヌプ化したす。 䜜成したすべおのトヌクンは、文法パヌサヌが実行すべき内容を決定する正確な眮換タむプであるこずに泚意しおください。 それらはあなたが奜きなもの、それらが蚀語自䜓でどのように芋えるか、ず呌ぶこずができたす。これに぀いおは埌で説明したす。 文法の゚ントリポむントがメむンであり、アクションタむプのオブゞェクトは垞にそれを返す必芁があるこず、぀たり、むンタプリタぞの指瀺であるこずを瀺したす。 最埌に、2぀の%%蚘号の埌、文法自䜓に぀いお説明したす。



䞭かっこでは、文字列がこのオプションに䞀臎した堎合の凊理​​を瀺したす。$ Nは、構造のN番目のメンバヌを瀺したす。 たずえば、「CALL ID」IDは文字列です。忘れないでくださいを満たす堎合、CallFunction呜什を䜜成し、パラメヌタヌ$ 2IDのみ-呌び出される関数の名前ずしお枡したす。



レクサヌ-蚀語をキヌワヌドに倉える


同時に、最も単玔で最も退屈な郚分に到達したした。 蚀語の単語からトヌクンぞの倉換を蚘述するだけなので、簡単です。 面倒なのは、字句解析噚たたはオカムロフスキヌ字句解析噚のみがロシア語で動䜜するように十分に蚭蚈されおいないため、文字列ず同様にロシア語の文字でしか動䜜できないためです。 蚀語のキヌワヌドの倧文字ず小文字を区別しないようにしたかったので、これはhemoの束を远加したした-「䞎える」だけを曞くのではなく、文字ごずにスペルオプションをペむントする必芁がありたした。 䞀般的には、yobaLexer.mllファむルをご芧ください。

  1. {
  2. YobaParserを開く
  3. 䟋倖 eof
  4. }
  5. ルヌルトヌクン=解析
  6.  "and" | "And"   "d" | "D"   "and" | "And"   ' '  +
  7.  "n" | "H"   "a" | "A"   "x" | "X"   "y" | "Y"   "y" | "Y"  { FUCKOFF }
  8. |  "b" | "B"   "a" | "A"   "l" | "L"   "a" | "A" 
  9.  "n" | "H"   "c" | "C"   ' '  +
  10.  "n" | "H"   "a" | "A"   "x" | "X"  {統蚈}
  11. | [ ' ' ' \ t ' ' \ n ' ' \ r ' ] {トヌクンlexbuf }
  12. | [ ' 0 '-' 9 ' ] + { INT  int_of_string  Lexing。Lexeme lexbuf   }
  13. |  "d" | "D"   "a" | "A"   "y" | "Y"  {䞎える}
  14. |  "n" | "H"   "a" | "A"  {テむク}
  15. |  "h" | "h"   "o" | "o"  { WASSUP }
  16. |  "th" | "th"   "o" | "O"   "b" | "B"   "a" | "A"  {くそ}
  17. |  "l" | "l"   "y" | "y"   "b" | "b"   "l" | " l "   "y" | " y "  { RULEZ }
  18. |  "e" | "E"   "c" | "C"   "t" | "T"   "b" | "b"  {含む }
  19. |  "t" | "T"   "a" | "A"   "d" | "D"   "a" | "A"  { THEN }
  20. |  "and" | "AND"   "l" | "L"   "and" | "AND"  {その他 }
  21. |  "y" | "y"   "c" | "c"   "e" | "e"   "k" | "k"   "and" | "and"  { MEMORIZE }
  22. |  "e" | "E"   "t" | "T"   "o" | "O"  { IS }
  23. |  "x" | "X"   "y" | "Y"   "y" | "Y"   "n" | "H"   "and" | "AND"  { CALL }
  24. |
  25.  "a" | "b" | "c" | "g" | "d" | "e" | "e" | "w"
  26. | 「z」 | 「そしお」 | 「th」 | 「〜」 | 「l」 | 「m」 | 「n」 | 「お」
  27. | 「p」 | 「p」 | 「s」 | 「t」 | 「u」 | 「f」 | x | 「c」
  28. | 「h」 | 「w」 | 「u」 | 「b」 | 「s」 | 「b」 | 「e」 | 「u」 | "I"  + { ID  Lexing。lexeme lexbuf  }
  29. | eof { Eofを䞊げる }


わいせ぀な蚀語の語圙はすべおここで説明しおいるため、このコヌドは子䟛や粟神組織が脆匱な人には芋せおはならないこずに泚意しおください。 さらに、最初にパヌサヌのモゞュヌルを開きたす。このモゞュヌルでは、すべおのタむプSTATS、GIVE、TAKEなどが定矩されおおり、入力が終了したずきにスロヌされる䟋倖を䜜成したす。 11行目に泚意しおください。スペヌスやその他のゎミは無芖する必芁があるこずを瀺しおいたすが、スペヌスを含む呜什の埌には特に続きたす。 12行目ず25-28行目は倉数の数ず名前を凊理し、29行目はファむルの終わりを瀺す䟋倖をスロヌしたす。



通蚳


最埌の郚分-蚀語構成を凊理するむンタヌプリタヌ自䜓。 最初にコヌド、次に説明

  1. YobaTypeを開く
  2. let identifiers = Hashtbl 。 䜜成 10 ;;
  3. let funcs = Hashtbl 。 䜜成 10 ;;
  4. let print_stats   =
  5. let print_item id amount =
  6. Printf 。 printf ">> YoYou havesd" id amount ;
  7. print_newline   ;
  8. 暙準出力 を フラッシュ
  9. Hashtbl 。 iter print_item identifiers ;;
  10. arithm id op倀  =
  11. 詊しおみる
  12. Hashtbl 。 識別子id  op  Hashtbl 。識別子idの怜玢 倀を 眮き換えたす。
  13. Printf 。 printf ">>くそ質問\ n" ; フラッシュ 暙準出力
  14. Not_found- > Printfで。 printf ">> X @on、yousは嫌いです \ n" id ; 暙準出力を フラッシュしたす ;;
  15. let cond cond id id act1 act2   =
  16. 詊しおみる
  17. hashtblの堎合 。 識別子を芋぀ける id > = amount then process_action act1   else process_action act2  
  18. Not_foundで->
  19. Printf 。 printf ">>なに\ n" ;
  20. フラッシュ 暙準出力
  21. および process_action = function
  22. | Create  id  ->  function   -> Hashtbl。ID 0を 远加 
  23. | 枛少 amount、id  -> arithm id  -  amount
  24. | むンクリメント amount、id  -> arithm id  +  amount
  25. | 条件付き amount、id、act1、act2  -> cond amount id act1 act2
  26. | DoNothing ->  関数   ->   
  27. | 統蚈-> print_stats
  28. | AddFunction  id、funclist  ->  function   -> Hashtbl。funcs id funclistを远加 
  29. | CallFunction  id  -> callfun id
  30. および callfun id   =
  31. let f  YobaType 。 アクションリスト= Hashtbl funcs id を 芋぀ける
  32. 䞀芧 iter  関数 x- > process_action x    f
  33. ;;
  34. 本圓 ながら
  35. 詊しおみる
  36. let lexbuf = Lexing 。 from_channel stdin in
  37. process_action  YobaParser。main YobaLexer。token lexbuf   
  38. ず
  39. YobaLexer 。 Eof- >
  40. print_stats   ;
  41. 出口0
  42. | 解析䞭。 Parse_error- >
  43. Printf 。 printf ">>どちらでもない@理解できなかったb @\ n" ;
  44. フラッシュ 暙準出力
  45. | 倱敗 _  ->
  46. Printf 。 printf ">>どちらでもない@理解できなかったb @\ n" ;
  47. フラッシュ 暙準出力
  48. やった


たず、倉数甚ず関数甚の2぀のハッシュテヌブルを䜜成したす。 初期サむズの10は懐䞭電灯から取埗され、同じトレヌニング蚀語を䜿甚しおいたすが、䞀床に倚くの機胜が必芁なのはなぜですか。

次に、2぀の小さな関数を宣蚀したす。1぀は統蚈の出力甚、もう1぀は倉数のむンクリメント/デクリメント甚です。



次に、3぀の関数のグルヌプが䞀床に来たす。condは条件付きコンストラクト私たちのifを凊理し、callfunは関数の呌び出しを担圓し、process_actionは入力ずしお来た呜什を凊理したす。 3぀の機胜すべおが互いに䟝存しおいる理由を説明したす。



process_actionのすべおのオプションはアクションを実行せず、単に実行する関数を返すだけであるこずに泚意しおください。 最初はそうではありたせんでしたが、この小さな倉曎により、ナヌザヌ関数のサポヌトを蚀語に簡単か぀簡単に远加できたした。



最埌に、コヌドの最埌の郚分は、ルヌプ内で青に倉わる前に、パヌサヌの結果を読み取っお凊理したす。



これにMakefileを远加するず、再生できたす

all:

ocamlc -c yobaType.ml

ocamllex yobaLexer.mll

ocamlyacc yobaParser.mly

ocamlc -c yobaParser.mli

ocamlc -c yobaLexer.ml

ocamlc -c yobaParser.ml

ocamlc -c yoba.ml

ocamlc -o yoba yobaLexer.cmo yobaParser.cmo yoba.cmo



clean:

rm -f *.cmo *.cmi *.mli yoba yobaLexer.ml yobaParser.ml






蚀語チェック


さお、泚意、なぜ倀ず倉数の異なる順序をサポヌトしたのですか 事実は、蚀語が非垞に、぀たり自然で、通蚳が文字通りあなたに話しかけおいるずいうこずです。 したがっお、私自身は䜕を曞くべきかに぀いお垞に混乱しおいたす。

$ ./yoba







3

4

2



@#

>>

>>

>>



>> ! : 7

>> ! : -2

4 1 @#

>>



>> ! : 7

>> ! : -1

4 @# @#

>>

>>

>>



>> ! : 14

>> ! : -3






欠点の1぀は、関数を呌び出すずきに、操䜜の数によるむンクリメント/デクリメントの成功に関するコメントが出おくるこずです。



面癜かったず思いたす。 すべおのむンタヌプリタヌコヌドはここからダりンロヌドできたす2kb 。

より経隓豊富な人々がコヌドに぀いおのコメントを共有する堎合、私は感謝したす。



All Articles