1 using System;
2 using System.Collections;
3
4
5
6
7
8 namespace soulcm.scmpg
9 {
10 public class LinkerVisitor : Visitor
11 {
12 public LinkerVisitor() :
13 domain(null), currentParser(null), currentRule(null), stage(Stage.addParsers)
14 {
15 }
16 public enum Stage
17 {
18 addParsers, resolveRules
19 }
20 public override void Visit(OptionalParser& parser)
21 {
22 parser.Child()->Accept(*this);
23 }
24 public override void Visit(KleeneParser& parser)
25 {
26 parser.Child()->Accept(*this);
27 }
28 public override void Visit(PositiveParser& parser)
29 {
30 parser.Child()->Accept(*this);
31 }
32 public override void Visit(ExpectationParser& parser)
33 {
34 parser.Child()->Accept(*this);
35 }
36 public override void Visit(GroupingParser& parser)
37 {
38 parser.Child()->Accept(*this);
39 }
40 public override void Visit(SequenceParser& parser)
41 {
42 parser.Left()->Accept(*this);
43 parser.Right()->Accept(*this);
44 }
45 public override void Visit(AlternativeParser& parser)
46 {
47 parser.Left()->Accept(*this);
48 parser.Right()->Accept(*this);
49 }
50 public override void Visit(DifferenceParser& parser)
51 {
52 parser.Left()->Accept(*this);
53 parser.Right()->Accept(*this);
54 }
55 public override void Visit(ListParser& parser)
56 {
57 parser.Child()->Accept(*this);
58 }
59 public override void Visit(ActionParser& parser)
60 {
61 parser.Child()->Accept(*this);
62 }
63 public override void Visit(NonterminalParser& parser)
64 {
65 currentRule->AddNonterminal(&parser);
66 RuleParser* rule = currentParser->GetRule(parser.RuleName());
67 parser.SetRule(rule);
68 if (rule->Parameters().Count() != parser.Args().Count())
69 {
70 throw Exception("Rule \'" + ToUtf8(rule->Name()) + "\' takes " + ToString(rule->Parameters().Count()) + " parameters (" + ToString(parser.Args().Count()) + " arguments supplied). Detected in parser \'" + ToUtf8(currentParser->Name()) + "\' rule \'" + ToUtf8(currentRule->Name()) + "\'.");
71 }
72 }
73 public override void Visit(RuleParser& parser)
74 {
75 currentRule = &parser;
76 parser.Definition()->Accept(*this);
77 if (stage == Stage.resolveRules)
78 {
79 domain->AddRule(&parser);
80 }
81 }
82 public override void Visit(GrammarParser& parser)
83 {
84 if (stage == Stage.addParsers)
85 {
86 domain->AddParser(&parser);
87 }
88 else if (stage == Stage.resolveRules)
89 {
90 currentParser = &parser;
91 for (const ustring& u : parser.Usings())
92 {
93 List<ustring> components = u.Split('.');
94 if (components.Count() != 2)
95 {
96 throw Exception("invalid using \'" + ToUtf8(u) + "\' in parser \'" + ToUtf8(parser.Name()) + "\'");
97 }
98 const ustring& parserName = components[0];
99 const ustring& ruleName = components[1];
100 GrammarParser* targetParser = domain->GetParser(parserName);
101 RuleParser* rule = targetParser->GetRule(ruleName);
102 parser.MapRule(rule);
103 }
104 for (const UniquePtr<RuleParser>& rule : parser.Rules())
105 {
106 rule->Accept(*this);
107 }
108 for (const Pair<ustring, ustring>& ruleInfo : parser.RuleInfos())
109 {
110 RuleParser* rule = parser.GetRule(ruleInfo.first);
111 rule->SetInfo(ruleInfo.second);
112 }
113 }
114 }
115 public override void Visit(ParserFile& parserFile)
116 {
117 for (const UniquePtr<GrammarParser>& parser : parserFile.Parsers())
118 {
119 parser->Accept(*this);
120 }
121 }
122 public override void Visit(Domain& domain)
123 {
124 this->domain = &domain;
125 stage = Stage.addParsers;
126 for (ParserFile* parserFile : domain.ParserFiles())
127 {
128 parserFile->Accept(*this);
129 }
130 stage = Stage.resolveRules;
131 for (ParserFile* parserFile : domain.ParserFiles())
132 {
133 parserFile->Accept(*this);
134 }
135 }
136 private Domain* domain;
137 private Stage stage;
138 private GrammarParser* currentParser;
139 private RuleParser* currentRule;
140 }
141 }