yylexの歩き方
RubyKaigiの「parse.yの歩き方」で「ennnnndっていうのをやりたかったけどできませんでした」って話をしたら、CRubyもJRubyも次のセッションが終わる前には実装終わってんの。一応オレ二晩くらいは考えてから諦めたんだけども・・・15分とかで・・・。ああ、これが「全力で潰す」って奴か(多分違う)。
もう変Ruby作成の道は諦めて死のうと思いつつ、最期に見るともなしにCRubyパッチを眺めていると、いやーこれいいすね。そうか、こうやればいいのか。いろいろと応用が効きそう。これを使うまでは死ねない。
中田さん版も遠藤さん版も大筋同じなので ennnd みたいなの作るにはこれでいいんだな、ふむ。
とりあえず中田さん版。
diff --git i/parse.y w/parse.y index aca2b6a..980cb13 100644 --- i/parse.y +++ w/parse.y @@ -238,6 +238,7 @@ struct parser_params { rb_encoding *enc; rb_encoding *utf8; + int end_count; int parser_yydebug; #ifndef RIPPER @@ -6620,6 +6621,19 @@ parser_prepare(struct parser_params *parser) (ambiguous_operator(op, syn), 0))) static int +super_end_p(const char *s, int len) +{ + int i; + + if (len <= 3) return 0; + if (s[0] != 'e') return 0; + if (s[--len] != 'd') return 0; + for (i = 1; i < len; ++i) + if (s[i] != 'n') return 0; + return i - 1; +} + +static int parser_yylex(struct parser_params *parser) { register int c; @@ -6632,6 +6646,11 @@ parser_yylex(struct parser_params *parser) int fallthru = FALSE; #endif + if (parser->end_count > 0) { + --parser->end_count; + return keyword_end; + } + if (lex_strterm) { int token; if (nd_type(lex_strterm) == NODE_HEREDOC) { @@ -7874,6 +7893,10 @@ parser_yylex(struct parser_params *parser) return kw->id[1]; } } + else if ((parser->end_count = super_end_p(tok(), toklen())) > 0) { + --parser->end_count; + return keyword_end; + } } if (IS_BEG() ||
- @@ -238,6 +238,7 @@ struct parser_params {
- parser_paramsにスキャン中の情報を保持するためのメンバ(end_count)を追加して
- @@ -7874,6 +7893,10 @@ parser_yylex(struct parser_params *parser)
- @@ -6632,6 +6646,11 @@ parser_yylex(struct parser_params *parser)
- 字句解析部の最初でparser_paramsをチェックして、情報がセットされていたら適当なキーワード(keyword_end)を返して残りの処理をスキップ
なるほどー。自分が考えた方針も基本コレだったんだけど、2番の処理がどこ弄ればいいんだかよく分かんなかったんだよなー。コードリーディング力が低くてすいません。
これホントいろいろと使い出がありそうなので次回はこのへん使ってなんか作ってみたいすね。中田さん、遠藤さん、Tom、ありがとうございました。