From eb678d0cb47b840a145f3479ee3626805c140250 Mon Sep 17 00:00:00 2001 From: linkrope Date: Wed, 14 Aug 2024 23:54:40 +0200 Subject: [PATCH] Postpone problem with ambiguity of actual parameters to semantic analysis --- TODO.md | 2 +- src/gamma/grammar/PrintingVisitor.d | 2 +- src/gamma/grammar/hyper/ActualParams.d | 41 +++ src/gamma/grammar/hyper/EBNFConverter.d | 58 +++-- src/gamma/grammar/hyper/Group.d | 5 +- ...titionAlternative.d => HyperAlternative.d} | 21 +- src/gamma/grammar/hyper/HyperSymbolNode.d | 22 -- src/gamma/grammar/hyper/HyperVisitor.d | 9 +- src/gamma/grammar/hyper/Operator.d | 11 +- src/gamma/grammar/hyper/Option.d | 4 +- src/gamma/grammar/hyper/Params.d | 2 +- .../grammar/hyper/PrintingHyperVisitor.d | 135 +++++----- src/gamma/grammar/hyper/Repetition.d | 4 +- src/gamma/grammar/hyper/Signature.d | 6 - src/gamma/input/epsilang/parser.d | 245 +++++++----------- 15 files changed, 278 insertions(+), 289 deletions(-) create mode 100644 src/gamma/grammar/hyper/ActualParams.d rename src/gamma/grammar/hyper/{RepetitionAlternative.d => HyperAlternative.d} (50%) mode change 100755 => 100644 delete mode 100755 src/gamma/grammar/hyper/HyperSymbolNode.d delete mode 100755 src/gamma/grammar/hyper/Signature.d diff --git a/TODO.md b/TODO.md index b8a1b06..1761728 100644 --- a/TODO.md +++ b/TODO.md @@ -9,7 +9,7 @@ - we finish `gamma.input` (handling of affix forms) - we transform the gamma grammar model into the epsilon grammar model - (to reuse the compiler generation) + (to reuse the compiler generation) - we remove the epsilon analyzer and move the lexer to `gamma.input.epsilang` ## Escape Sequences diff --git a/src/gamma/grammar/PrintingVisitor.d b/src/gamma/grammar/PrintingVisitor.d index a144f85..b5bb096 100755 --- a/src/gamma/grammar/PrintingVisitor.d +++ b/src/gamma/grammar/PrintingVisitor.d @@ -62,7 +62,7 @@ private class PrintingVisitor(Writer) : Visitor this.writer.put(symbolNode.symbol.toString); } - public void visit(Rule rule) + public void visit(Rule rule) { rule.alternatives.front.lhs.accept(this); this.writer.put(" ="); diff --git a/src/gamma/grammar/hyper/ActualParams.d b/src/gamma/grammar/hyper/ActualParams.d new file mode 100644 index 0000000..ab03ee4 --- /dev/null +++ b/src/gamma/grammar/hyper/ActualParams.d @@ -0,0 +1,41 @@ +module gamma.grammar.hyper.ActualParams; + +import gamma.grammar.hyper.HyperVisitor; +import gamma.grammar.hyper.Operator; +import gamma.grammar.hyper.Params; +import gamma.grammar.Node; +import gamma.grammar.Visitor; +import gamma.util.Position; + +/** + * This value object represents actual parameters on the right-hand side of a hyper rule. + * + * Note that for ident [ ActualParams ] [ ActualParams ] '(' (or '[' or '{') + * it is not obvious whether single ActualParams belong to ident or to '('. + * To keep the parser simple, this problem is postponed to semantic analysis. + */ +public class ActualParams : Node +{ + private Params params_; + + public this(Params params) + { + super(params.position); + this.params_ = params; + } + + public override void accept(Visitor visitor) + { + accept(cast(HyperVisitor) visitor); + } + + public void accept(HyperVisitor visitor) + { + visitor.visit(this); + } + + public Params params() + { + return this.params_; + } +} diff --git a/src/gamma/grammar/hyper/EBNFConverter.d b/src/gamma/grammar/hyper/EBNFConverter.d index 57a5704..978ce06 100644 --- a/src/gamma/grammar/hyper/EBNFConverter.d +++ b/src/gamma/grammar/hyper/EBNFConverter.d @@ -2,12 +2,12 @@ module gamma.grammar.hyper.EBNFConverter; import gamma.grammar.Alternative; import gamma.grammar.Grammar; +import gamma.grammar.hyper.ActualParams; import gamma.grammar.hyper.Group; -import gamma.grammar.hyper.HyperSymbolNode; +import gamma.grammar.hyper.HyperAlternative; import gamma.grammar.hyper.HyperVisitor; import gamma.grammar.hyper.Option; import gamma.grammar.hyper.Repetition; -import gamma.grammar.hyper.RepetitionAlternative; import gamma.grammar.Node; import gamma.grammar.Nonterminal; import gamma.grammar.Rule; @@ -37,7 +37,7 @@ private class EBNFConverter : HyperVisitor Nonterminal startSymbol; - SymbolNode[] lhsStack; + bool[] repetitionStack; Node[][] rhsStack; @@ -48,15 +48,29 @@ private class EBNFConverter : HyperVisitor this.terminals = grammar.terminals; this.alternatives = null; this.startSymbol = grammar.startSymbol; + + this.repetitionStack ~= false; + scope (exit) + this.repetitionStack.popBack; + grammar.rules.each!(rule => rule.accept(this)); } + void visit(HyperAlternative hyperAlternative) + { + visit(cast(Alternative) hyperAlternative); + } + void visit(Alternative alternative) { this.rhsStack ~= null; + scope (exit) + this.rhsStack.popBack; + alternative.rhs.each!(node => node.accept(this)); + if (this.repetitionStack.back) + this.rhsStack.back ~= alternative.lhs; this.alternatives ~= new Alternative(alternative.lhs, this.rhsStack.back, alternative.position); - this.rhsStack.popBack; } void visit(SymbolNode symbolNode) @@ -64,54 +78,56 @@ private class EBNFConverter : HyperVisitor this.rhsStack.back ~= symbolNode; } + void visit(ActualParams) + { + // do nothing + } + void visit(Rule rule) { - this.lhsStack ~= rule.lhs; rule.alternatives.each!(alternative => alternative.accept(this)); - this.lhsStack.popBack; } void visit(Group group) { + this.repetitionStack ~= false; + scope (exit) + this.repetitionStack.popBack; + this.rhsStack.back ~= group.rule.lhs; group.rule.accept(this); } void visit(Option option) { + this.repetitionStack ~= false; + scope (exit) + this.repetitionStack.popBack; + this.rhsStack.back ~= option.rule.lhs; option.rule.accept(this); auto nonterminal = cast(Nonterminal) option.rule.lhs.symbol; - SymbolNode symbolNode = new HyperSymbolNode(nonterminal, option.endParams, option.position); + auto symbolNode = new SymbolNode(nonterminal, option.position); this.alternatives ~= new Alternative(symbolNode, null, option.position); } void visit(Repetition repetition) { + this.repetitionStack ~= true; + scope (exit) + this.repetitionStack.popBack; + this.rhsStack.back ~= repetition.rule.lhs; repetition.rule.accept(this); auto nonterminal = cast(Nonterminal) repetition.rule.lhs.symbol; - SymbolNode symbolNode = new HyperSymbolNode(nonterminal, repetition.endParams, repetition.position); + auto symbolNode = new SymbolNode(nonterminal, repetition.position); this.alternatives ~= new Alternative(symbolNode, null, repetition.position); } - void visit(RepetitionAlternative alternative) - { - this.rhsStack ~= null; - alternative.rhs.each!(node => node.accept(this)); - - auto nonterminal = cast(Nonterminal) this.lhsStack.back.symbol; - SymbolNode symbolNode = new HyperSymbolNode(nonterminal, alternative.params, alternative.position); - Node[] rhs = this.rhsStack.back ~ symbolNode; - - this.alternatives ~= new Alternative(alternative.lhs, rhs, alternative.position); - this.rhsStack.popBack; - } - Grammar grammar() { import std.algorithm : filter; diff --git a/src/gamma/grammar/hyper/Group.d b/src/gamma/grammar/hyper/Group.d index edfc935..2cf795f 100755 --- a/src/gamma/grammar/hyper/Group.d +++ b/src/gamma/grammar/hyper/Group.d @@ -2,7 +2,6 @@ module gamma.grammar.hyper.Group; import gamma.grammar.hyper.HyperVisitor; import gamma.grammar.hyper.Operator; -import gamma.grammar.hyper.Params; import gamma.grammar.Rule; import gamma.util.Position; @@ -10,9 +9,9 @@ public class Group : Operator { alias accept = Operator.accept; - public this(Params params, Rule rule, Position position) + public this(Rule rule, Position position) { - super(params, rule, position); + super(rule, position); } public override void accept(HyperVisitor visitor) diff --git a/src/gamma/grammar/hyper/RepetitionAlternative.d b/src/gamma/grammar/hyper/HyperAlternative.d old mode 100755 new mode 100644 similarity index 50% rename from src/gamma/grammar/hyper/RepetitionAlternative.d rename to src/gamma/grammar/hyper/HyperAlternative.d index f5fbd48..9f4131e --- a/src/gamma/grammar/hyper/RepetitionAlternative.d +++ b/src/gamma/grammar/hyper/HyperAlternative.d @@ -1,26 +1,33 @@ -module gamma.grammar.hyper.RepetitionAlternative; +module gamma.grammar.hyper.HyperAlternative; import gamma.grammar.Alternative; -import gamma.grammar.hyper.HyperVisitor; import gamma.grammar.hyper.Params; import gamma.grammar.Node; +import gamma.grammar.Nonterminal; import gamma.grammar.SymbolNode; -import gamma.grammar.Visitor; +import gamma.grammar.hyper.HyperVisitor; import gamma.util.Position; -public class RepetitionAlternative : Alternative +public class HyperAlternative : Alternative { + alias accept = Alternative.accept; + private Params params_; - public this(SymbolNode lhs, Node[] rhs, Params params, Position position) + private Node[] rhs_; + + private Position position_; + + public this(SymbolNode lhs, Params params, Node[] rhs, Position position) + in (cast(Nonterminal) lhs.symbol()) { super(lhs, rhs, position); this.params_ = params; } - public override void accept(Visitor visitor) + public void accept(HyperVisitor visitor) { - (cast(HyperVisitor) visitor).visit(this); + visitor.visit(this); } public Params params() diff --git a/src/gamma/grammar/hyper/HyperSymbolNode.d b/src/gamma/grammar/hyper/HyperSymbolNode.d deleted file mode 100755 index af344c6..0000000 --- a/src/gamma/grammar/hyper/HyperSymbolNode.d +++ /dev/null @@ -1,22 +0,0 @@ -module gamma.grammar.hyper.HyperSymbolNode; - -import gamma.grammar.hyper.Params; -import gamma.grammar.Nonterminal; -import gamma.grammar.SymbolNode; -import gamma.util.Position; - -public class HyperSymbolNode : SymbolNode -{ - private Params params_; - - public this(Nonterminal nonterminal, Params params, Position position) - { - super(nonterminal, position); - this.params_ = params; - } - - public Params params() - { - return this.params_; - } -} diff --git a/src/gamma/grammar/hyper/HyperVisitor.d b/src/gamma/grammar/hyper/HyperVisitor.d index 8f2e1a1..980b404 100755 --- a/src/gamma/grammar/hyper/HyperVisitor.d +++ b/src/gamma/grammar/hyper/HyperVisitor.d @@ -1,18 +1,21 @@ module gamma.grammar.hyper.HyperVisitor; +import gamma.grammar.hyper.ActualParams; import gamma.grammar.hyper.Group; +import gamma.grammar.hyper.HyperAlternative; import gamma.grammar.hyper.Option; import gamma.grammar.hyper.Repetition; -import gamma.grammar.hyper.RepetitionAlternative; import gamma.grammar.Visitor; public interface HyperVisitor : Visitor { + public void visit(HyperAlternative); + + public void visit(ActualParams); + public void visit(Group); public void visit(Option); public void visit(Repetition); - - public void visit(RepetitionAlternative); } diff --git a/src/gamma/grammar/hyper/Operator.d b/src/gamma/grammar/hyper/Operator.d index c9a5308..f8b8792 100755 --- a/src/gamma/grammar/hyper/Operator.d +++ b/src/gamma/grammar/hyper/Operator.d @@ -1,7 +1,6 @@ module gamma.grammar.hyper.Operator; import gamma.grammar.hyper.HyperVisitor; -import gamma.grammar.hyper.Params; import gamma.grammar.Node; import gamma.grammar.Rule; import gamma.grammar.Visitor; @@ -9,14 +8,11 @@ import gamma.util.Position; public abstract class Operator : Node { - private Params params_; - private Rule rule_; - protected this(Params params, Rule rule, Position position) + protected this(Rule rule, Position position) { super(position); - this.params_ = params; this.rule_ = rule; } @@ -27,11 +23,6 @@ public abstract class Operator : Node public abstract void accept(HyperVisitor visitor); - public Params params() - { - return this.params_; - } - public Rule rule() { return this.rule_; diff --git a/src/gamma/grammar/hyper/Option.d b/src/gamma/grammar/hyper/Option.d index 683d0ca..23070c6 100755 --- a/src/gamma/grammar/hyper/Option.d +++ b/src/gamma/grammar/hyper/Option.d @@ -12,9 +12,9 @@ public class Option : Operator private Params endParams_; - public this(Params params, Rule rule, Params endParams, Position position) + public this(Rule rule, Params endParams, Position position) { - super(params, rule, position); + super(rule, position); this.endParams_ = endParams; } diff --git a/src/gamma/grammar/hyper/Params.d b/src/gamma/grammar/hyper/Params.d index 46bebe0..d02a97c 100755 --- a/src/gamma/grammar/hyper/Params.d +++ b/src/gamma/grammar/hyper/Params.d @@ -3,7 +3,7 @@ module gamma.grammar.hyper.Params; import gamma.input.earley.AffixForm; import gamma.util.Position; -// TODO: may gamma.grammar depend on gamma.input.earley? +// FXIME: gamma.grammar max not depend on gamma.input.earley public class Params { private AffixForm[] affixForms_; diff --git a/src/gamma/grammar/hyper/PrintingHyperVisitor.d b/src/gamma/grammar/hyper/PrintingHyperVisitor.d index 5abb27f..8f2b60a 100755 --- a/src/gamma/grammar/hyper/PrintingHyperVisitor.d +++ b/src/gamma/grammar/hyper/PrintingHyperVisitor.d @@ -3,11 +3,13 @@ module gamma.grammar.hyper.PrintingHyperVisitor; import gamma.grammar.affixes.Variable; import gamma.grammar.Alternative; import gamma.grammar.Grammar; +import gamma.grammar.hyper.ActualParams; import gamma.grammar.hyper.Group; +import gamma.grammar.hyper.HyperAlternative; import gamma.grammar.hyper.HyperVisitor; import gamma.grammar.hyper.Option; +import gamma.grammar.hyper.Params; import gamma.grammar.hyper.Repetition; -import gamma.grammar.hyper.RepetitionAlternative; import gamma.grammar.Node; import gamma.grammar.Rule; import gamma.grammar.SymbolNode; @@ -46,62 +48,68 @@ private class PrintingHyperVisitor(Writer) : HyperVisitor public void visit(Grammar grammar) { - foreach (i, rule; grammar.rules.enumerate) - { - if (i > 0) - this.writer.put("\n"); - rule.accept(this); - } + import std.algorithm : each; + + grammar.rules.each!(rule => rule.accept(this)); } - public void visit(Alternative alternative) + public void visit(Rule rule) { - foreach (i, node; alternative.rhs.enumerate) + foreach (alternative; rule.alternatives) { - if (i > 0) + alternative.lhs.accept(this); + this.writer.put(":"); + this.indentation = " "; + alternative.accept(this); + if (alternative.rhs.empty) { this.writer.put("\n"); this.writer.put(this.indentation); } - node.accept(this); + this.writer.put(".\n"); } } - public void visit(SymbolNode symbolNode) + public void visit(Alternative alternative) { - import gamma.grammar.hyper.HyperSymbolNode : HyperSymbolNode; + if (auto hyperAlternative = cast(HyperAlternative) alternative) + { + visit(hyperAlternative); + return; + } - this.writer.put(symbolNode.symbol.toString); - if (cast(HyperSymbolNode) symbolNode) + foreach (node; alternative.rhs) { - auto hyperSymbolNode = cast(HyperSymbolNode) symbolNode; + this.writer.put("\n"); + this.writer.put(this.indentation); + node.accept(this); + } + } - if (hyperSymbolNode.params !is null) - { - this.writer.put(" <"); - foreach (i, affixForm; hyperSymbolNode.params.affixForms.enumerate) - { - if (i > 0) - this.writer.put(", "); - this.writer.write(affixForm); - } - this.writer.put(">"); - } + public void visit(HyperAlternative alternative) + { + if (alternative.params !is null) + { + this.writer.put(" "); + this.writer.write(alternative.params); + } + + foreach (node; alternative.rhs) + { + this.writer.put("\n"); + this.writer.put(this.indentation); + node.accept(this); } } - public void visit(Rule rule) + public void visit(SymbolNode symbolNode) { - Alternative alternative = rule.alternatives.front; + this.writer.put(symbolNode.symbol.toString); + } - alternative.lhs.accept(this); - this.writer.put(":"); - this.indentation = null; - printHyperExpr(rule.alternatives); - if (!rule.alternatives.back.rhs.empty) - this.writer.put(".\n"); - else - this.writer.put(" .\n"); + public void visit(ActualParams actualParams) + { + this.writer.write(actualParams.params); } public void visit(Group group) @@ -120,6 +128,11 @@ private class PrintingHyperVisitor(Writer) : HyperVisitor this.writer.put("\n"); this.writer.put(this.indentation); this.writer.put("]"); + if (option.endParams !is null) + { + this.writer.put(" "); + this.writer.write(option.endParams); + } } public void visit(Repetition repetition) @@ -129,11 +142,11 @@ private class PrintingHyperVisitor(Writer) : HyperVisitor this.writer.put("\n"); this.writer.put(this.indentation); this.writer.put("}"); - } - - public void visit(RepetitionAlternative alternative) - { - visit(cast(Alternative) alternative); + if (repetition.endParams !is null) + { + this.writer.put(" "); + this.writer.write(repetition.endParams); + } } private void printHyperExpr(Alternative[] alternatives) @@ -146,22 +159,11 @@ private class PrintingHyperVisitor(Writer) : HyperVisitor this.indentation ~= " "; foreach (i, alternative; alternatives.enumerate) { - if (i == 0) - { - if (!alternative.rhs.empty) - { - this.writer.put("\n"); - this.writer.put(this.indentation); - } - } - else + if (i > 0) { this.writer.put("\n"); this.writer.put(indentation); - if (!alternative.rhs.empty) - this.writer.put(" | "); - else - this.writer.put(" |"); + this.writer.put("|"); } alternative.accept(this); } @@ -180,17 +182,32 @@ unittest const expected = ` A: - A - | . - + A. + A: + . + B: + . B: - | B. + B. `.outdent.stripLeft; assert(grammar.toPrettyString == expected); } } +private void write(Writer)(Writer writer, Params params) +in (params !is null) +{ + writer.put("<"); + foreach (i, affixForm; params.affixForms.enumerate) + { + if (i > 0) + writer.put(", "); + writer.write(affixForm); + } + writer.put(">"); +} + private void write(Writer)(Writer writer, AffixForm affixForm) { import gamma.grammar.Nonterminal : Nonterminal; diff --git a/src/gamma/grammar/hyper/Repetition.d b/src/gamma/grammar/hyper/Repetition.d index 5a2483c..23e7631 100755 --- a/src/gamma/grammar/hyper/Repetition.d +++ b/src/gamma/grammar/hyper/Repetition.d @@ -12,9 +12,9 @@ public class Repetition : Operator private Params endParams_; - public this(Params params, Rule rule, Params endParams, Position position) + public this(Rule rule, Params endParams, Position position) { - super(params, rule, position); + super(rule, position); this.endParams_ = endParams; } diff --git a/src/gamma/grammar/hyper/Signature.d b/src/gamma/grammar/hyper/Signature.d deleted file mode 100755 index 3140f8b..0000000 --- a/src/gamma/grammar/hyper/Signature.d +++ /dev/null @@ -1,6 +0,0 @@ -module gamma.grammar.hyper.Signature; - -public class Signature -{ - // TODO -} diff --git a/src/gamma/input/epsilang/parser.d b/src/gamma/input/epsilang/parser.d index 2910839..33149aa 100755 --- a/src/gamma/input/epsilang/parser.d +++ b/src/gamma/input/epsilang/parser.d @@ -5,13 +5,13 @@ import gamma.grammar.affixes.Variable; import gamma.grammar.Alternative; import gamma.grammar.Grammar; import gamma.grammar.GrammarBuilder; +import gamma.grammar.hyper.ActualParams; import gamma.grammar.hyper.Group; -import gamma.grammar.hyper.HyperSymbolNode; +import gamma.grammar.hyper.HyperAlternative; import gamma.grammar.hyper.Operator; import gamma.grammar.hyper.Option; import gamma.grammar.hyper.Params; import gamma.grammar.hyper.Repetition; -import gamma.grammar.hyper.RepetitionAlternative; import gamma.grammar.Node; import gamma.grammar.Nonterminal; import gamma.grammar.Rule; @@ -35,10 +35,6 @@ public class Parser private Position lastPosition; - private Params spareActualParams; - - private Params undecidedActualParams; - private GrammarBuilder metaGrammarBuilder; private GrammarBuilder hyperGrammarBuilder; @@ -65,11 +61,16 @@ public class Parser if (position != this.lastPosition) { - this.lexer.addError(position, message); + markError(position, message); this.lastPosition = position; } } + private void markError(Position position, string message) + { + this.lexer.addError(position, message); + } + /** * Specification: * { WhiteSpaceRule | MetaRule | HyperRule }. @@ -120,7 +121,7 @@ public class Parser else if (this.lexer.front == ':' || this.lexer.front == '<') { auto nonterminal = hyperNonterminal(value); - auto lhs = new HyperSymbolNode(nonterminal, null, position); // TODO: which params? + auto lhs = new SymbolNode(nonterminal, position); if (starred) this.lexicalHyperNonterminals[nonterminal] = true; @@ -220,8 +221,6 @@ public class Parser /** * MetaRule: * ident [ '*' ] '=' MetaExpr '.'. - * - * @param lhs the identifier occurrence for the left-hand side */ private void parseMetaRule(SymbolNode lhs) in (this.lexer.front == '=') @@ -242,9 +241,6 @@ public class Parser /** * MetaExpr: * MetaTerm { '|' MetaTerm }. - * - * @param lhs the identifier occurrence for the left-hand side - * @param position the position for the first alternative */ private void parseMetaExpr(SymbolNode lhs, Position position) { @@ -267,8 +263,6 @@ public class Parser /** * MetaTerm: * { ident | string }. - * - * @return the list of occurrences of identifiers and strings */ private Node[] parseMetaTerm() { @@ -310,32 +304,34 @@ public class Parser /** * HyperRule: * ident [ '*' ] [ FormalParams ] ':' HyperExpr '.'. - * - * @param lhs the identifier occurrence for the left-hand side */ - private void parseHyperRule(HyperSymbolNode lhs) + private void parseHyperRule(SymbolNode lhs) in (this.lexer.front == ':' || this.lexer.front == '<') { - Position position; + Params formalParams; if (this.lexer.front == '<') { with (parseParams(Yes.formalParams)) { - // TODO: rewriting lhs requires cast to Nonterminal - lhs = new HyperSymbolNode(cast(Nonterminal) lhs.symbol, params, lhs.position); + // TODO: check signature + formalParams = params; } } + + Position position; + if (this.lexer.front == ':') { position = this.lexer.position; this.lexer.popFront; - } else + } + else + { markError(`":" expected`); + } - Alternative[] alternatives = parseHyperExpr(lhs, - No.repetition, - position); + Alternative[] alternatives = parseHyperExpr(lhs, formalParams, position); foreach (alternative; alternatives) this.hyperGrammarBuilder.add(alternative); @@ -353,72 +349,39 @@ public class Parser * HyperExpr: * [ FormalParams ] HyperTerm [ ActualParams ] * { '|' [ FormalParams ] HyperTerm [ ActualParams ] }. - * - * @param lhs the identifier occurrence for the left-hand side - * @return the list of alternatives */ - private Alternative[] parseHyperExpr(HyperSymbolNode lhs, - Flag!"repetition" repetition, - Position position) + private Alternative[] parseHyperExpr(SymbolNode lhs, Params lhsParams, Position position) { Alternative[] alternatives; - Params formalParams = null; - for (bool firstRound = true;; firstRound = false) + for (;;) { - auto alternativeLhs = lhs; - Params spareActualParams = null; + Params formalParams = lhsParams; + Node[] rhs; if (this.lexer.front == '<') { + const paramsPosition = this.lexer.position; + with (parseParams) { if (signature !is null) { - if (lhs.params !is null || !firstRound && formalParams is null) - { - this.lexer.addError(params.position, "unexpected formal parameters"); - } + if (lhsParams !is null) + markError(paramsPosition, "unexpected formal parameters"); else - { - // TODO: rewriting lhs requires cast to Nonterminal - alternativeLhs = new HyperSymbolNode(cast(Nonterminal) lhs.symbol, params, lhs.position); + // TODO: check signature formalParams = params; - } } else { - if (formalParams !is null) - this.lexer.addError(params.position, "formal parameters expected"); - else - spareActualParams = params; + rhs ~= new ActualParams(params); } } } - else if (formalParams !is null) - { - markError("formal parameters expected"); - } - - Node[] rhs = parseHyperTerm(spareActualParams); - Alternative alternative; - - if (repetition) - alternative = new RepetitionAlternative(alternativeLhs, rhs, null, position); // TODO: which params? - else - alternative = new Alternative(alternativeLhs, rhs, position); - alternatives ~= alternative; - if (repetition && formalParams !is null) - { - if (this.undecidedActualParams is null && this.spareActualParams is null) - markError("actual parameters expected"); - } - else - { - if (this.spareActualParams !is null) - this.lexer.addError(this.spareActualParams.position, "unexpected actual parameters"); - } + rhs ~= parseHyperTerm; + alternatives ~= new HyperAlternative(lhs, formalParams, rhs, position); assert(this.lexer.empty || this.lexer.front == '|' || this.lexer.front == '.' || this.lexer.front == ')' || this.lexer.front == ']' || this.lexer.front == '}'); @@ -434,66 +397,52 @@ public class Parser /** * HyperTerm: * { ident [ ActualParams ] - * | string - * | [ ActualParams ] ( '(' HyperExpr ')' - * | '[' HyperExpr ']' [ FormalParams ] - * | '{' HyperExpr '}' [ FormalParams ] - * ) - * }. - * - * @return the list of occurrences of identifiers and strings + * | string + * | [ ActualParams ] ( '(' HyperExpr ')' + * | '[' HyperExpr ']' [ FormalParams ] + * | '{' HyperExpr '}' [ FormalParams ] + * ) + * }. */ - private Node[] parseHyperTerm(Params spareActualParams) + private Node[] parseHyperTerm() { Node[] nodes; - Params undecidedActualParams = null; for (;;) { if (this.lexer.front == Token.name || this.lexer.front == Token.string_ || this.lexer.front == '<') { - undecidedActualParams = null; - if (spareActualParams !is null) - { - this.lexer.addError(spareActualParams.position, "unexpected actual parameters"); - spareActualParams = null; - } if (this.lexer.front == Token.name) { auto nonterminal = hyperNonterminal(this.lexer.value); const position = this.lexer.position; - auto node = new HyperSymbolNode(nonterminal, null, position); // TODO: which params? - nodes ~= node; + nodes ~= new SymbolNode(nonterminal, position); this.lexer.popFront; if (this.lexer.front == Token.number) { markError("unexpected number"); this.lexer.popFront; } - if (this.lexer.front == '<') - { - with (parseParams(No.formalParams)) - { - // formal parameters following a nonterminal - // can also belong to the next EBNF expression - undecidedActualParams = params; - } - } } else if (this.lexer.front == Token.string_) { auto terminal = hyperTerminal(this.lexer.value); - auto node = new SymbolNode(terminal, this.lexer.position); + const position = this.lexer.position; - nodes ~= node; + nodes ~= new SymbolNode(terminal, position); this.lexer.popFront; } else if (this.lexer.front == '<') { - with (parseParams(No.formalParams)) + const position = this.lexer.position; + + with (parseParams) { - spareActualParams = params; + if (signature !is null) + markError(position, "unexpected formal parameters"); + else + nodes ~= new ActualParams(params); } } } @@ -505,60 +454,56 @@ public class Parser this.lexer.popFront; Nonterminal identifier = hyperGrammarBuilder.buildAnonymousNonterminal; - auto lhs = new HyperSymbolNode (identifier, null, position); // TODO: which params? - Alternative[] alternatives = parseHyperExpr(lhs, - (open == '{') ? Yes.repetition : No.repetition, - position); + auto lhs = new SymbolNode (identifier, position); + Alternative[] alternatives = parseHyperExpr(lhs, null, position); auto rule = new Rule(alternatives); - Operator operator = null; - assert(this.lexer.empty || this.lexer.front == '|' || this.lexer.front == '.' + assert(this.lexer.empty || this.lexer.front == '.' || this.lexer.front == ')' || this.lexer.front == ']' || this.lexer.front == '}'); - if (open == '(') - { - if (this.lexer.front != ')') - markError(`")" expected`); - operator = new Group(null, rule, position); - } - else if (open == '[') - { - if (this.lexer.front != ']') - markError(`"]" expected`); - operator = new Option(null, rule, null, position); - } - else if (open == '{') - { - if (this.lexer.front != '}') + if (open == '(' && this.lexer.front != ')') + markError(`")" expected`); + else if (open == '[' && this.lexer.front != ']') + markError(`"]" expected`); + else if (open == '{' && this.lexer.front != '}') markError(`"}" expected`); - operator = new Repetition(null, rule, null, position); - } - nodes ~= operator; if (this.lexer.front == ')' || this.lexer.front == ']' || this.lexer.front == '}') - this.lexer.popFront; - if (open != '(' && (cast(HyperSymbolNode) rule.lhs).params !is null) { + Params endParams; + ActualParams actualParams; + + this.lexer.popFront; if (this.lexer.front == '<') { - parseParams(Yes.formalParams); + const paramsPosition = this.lexer.position; + + with (parseParams) + { + if (signature !is null) + { + // TODO: check signature + if (open == '(') + markError(paramsPosition, "unexpected formal parameters"); + endParams = params; + } + else + { + actualParams= new ActualParams(params); + } + } } - else - markError("formal parameters expected"); - } - if ((cast(HyperSymbolNode) rule.lhs).params !is null) - { - // FIXME: also OK for EBNF expression at beginning when LHS has no formal parameter - if (undecidedActualParams is null && spareActualParams is null && false) - this.lexer.addError(position, "actual parameters expected"); - } - else - { - if (spareActualParams !is null) - this.lexer.addError(spareActualParams.position, "unexpected actual parameters"); + + if (open == '(') + nodes ~= new Group(rule, position); + else if (open == '[') + nodes ~= new Option(rule, endParams, position); + else if (open == '{') + nodes ~= new Repetition(rule, endParams, position); + + if (actualParams !is null) + nodes ~= actualParams; } - undecidedActualParams = null; - spareActualParams = null; } else if (this.lexer.empty || this.lexer.front == '|' || this.lexer.front == '.' || this.lexer.front == ')' || this.lexer.front == ']' || this.lexer.front == '}') @@ -579,8 +524,6 @@ public class Parser } } - this.spareActualParams = spareActualParams; - this.undecidedActualParams = undecidedActualParams; return nodes; } @@ -602,9 +545,9 @@ public class Parser import gamma.grammar.affixes.Direction : Direction; import gamma.grammar.affixes.Signature : Signature; - Direction[] directions = null; - Nonterminal[] domains = null; - AffixForm[] affixForms = null; + Direction[] directions; + Nonterminal[] domains; + AffixForm[] affixForms; const position = this.lexer.position; this.lexer.popFront; @@ -689,7 +632,7 @@ public class Parser else markError(`">" expected`); - Signature signature = null; + Signature signature; auto params = new Params(affixForms, position); if (formalParams.get) @@ -707,8 +650,8 @@ public class Parser */ private AffixForm parseAffixForm() { - SymbolNode[] symbolNodes = null; - Variable[] variables = null; + SymbolNode[] symbolNodes; + Variable[] variables; for (;;) {