2

マークアップ区切り文字をエスケープできるマークアップ言語用の Jison (Bison) 文法を作成したいと考えています。

これらは有効です:

I like apples
I like [apples, oranges, pears]
I like [apples, oranges, pears] and [peanut butter, jelly]
I like [apples, oranges, pears] \[when they're in season\]
I like emoticons :-\]

例は、おそらく次のように解釈されます (JSON 表現)。

["I like apples"]
["I like ", ["apples", "oranges", "pears"]]
["I like ", ["apples", "oranges", "pears"], " and ", ["peanut butter", "jelly"]]
["I like ", ["apples", "oranges", "pears"], " [when they're in season]"]
["I like emoticons :-]"]

のエスケープ[]\,は最小限ですが、エスケープが不要な場合でも、印刷可能な文字をエスケープできるようにすることはおそらく理にかなっています。

印刷できない文字のエスケープがサポートされていないといいのですが。つまり\、行末の a は不正です。正規表現.には改行が含まれていない可能性があるため、これは無料である可能性がありますが、他の印刷できない文字でも発生するはずです。

Bison 定義などでリテラル文字をエスケープするための多くの結果と混同されているため、これをグーグルで検索するのは困難です。

Bison で定義された言語でエスケープ文字をサポートする最もエレガントな方法は何ですか?

編集

ここに私がこれまでに持っていて、 Jison でテストできるものがありますが、機能1していません (何かあれば返されるだけです)。テキストがエスケープされずに到着することは期待できません。それは避けられますか?

/* description: markup */

/* lexical grammar */
%lex
%%

(\\.|[^\\\[])+            return 'TOPTEXT'
(\\.|[^\\\[\]\,])+        return 'TEXT'
\-?[0-9]+("."[0-9]+)?\b   return 'NUMBER'
".."|"-"                  return '..'
"["                       return '['
"]"                       return ']'
","                       return ','
<<EOF>>                   return 'EOF'

/lex

%start markup

%%

markup
    : template EOF
        { return $template; }
    ;

template
    : template TOPTEXT
        { $$ = $template.push($TOPTEXT); }
    | template dynamic
        { $$ = $template.push($dynamic); }
    | /* empty */
        { $$ = []; }
    ;

dynamic
    : '[' phraselist ']'
        { $$ = $phraselist; }
    ;

phraselist
    : phraselist ',' phrase
        { $$ = $phraselist.push($phrase); }
    | /* empty */
        { $$ = []; }
    ;

phrase
    : TEXT
        { $$ = $phrase.push($TEXT); }
    | phrase dynamic
        { $$ = $phrase.push($dynamic); }
    | /* empty */
        { $$ = []; }
    ;
4

1 に答える 1

2

あなたのコードには複数の問題があると思います。

最初の (そしてこれが1出力を説明します) は[].push、リストの新しい長さを返すことです。したがって、必要なのはおそらくプッシュであり、値定義します。

template
: template TOPTEXT
    { $template.push($TOPTEXT); $$ = $template; }
| template dynamic
    { $template.push($dynamic); $$ = $template; }
| /* empty */
    { $$ = []; }
;

もう 1 つのことは、あまりにも多くのことを同時に機能させようとしているように見えることです。それらが必要であるか、またはそれらが実際に想定どおりに機能しているかを本当に確信していません。

たぶん、基本から始めて、一度に 1 つのルールを機能させるように、小さく始める方が良い戦略になるでしょう。

たとえば、トークンを出力するだけの単純な文法でテストして、すべてのケースでレクサーが機能していることを最初に確認できます。

%lex
%%

(\\\\|\\\[|\\\]|\\\,|[^,\\\[\]])+   return 'TEXT'
\-?[0-9]+("."[0-9]+)?\b             return 'NUMBER'
".."|"-"                            return 'RANGE'
"["                                 return '['
"]"                                 return ']'
","                                 return ','

/lex

%start lexertest

%%

lexertest:
token lexertest
| /* empty */
;

token:
TEXT    { console.log("Token TEXT: |" + $TEXT +  "|"); }
|
NUMBER  { console.log("Token NUMBER: |" + $NUMBER +  "|"); }
|
'['     { console.log("Token ["); }
|
']'     { console.log("Token ]"); }
|
','     { console.log("Token ,"); }
|
'RANGE' { console.log("Token RANGE: |" + $1 +  "|"); }
;

注:ブラウザーで実行する場合、console.log出力は開発者ツールにのみ表示されます。このようなスクリプト (Bash の場合)を使用してコマンド ラインで Jison を使用すると、複数の入力を使用して簡単にテストできます。

それから、満足するまでそれを改良します。lexer に満足したら、文法を機能させるための作業を開始し、一度に 1 つのルールを再度テストします。レクサーの出力をデバッグするときはいつでも上記のルールを維持してください。ルールを変更するだけ%startです。

最終的にEOFは、最初から不要であることに気付くかもしれません。また、フリー テキストを一致させるために 2 つの異なるルールを使用する必要はないかもしれません。

それが役に立てば幸い。

于 2012-09-25T14:05:21.697 に答える