解析結果をXMLで出力する

解析結果の出力をもう少し実用的(?)なものにしてみる。
とりあえずマークアップ言語界の雄XMLで出力してみよう。

translator.y
...snip
%%

xmltext : { fputs("<text>", stdout); } text { fputs("</text>", stdout); }

text :
      string_headed
    | marked_string_headed
    ;

string_headed :
      string_except_parenthesis { fputs($1, stdout); free($1); }
    | string_except_parenthesis { fputs($1, stdout); free($1); } marked_string_headed
    ;

marked_string_headed :
      marked_string
    | marked_string marked_string_headed
    | marked_string string_headed
    ;

marked_string :
      START_MARK marked_string_body_with_annotation END_MARK
    ;

marked_string_body_with_annotation :
      STRING_EXCEPT_SPECIAL
        {
            printf("<mark>%s</mark>", $1); free($1);
        }
    | STRING_EXCEPT_SPECIAL START_ANNOTATION string_except_parenthesis
        {
            printf("<mark>%s<annotation>%s</annotation></mark>", $1, $3);
            free($1); free($2); free($3);
        }
    ;

string_except_parenthesis :
...snip

translator.yはparser.yの構文規則部のみを変更したもので他は一切変えていない。
また、構文規則そのものを変えているのは一ヶ所だけで、
主要な変更はアクション中の標準出力への出力形式に関するものだけである。
構文規則で唯一変えたのは、これまでの開始記号textに代わり、
新たな開始記号xmltextを定義している部分である。
といってもxmltexttextからの単一生成規則であり、
単にtextに関わる出力をルート要素の開始タグと終了タグの出力で囲むためだけのものである。
記述は増えるがxmltextを定義しなくてもtextの規則だけでもこの処理に対応することはできる。
なので、この構文規則の変更はparser.yからの本質的な変更ではない。

このコードでは文字コードに関する処理は一切していないし、translatorの出力にXML宣言はない。
したがって、translatorへの入力はASCII前提であり、
既に述べているように解析が成功する正当な入力であればUTF-8でも大丈夫だと思う。

$ bison -dy translator.y

$ gcc -std=c89 -pedantic -Wall -Wextra -Werror -o translator y.tab.c mclex.c

$ echo -n "The (quick: swift) brown (fox) jumps over the (lazy: one of three virtues of a programmer) (dog)." | ./translator
<text>The <mark>quick<annotation> swift</annotation></mark> brown <mark>fox</mark> jumps over the <mark>lazy<annotation> one of three virtues of a programmer</annotation></mark> <mark>dog</mark>.</text>

ルート要素はtext、マークされた部分はmark要素、注釈部はannotation要素としている。
Firefoxでこの出力のドキュメントツリーを表示させるとこんな感じ。