0

所以,我正在尝试在 pegjs 中编写一个非常基本的 Lisp 解析器,只要 Lisp 代码在语法上有效并且适合一行,我就会让它吐出相同的代码。

我希望扩展解析器以能够接受插入任何地方的任何换行符以及代码中的额外空格。

因此,只要所有内容都在一行上,这里的代码就可以工作:

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)))"

虽然在每个“令牌”或“元组”之后只允许一个换行符是微不足道的,但我希望接受以下作为合法代码:

(f x

   (g     y (

       h z t) ) )
4

1 回答 1

0

原来这个问题非常类似于Ignore whitespace with 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 回答