diff --git a/compiler/syntax.go b/compiler/syntax.go index 0ec1137c9..ebebe42f8 100644 --- a/compiler/syntax.go +++ b/compiler/syntax.go @@ -379,6 +379,20 @@ func (c *syntaxLoader) convertSet(expr ast.SetExpression, nonterm *syntax.Nonter default: c.Errorf(op, "operator must be one of: first, last, precede or follow") } + } else { + // Check if the reference targets another named set. + name := expr.Symbol().Name() + if index, ok := c.namedSets[name.Text()]; ok { + if index >= len(c.out.Sets) { + c.Errorf(expr.TmNode(), "forward references are not allowed") + return ret + } + if _, ok := c.resolveRefIndex(expr.Symbol()); ok { + c.Errorf(expr.TmNode(), "ambigious reference") + return ret + } + return c.out.Sets[index] + } } ret.Symbol, ret.Args = c.resolveRef(expr.Symbol(), nonterm) return ret @@ -510,7 +524,7 @@ func (c *syntaxLoader) instantiateOpt(name string, origin ast.Symref) (int, bool return index, true } -func (c *syntaxLoader) resolveRef(ref ast.Symref, nonterm *syntax.Nonterm) (int, []syntax.Arg) { +func (c *syntaxLoader) resolveRefIndex(ref ast.Symref) (int, bool) { name := ref.Name() text := name.Text() index, ok := c.resolver.syms[text] @@ -523,6 +537,13 @@ func (c *syntaxLoader) resolveRef(ref ast.Symref, nonterm *syntax.Nonterm) (int, if !ok && len(text) > 3 && strings.HasSuffix(text, "opt") { index, ok = c.instantiateOpt(text, ref) } + return index, ok +} + +func (c *syntaxLoader) resolveRef(ref ast.Symref, nonterm *syntax.Nonterm) (int, []syntax.Arg) { + name := ref.Name() + text := name.Text() + index, ok := c.resolveRefIndex(ref) if !ok { c.Errorf(name, "unresolved reference '%v'", text) return 0, nil // == eoi diff --git a/parsers/test/parser_tables.go b/parsers/test/parser_tables.go index 05c318fc2..8c67213e1 100644 --- a/parsers/test/parser_tables.go +++ b/parsers/test/parser_tables.go @@ -224,5 +224,15 @@ var tmRuleType = [...]uint32{ 0, // QualifiedNameopt : } +// set(MINUS | PLUS) = MINUS, PLUS +var plusMinus = []token.Type{ + 25, 27, +} + +// set((MINUS | PLUS) | MINUSGT) = MINUS, MINUSGT, PLUS +var plusMinusArrow = []token.Type{ + 25, 26, 27, +} + // set(follow ERROR) = var afterErr = []token.Type{} diff --git a/parsers/test/test.tm b/parsers/test/test.tm index b2fe5e754..6b8dde694 100644 --- a/parsers/test/test.tm +++ b/parsers/test/test.tm @@ -120,6 +120,9 @@ MultiLineComment -> MultiLineComment: /\/\*/ (space) :: parser +%generate plusMinus = set('-' | '+'); +%generate plusMinusArrow = set(plusMinus | '->'); + %input Test, Decl1; Test -> Test: @@ -166,7 +169,7 @@ foo_la: ; foo_nonterm : - IntegerConstant '.' expr + IntegerConstant '.' expr | [A] IntegerConstant 'foo_' expr ;