diff options
author | Ryo Nihei <nihei.dev@gmail.com> | 2022-03-29 21:52:47 +0900 |
---|---|---|
committer | Ryo Nihei <nihei.dev@gmail.com> | 2022-03-29 22:12:37 +0900 |
commit | 90f28b5f7e7ef08e107e38002d122825764aad09 (patch) | |
tree | d80dfc08063727caa48fac4f28a929cb669c1465 /grammar/grammar.go | |
parent | Change syntax of production directives (diff) | |
download | urubu-90f28b5f7e7ef08e107e38002d122825764aad09.tar.gz urubu-90f28b5f7e7ef08e107e38002d122825764aad09.tar.xz |
Move directives given to lexical productions
Move all directives given to lexical productions from alternative directives to production directives.
This change aims to ensure consistency with respect to the syntax of definitions of terminal symbols and non-terminal symbols.
Diffstat (limited to 'grammar/grammar.go')
-rw-r--r-- | grammar/grammar.go | 66 |
1 files changed, 36 insertions, 30 deletions
diff --git a/grammar/grammar.go b/grammar/grammar.go index 9e8f30a..c5726d7 100644 --- a/grammar/grammar.go +++ b/grammar/grammar.go @@ -472,9 +472,34 @@ func (b *GrammarBuilder) genSymbolTableAndLexSpec(root *spec.RootNode) (*symbolT } func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *verr.SpecError, error) { + alt := prod.RHS[0] + elem := alt.Elements[0] + + var pattern string + var alias string + if elem.Literally { + pattern = mlspec.EscapePattern(elem.Pattern) + alias = elem.Pattern + } else { + pattern = elem.Pattern + } + var modes []mlspec.LexModeName - if prod.Directive != nil { - dir := prod.Directive + var skip bool + var push mlspec.LexModeName + var pop bool + dirConsumed := map[string]struct{}{} + for _, dir := range prod.Directives { + if _, consumed := dirConsumed[dir.Name]; consumed { + return nil, false, "", &verr.SpecError{ + Cause: semErrDuplicateDir, + Detail: dir.Name, + Row: dir.Pos.Row, + Col: dir.Pos.Col, + }, nil + } + dirConsumed[dir.Name] = struct{}{} + switch dir.Name { case "mode": if len(dir.Parameters) == 0 { @@ -496,34 +521,6 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *ve } modes = append(modes, mlspec.LexModeName(param.ID)) } - default: - return nil, false, "", &verr.SpecError{ - Cause: semErrDirInvalidName, - Detail: dir.Name, - Row: dir.Pos.Row, - Col: dir.Pos.Col, - }, nil - } - } - - alt := prod.RHS[0] - elem := alt.Elements[0] - - var pattern string - var alias string - if elem.Literally { - pattern = mlspec.EscapePattern(elem.Pattern) - alias = elem.Pattern - } else { - pattern = elem.Pattern - } - - var skip bool - var push mlspec.LexModeName - var pop bool - if alt.Directive != nil { - dir := alt.Directive - switch dir.Name { case "skip": if len(dir.Parameters) > 0 { return nil, false, "", &verr.SpecError{ @@ -574,6 +571,15 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *ve } } + if alt.Directive != nil { + return nil, false, "", &verr.SpecError{ + Cause: semErrInvalidAltDir, + Detail: "a lexical production cannot have alternative directives", + Row: alt.Directive.Pos.Row, + Col: alt.Directive.Pos.Col, + }, nil + } + return &mlspec.LexEntry{ Modes: modes, Kind: mlspec.LexKindName(prod.LHS), |