VBScript Грамматика: Как смоделировать суб-вызов без скобок

Я пишу грамматику GOLD Parser для VBScript. Вот выдержка:

<CallStmt>             ::= 'Call' <CallExpr>
                         | <CallExpr> <ParameterList>
                         !| <CallExpr> '(' <Expr> ')'
                         | <CallExpr> '(' ')'

<AssignStmt>           ::= <CallExpr> '=' <Expr>
                         | 'Set' <CallExpr> '=' <Expr>
                         | 'Set' <CallExpr> '=' 'New' <CallExpr>

<CallExpr>             ::= '.' <LeftExpr>
                         | <LeftExpr>

<LeftExpr>             ::= ID
                         | IDDot <LeftExpr>
                         | ID '(' <ParameterList> ')'
                         | ID '(' <ParameterList> ').' <LeftExpr>

!VBScript allows to skip parameters a(1,,2)
<ParameterList>        ::= <Expr> ',' <ParameterList>
                         | ',' <ParameterList> 
                         | <Expr>
                         |

! Value can be reduced from <Expr>                       
<Value>                ::= <ConstExpr>
                         | <CallExpr>
                         | '(' <Expr> ')'                        

У меня конфликт по поводу <CallStmt> ::= <CallExpr> <ParameterList> править. Это правило описывает вызов sub без круглых скобок. Например, следующие утверждения синтаксически верны:

obj.sub1(1, 2).sub2 1, 2
obj.sub1(1, 2).sub2(1),(2)
Call obj.sub1(1, 2).sub2(1, 2)

Как я могу различить дополнительный вызов с окружающими скобками sub1(1, 2) и дополнительный вызов с круглыми скобками вокруг аргументов sub2(1),(2)?

1 ответ

Решение

Проблема в том, что синтаксис VBScript неоднозначен.

Какой вариант obj.sub1 (1)? Тот, у кого есть спаррины вокруг аргументов, или тот, у кого нет и первый аргумент случается в паранах?

Если мы не можем сказать, то и парсер не может... мы можем точно сказать, только когда у нас есть несколько аргументов, например, запятая. Поэтому предположим, что по умолчанию мы выбираем использование аргументов в качестве аргументов только в тех случаях, когда встречаемся с более чем одним параметром или вообще не имеем параметров.

В ваших усилиях по решению этой проблемы вы начали создавать сверхкомпетентные терминалы, в которые также входит точка. Это плохая идея, так как она не работает (пробелы вокруг "." Разрешены, но не соответствуют этим терминалам), и это может привести к неожиданному поведению токенизации и снижению производительности. Обычно это указывает на проблему в вашей грамматике.

Вот грамматика, которую я взломал вместе, которая прекрасно разбирает ваши образцы, и фактически должна также правильно обрабатывать назначения и вызовы конструктора. Обратите внимание, что <ParameterList> будет соответствовать только два или более параметров, но не ноль или один параметр; это ключ к решению проблемы, которая вызывает вашу проблему.

<CallStmt>    ::= 'Call' <CallPath>
               |  <CallPath>

<AssignStmt>  ::= <AssignPath> '=' <Expr>
               |  'Set' <AssignPath> '=' <Expr>
               |  'Set' <AssignPath> '=' 'New' <CtorPath>

<CtorPath>    ::= ID '.' <CtorPath>
               |  ID
               |  <CallExpr>
               |  ID <ParameterList>

<CallExpr>    ::= ID '(' ')'
               |  ID '(' <Expr> ')'
               |  ID '(' <ParameterList> ')'

<CallPath>    ::= <Member> '.' <CallPath>
               |  ID
               |  <CallExpr>
               |  ID <ParameterList>

<Member>      ::= <CallExpr>
               |  ID

<MemberPath>  ::= <Member> '.' <MemberPath>
               |  <Member>

<AssignPath>  ::= <Member> '.' <AssignPath>
               |  ID

!VBScript allows to skip parameters a(1,,2)
<ParameterList> ::= <Expr> ',' <ParameterList>
               | <Expr> ',' <Expr>
               | <Expr> ','
               | ',' <ParameterList> 
               | ','

! Value can be reduced from <Expr>                       
<Value>       ::= NumberLiteral
               | StringLiteral
               | <MemberPath>
               | '(' <Expr> ')'

!--- The rest of the grammar ---               
"Start Symbol"  = <Start>

{WS}            = {Whitespace} - {CR} - {LF}
{ID Head}       = {Letter} + [_]
{ID Tail}       = {Alphanumeric} + [_]
{String Chars}  = {Printable} + {HT} - ["]

Whitespace      = {WS}+
NewLine         = {CR}{LF} | {CR} | {LF}

ID              = {ID Head}{ID Tail}*
StringLiteral   = ('"' {String Chars}* '"')+
NumberLiteral   = {Number}+ ('.' {Number}+ )?

<nl>          ::= NewLine <nl>          !One or more
               |  NewLine

<nl Opt>      ::= NewLine <nl Opt>      !Zero or more
               |  !Empty

<Start>       ::= <nl opt> <StmtList>

<StmtList>    ::= <CallStmt> <nl> <StmtList>
               |  <AssignStmt> <nl> <StmtList>
               |

<Expr>        ::= <Add Exp> 

<Add Exp>     ::= <Add Exp> '+' <Mult Exp>
               |  <Add Exp> '-' <Mult Exp>
               |  <Mult Exp> 

<Mult Exp>    ::= <Mult Exp> '*' <Negate Exp> 
               |  <Mult Exp> '/' <Negate Exp> 
               |  <Negate Exp> 

<Negate Exp>  ::= '-' <Value> 
               |  <Value> 
Другие вопросы по тегам