0

だから、私は pegjs で非常に基本的な Lisp パーサーを書こうとしていて、Lisp コードが構文的に有効で 1 行に収まる限り、同じコードを吐き出すことができました。

コード内の任意の場所に挿入された改行文字と余分な空白を受け入れることができるようにパーサーを拡張したいと考えています。

したがって、すべてが1行にある限り機能するコードは次のとおりです。

Start
  = List

Character
  = [^\n" ""("")"]

LeftParenthesis
  = "("

RightParenthesis
  = ")"

WhiteSpace
  = " "

NewLine
  = "\n"

Token
  = token:Character+{return token.join("");}

Tuple
  = left:Token WhiteSpace+ right:List?{
        return left.concat([" "]).concat(right);
    }
  / Token

List
  = left:LeftParenthesis tuple:Tuple right:RightParenthesis{
        return left.concat(tuple).concat(right);
    }
  / Tuple

次に、改行と空白を許可しようとして、「タプル」のルールを次のように変更してみました

Tuple
  = left:Token WhiteSpace+ (NewLine* WhiteSpace*)* right:List?{
        return left.concat([" "]).concat(right);
    }
  / Token

しかし、この変更により pegjs は無限ループに入りますが、ルールへの追加は再帰的ではないように見えます。

注:私が何をしようとしているのか不明な場合は、pegjs が解析するパーサーを吐き出すような文法を書いています。

(f x 
  (g y 
    (h z t)))

文字列と同じコードを吐き出すか、単に

"(f x (g y (h z t)))" 

どちらも私にとってはうまくいきます。

私の現在の作業文法が行うことは、

(f x (g y (h z t)))

と出力

"(f x (g y (h z t)))"

各「トークン」または「タプル」の後に改行文字を 1 つだけ許可するのは些細なことですが、合法的なコードとして次を受け入れたいと思います。

(f x

   (g     y (

       h z t) ) )
4

1 に答える 1

0

この質問は、PEG.jsで空白を無視するに非常に似ていることがわかりました

空白と改行を無視することがすべてです。上記のコードが失敗する理由は実際にはわかりませんが、遊んだ後、pegjsにやりたいことをさせることができました

Start
  = List

Character
  = [^ \t\r\n"("")"]

LeftParenthesis
  = "("

RightParenthesis
  = ")"

Separator
  = [ \t\r\n]

Token
  = List
  / token:Character+{return token.join("");}

Tuple
  = first:Token second:Separator+ rest:Tuple*{
        return rest.length > 0 ? first.concat([" "]).concat(rest) : first;
    }
  / Token

List
  = left:LeftParenthesis Separator* token:Tuple Separator* right:RightParenthesis{
        return [left].concat(token).concat([right]).join("");
     }

したがって、解析する次の文字列を指定すると:

(f x

   (g     y (

       h z t) ) )

パーサーの出力

"(f x (g y (h z t)))"

これはまさに私が欲しかったものです

于 2014-04-05T17:02:44.673 に答える