さて、私は最初のパーサーを OCaml で書いていますが、すぐにどうにかして無限ループを持つパーサーを作成することができました。
特に注目すべきは、Scheme 仕様の規則に従って識別子を lex しようとしていることです (明らかに、自分が何をしているのかわかりません)。また、識別子の後に区切り文字が続くことを要求する言語がいくつかあります。現在の私のアプローチは、メインのレクサーによって消費されるべきではない文字delimited_identifier
の1つを含む正規表現を持つことです...そして、それが一致すると、その語彙素の読み取りは(まあ、私のラッパー)によって元に戻されます、実際の識別子のみを食べるサブレクサーに渡される前に、うまくいけばデリミタをバッファーに残して、親レクサーによって別の語彙素として食べられるようにします。delimiter
Sedlexing.rollback
私はMenhirとSedlexを使用しており、主に@smolkajのocaml-parsing
example-repo とRWO の解析の章の例を合成しています。これが私の現在のパーサーとレクサーの最も簡単な削減です:
%token LPAR RPAR LVEC APOS TICK COMMA COMMA_AT DQUO SEMI EOF
%token <string> IDENTIFIER
(* %token <bool> BOOL *)
(* %token <int> NUM10 *)
(* %token <string> STREL *)
%start <Parser.AST.t> program
%%
program:
| p = list(expression); EOF { p }
;
expression:
| i = IDENTIFIER { Parser.AST.Atom i }
%%
…そして…</p>
(** Regular expressions *)
let newline = [%sedlex.regexp? '\r' | '\n' | "\r\n" ]
let whitespace = [%sedlex.regexp? ' ' | newline ]
let delimiter = [%sedlex.regexp? eof | whitespace | '(' | ')' | '"' | ';' ]
let digit = [%sedlex.regexp? '0'..'9']
let letter = [%sedlex.regexp? 'A'..'Z' | 'a'..'z']
let special_initial = [%sedlex.regexp?
'!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' ]
let initial = [%sedlex.regexp? letter | special_initial ]
let special_subsequent = [%sedlex.regexp? '+' | '-' | '.' | '@' ]
let subsequent = [%sedlex.regexp? initial | digit | special_subsequent ]
let peculiar_identifier = [%sedlex.regexp? '+' | '-' | "..." ]
let identifier = [%sedlex.regexp? initial, Star subsequent | peculiar_identifier ]
let delimited_identifier = [%sedlex.regexp? identifier, delimiter ]
(** Swallow whitespace and comments. *)
let rec swallow_atmosphere buf =
match%sedlex buf with
| Plus whitespace -> swallow_atmosphere buf
| ";" -> swallow_comment buf
| _ -> ()
and swallow_comment buf =
match%sedlex buf with
| newline -> swallow_atmosphere buf
| any -> swallow_comment buf
| _ -> assert false
(** Return the next token. *)
let rec token buf =
swallow_atmosphere buf;
match%sedlex buf with
| eof -> EOF
| delimited_identifier ->
Sedlexing.rollback buf;
identifier buf
| '(' -> LPAR
| ')' -> RPAR
| _ -> illegal buf (Char.chr (next buf))
and identifier buf =
match%sedlex buf with
| _ -> IDENTIFIER (Sedlexing.Utf8.lexeme buf)
(はい、基本的にノーオペレーション/可能な限り簡単なことです。私は学ぼうとしています! :x
)
残念ながら、この組み合わせにより、解析オートマトンで無限ループが発生します。
State 0:
Lookahead token is now IDENTIFIER (1-1)
Shifting (IDENTIFIER) to state 1
State 1:
Lookahead token is now IDENTIFIER (1-1)
Reducing production expression -> IDENTIFIER
State 5:
Shifting (IDENTIFIER) to state 1
State 1:
Lookahead token is now IDENTIFIER (1-1)
Reducing production expression -> IDENTIFIER
State 5:
Shifting (IDENTIFIER) to state 1
State 1:
...
私は解析と字句解析、およびこれらすべてに不慣れです。どんなアドバイスも大歓迎です。きっと初心者のミスだと思いますが…</p>
ありがとう!