Я пытаюсь написать грамматику LBNF / BNFC для C-подобного языка.В C есть много возможных модификаторов, которые вы можете или не можете писать перед объявлением (например, inline
, const
, volatile
и т. Д.).
Я пытаюсь написать свою грамматику, чтобы повторно использовать код и сделать полученный Haskell AST простым для использования.Грамматика для типов может выглядеть так:
rule TypeName ::= "bool" | "int" | "double" | "void" | Id ;
Type. Type ::= TypeQualifier TypeName;
ConstModifier. TypeModifier ::= "const" ;
VolatileModifier. TypeModifier ::= "volatile" ;
NoModifier. TypeModifier ::= ;
А для объявления функции это может выглядеть следующим образом:
Fun. Fun ::= FunModifier Type Id "(" [Param] ")" ";" ;
InlineModifier. FunModifier ::= "inline" ;
NoFunModifier. FunModifier ::= ;
Проблема в том, что я получаю тоннусдвиг / уменьшение, а иногда даже уменьшение / уменьшение конфликтов из-за этих необязательных префиксов.Альтернативная грамматика, позволяющая избежать этих конфликтов, может выглядеть следующим образом:
NotInlinedFun. Fun ::= Type Id "(" [Param] ")" ";" ;
InlinedFun. Fun ::= "inline" Type Id "(" [Param] ")" ";" ;
или
NotInlinedFun. Fun ::= FunRest
InlinedFun. Fun ::= "inline" FunRest;
FunRest. FunRest ::= Type Id "(" [Param] ")" ";" ;
, что приводит к AST на Haskell, например:
data Fun = AFun FunRest | BFun FunRest | CFun FunRest
data FunRest = FunRest Type Id [Param]
из более привлекательных
data Fun = Fun Modifier Type Id [Param]
data Modifier = A | B | C
Вы можете видеть, как это может быстро привести к комбинаторному взрыву правил или к Haskell AST, который не будет приятным в использовании.
Как мне лучше всегоизбежать этих конфликтов?