Parsing 持续移位-减少Goldparser中的冲突

Parsing 持续移位-减少Goldparser中的冲突,parsing,shift-reduce-conflict,gold-parser,Parsing,Shift Reduce Conflict,Gold Parser,我真的被Goldparser中的Shift-Reduce冲突所困扰 我编写了一个类似PHP的语法,理论上应该能够解析以下脚本: public $Test = null; protected $bDemo = true; function Main() { } private function Run() { } 在顶部,我想分配全局变量,然后是函数定义 为了缩小问题的范围,我把我的大语法简化为以下几行,它们可以重现错误。显然,这是不完整的。函数没有参数,没有返回值,也没有语句 "Start

我真的被Goldparser中的Shift-Reduce冲突所困扰

我编写了一个类似PHP的语法,理论上应该能够解析以下脚本:

public $Test = null;
protected $bDemo = true;

function Main()
{
}

private function Run()
{
}
在顶部,我想分配全局变量,然后是函数定义

为了缩小问题的范围,我把我的大语法简化为以下几行,它们可以重现错误。显然,这是不完整的。函数没有参数,没有返回值,也没有语句

"Start Symbol"   = <Script>

! ------------------------------------------------- Sets

{Name} = {Letter} + {Alphanumeric} + [_]

! ------------------------------------------------- Terminals

VarName        = '$'  {Name}*
FuncName       = {Name}*

! ------------------------------------------------- Rules

<Variable>       ::= VarName

<Value>          ::= 'null'
                   | 'true'
                   | 'false'

<Modifier>       ::= 'private'
                   | 'protected'
                   | 'public'

<ModifierOpt>    ::= <Modifier>
                   |

! ---------------

<GlbAssignVar>   ::= <ModifierOpt> <Variable> '=' <Value> ';'

<GlobalList>     ::= <GlobalList> <GlbAssignVar>
                   | <GlbAssignVar>

<GlobalListOpt>  ::= <GlobalList>
                   | 

! ---------------

<FuncDef>        ::= <ModifierOpt> 'function'  FuncName '('  ')' '{'  '}'

<FuncList>       ::= <FuncList> <FuncDef>
                   | <FuncDef>

<FuncListOpt>    ::= <FuncList>
                   |

! ---------------

<Script>         ::=  <GlobalListOpt> <FuncListOpt>
“开始符号”=
! ------------------------------------------------- 设置
{Name}={Letter}+{Alphanumeric}+[[uUX]
! ------------------------------------------------- 终端
VarName='$'{Name}*
FuncName={Name}*
! ------------------------------------------------- 规则
:=VarName
:='null'
|“真的”
|“假”
:=“私人”
|“受保护”
|“公众”
::= 
|
! ---------------
::=   '='  ';'
::=  
| 
::= 
| 
! ---------------
::='函数'FuncName'('')'{'}'
::=  
| 
::= 
|
! ---------------
::=   
构建LALR表时,Goldparser告诉我:

“解决了减少冲突的问题 “private”、“protected”、“public”可以遵循已完成的规则,也可以进行转换。冲突是通过在“reduce”上选择“shift”操作解决的。请小心,某些语法部分可能无法访问。建议您尝试删除所有冲突。”

但是它所应用的修正使得语法不能正确工作。在上面的示例中,我在
function Main()
处得到一个语法错误,它需要一个“
private
”、“
protected
”或“
public
”,尽管我声明它们是可选的

当我从
定义或
定义中删除
时,错误消失


我不知道怎么解决这个问题。请帮忙

请记住,解析器生成器正在构建一个
LALR(1)
解析器,这意味着解析器需要能够在从左向右扫描输入(
LR
)时决定是减少已经完成的生产还是转移可能构成尚未完成生产一部分的令牌,仅查看下一个
(1)
标记(可能会移位的标记)

因此,假设我们只能看到第一个标记,
private
。现在,有两种可能性:

  • 有一个非空的
    GlobalList
    ,其中的第一个声明是
    private

  • GlobalList
    为空,但
    FuncList
    中的第一个函数声明为
    private

  • 这些对应于输入:

    private $a = null;
    
    private function a() {}
    
    但是我们只能看到令牌
    private

    我们正在进行的生产是:

    <Script>         ::=  <GlobalListOpt> <FuncListOpt>
    
    这是因为现在解析器总是可以移动
    私有的
    ,即使它不知道最终会减少哪个生产。(这就是LR解析的神奇之处:解析器可以同时保持多个产品处于活动状态;在产品实际减少之前,它不需要提交其中一个产品。)

    当然,更简单的解决方案是只允许用户将全局定义与函数交错:

    <Script>         ::= 
                       | <Script> <FuncDef>
                       | <Script> <GlbAssignVar>
    
    :=
    |  
    |  
    

    它摆脱了<代码> FunCalists<代码>,<代码> FielSistopt < /C>,<代码> Guulalists< /C>和 GualListopt ,但可能为用户提供了您认为太大的灵活性。p> 你太快了!我最近问了,已经得到了答案!谢谢是的,你是对的:错误不是我搜索过的。这是规矩。但你的答案并不完全正确。我既不能删除FuncList,也不能删除GlobalList,因为用户需要定义多个函数和多个变量。因此,最终起作用的是:::=| |@Elmue:是的,这比我提供的第一个示例更加一致。我在我的建议中留下了

    FuncListOpt
    ,只是因为这是一个最小的更改。第二个示例允许使用任意数量的函数和变量。试试看:)
    <Script>         ::= 
                       | <Script> <FuncDef>
                       | <Script> <GlbAssignVar>