注釈付きでマークされた文字列の解析 #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:]

マーク外の文字列や注釈にはコロンが許されるので、このような入力も受容する。