注釈付きでマークされた文字列の解析 #2
前回BNFで示した構文生成規則はこれまでの構文の定義と似ているため、
これを基にして構文解析器生成系のソースを書くとやっぱり似ることになる。というかほとんど同じだ。
parser.y
%{ #include <stdio.h> int yylex(void); void yyerror(char const *); %} %token CHAR_EXCEPT_SPECIAL %% text : string_headed | marked_string_headed ; string_headed : string { puts("]"); } | string { puts("]"); } marked_string_headed ; marked_string_headed : marked_string | marked_string marked_string_headed | marked_string string_headed ; marked_string : '(' marked_string_body_with_annotation ')' { puts("]"); } ; string : char_except_parenthesis { printf("string [%c", $1); } | string char_except_parenthesis { putchar($2); } ; char_except_parenthesis : CHAR_EXCEPT_SPECIAL | ':' { $$ = ':'; } ; marked_string_body_with_annotation : marked_string_body | marked_string_body ':' annotation ; marked_string_body : CHAR_EXCEPT_SPECIAL { printf("marked-string [%c", $1); } | marked_string_body CHAR_EXCEPT_SPECIAL { putchar($2); } ; annotation : char_except_parenthesis { printf("]: annotation [%c", $1); } | annotation char_except_parenthesis { putchar($2); } ; %% int main(void) { return yyparse(); } int yylex(void) { int c = getchar(); if (c == '(' || c == ')' || c == ':') return c; if (c == EOF) return 0; yylval = c; return CHAR_EXCEPT_SPECIAL; } void yyerror(char const *s) { fprintf(stderr, "%s\n", s); }
括弧以外の文字を表す非終端記号char_except_parenthesis
の意味値を正しく与えられるように、
リテラル文字トークン':'
を還元するときにアクション$$ = ':';
を実行する。
$ echo -n "The (quick: swift) brown (fox) jumps over the (lazy: one of three virtues of a programmer) (dog)." | ./parser string [The ] marked-string [quick]: annotation [ swift] string [ brown ] marked-string [fox] string [ jumps over the ] marked-string [lazy]: annotation [ one of three virtues of a programmer] string [ ] marked-string [dog] string [.]
のように、マーク外の文字列string、マークされた文字列marked-string、その注釈annotationを区別して出力できている。
$ echo -n "::(a::)(b:c:)" | ./parser string [::] marked-string [a]: annotation [:] marked-string [b]: annotation [c:]
マーク外の文字列や注釈にはコロンが許されるので、このような入力も受容する。