14 using System.Collections.Generic;
16 using System.Collections;
17 using System.Diagnostics;
29 Data = parser.Language.ParserData;
30 _grammar = Data.Language.Grammar;
34 #region Properties and fields: Parser, Data, _grammar
41 get {
return Parser.Context; }
45 internal void Reset() {
51 Context.Status = ParserStatus.Parsing;
60 private void ReadInput() {
61 if (Context.ParserInputStack.Count > 0)
62 Context.ParserInputStack.Pop();
63 if (Context.ParserInputStack.Count > 0) {
64 Context.CurrentParserInput = Context.ParserInputStack.Top;
70 private void FetchToken() {
74 token = Parser.Scanner.GetToken();
75 }
while (token.Terminal.FlagIsSet(
TermFlags.IsNonGrammar) && token.Terminal != _grammar.Eof);
76 if (token.Terminal.FlagIsSet(
TermFlags.IsBrace))
77 token = CheckBraceToken(token);
78 Context.CurrentParserInput =
new ParseTreeNode(token);
79 Context.ParserInputStack.Push(Context.CurrentParserInput);
83 #region execute actions
84 private void ExecuteAction() {
85 _traceEnabled = Context.OptionIsSet(ParseOptions.TraceParser);
88 if (Context.CurrentParserInput == null && Context.CurrentParserState.DefaultAction == null)
91 if (Context.CurrentParserInput != null && Context.CurrentParserInput.IsError) {
96 var action = FindActionForStateAndInput();
98 if (CheckPartialInputCompleted())
100 ProcessParserError();
104 if (_traceEnabled) Context.AddTrace(
"{0}", action);
106 switch (action.ActionType) {
107 case ParserActionType.Shift: ExecuteShift(action);
break;
108 case ParserActionType.Operator: ExecuteOperatorAction(action);
break;
109 case ParserActionType.Reduce: ExecuteReduce(action);
break;
110 case ParserActionType.Code: ExecuteConflictAction(action);
break;
111 case ParserActionType.Accept: ExecuteAccept(action);
break;
115 private bool CheckPartialInputCompleted() {
116 bool partialCompleted = (Context.Mode == ParseMode.CommandLine && Context.CurrentParserInput.Term == _grammar.Eof);
117 if (!partialCompleted)
return false;
118 Context.Status = ParserStatus.AcceptedPartial;
120 Context.CurrentParserInput = null;
121 Context.ParserInputStack.Pop();
126 private ParserAction FindActionForStateAndInput() {
127 if (Context.CurrentParserState.DefaultAction != null)
128 return Context.CurrentParserState.DefaultAction;
132 Token inputToken = Context.CurrentParserInput.Token;
133 if (inputToken != null && inputToken.KeyTerm != null) {
134 var keyTerm = inputToken.KeyTerm;
135 if (Context.CurrentParserState.Actions.TryGetValue(keyTerm, out action)) {
148 inputToken.SetTerminal(keyTerm);
149 Context.CurrentParserInput.Term = keyTerm;
150 Context.CurrentParserInput.Precedence = keyTerm.Precedence;
156 if (Context.CurrentParserState.Actions.TryGetValue(Context.CurrentParserInput.Term, out action))
159 if(Context.CurrentParserInput.Term == _grammar.Eof && _grammar.FlagIsSet(
LanguageFlags.NewLineBeforeEOF) &&
160 Context.CurrentParserState.Actions.TryGetValue(_grammar.NewLine, out action)) {
161 InjectNewLineToken();
167 private void InjectNewLineToken() {
168 var newLineToken =
new Token(_grammar.NewLine, Context.CurrentParserInput.Token.Location,
"\r\n", null);
169 var newLineNode =
new ParseTreeNode(newLineToken);
170 Context.ParserInputStack.Push(newLineNode);
171 Context.CurrentParserInput = newLineNode;
175 private void ExecuteShift(ParserAction action) {
176 Context.ParserStack.Push(Context.CurrentParserInput, action.NewState);
177 Context.CurrentParserState = action.NewState;
178 Context.CurrentParserInput = null;
179 if (action.NewState.DefaultAction == null)
183 #region ExecuteReduce
184 private void ExecuteReduce(ParserAction action) {
185 var reduceProduction = action.ReduceProduction;
186 ParseTreeNode newNode;
188 newNode = ReduceExistingList(action);
189 else if(reduceProduction.LValue.FlagIsSet(
TermFlags.IsListContainer))
190 newNode = ReduceListContainer(action);
191 else if (reduceProduction.LValue.FlagIsSet(
TermFlags.IsTransient))
192 newNode = ReduceTransientNonTerminal(action);
194 newNode = ReduceRegularNode(action);
196 Context.ParserStack.Pop(reduceProduction.RValues.Count);
199 Context.CurrentParserState = Context.ParserStack.Top.State;
202 var shift = Context.CurrentParserState.Actions[reduceProduction.LValue];
203 Context.ParserStack.Push(newNode, shift.NewState);
204 Context.CurrentParserState = shift.NewState;
207 private ParseTreeNode ReduceExistingList(ParserAction action) {
208 int childCount = action.ReduceProduction.RValues.Count;
209 int firstChildIndex = Context.ParserStack.Count - childCount;
210 var listNode = Context.ParserStack[firstChildIndex];
211 listNode.Span = ComputeNewNodeSpan(childCount);
212 var listMember = Context.ParserStack.Top;
213 if (ShouldSkipChildNode(listMember))
215 CheckCreateAstNode(listMember);
216 listNode.ChildNodes.Add(listMember);
220 private bool ShouldSkipChildNode(ParseTreeNode childNode) {
221 if (childNode.Term.FlagIsSet(
TermFlags.IsPunctuation))
223 if (childNode.Term.FlagIsSet(
TermFlags.IsTransient) && childNode.ChildNodes.Count == 0)
231 private ParseTreeNode ReduceListContainer(ParserAction action) {
232 int childCount = action.ReduceProduction.RValues.Count;
233 int firstChildIndex = Context.ParserStack.Count - childCount;
234 var span = ComputeNewNodeSpan(childCount);
235 var newNode =
new ParseTreeNode(action.ReduceProduction, span);
237 var listNode = Context.ParserStack[firstChildIndex];
238 newNode.ChildNodes.AddRange(listNode.ChildNodes);
243 private ParseTreeNode ReduceTransientNonTerminal(ParserAction action) {
244 var topIndex = Context.ParserStack.Count - 1;
245 var childCount = action.ReduceProduction.RValues.Count;
246 for(
int i = 0; i < childCount; i++) {
247 var child = Context.ParserStack[topIndex - i];
248 if (ShouldSkipChildNode(child))
continue;
249 CheckCreateAstNode(child);
253 var span = ComputeNewNodeSpan(childCount);
254 return new ParseTreeNode(action.ReduceProduction, span);
257 private ParseTreeNode ReduceRegularNode(ParserAction action) {
258 var childCount = action.ReduceProduction.RValues.Count;
259 int firstChildIndex = Context.ParserStack.Count - childCount;
260 var span = ComputeNewNodeSpan(childCount);
261 var newNode =
new ParseTreeNode(action.ReduceProduction, span);
262 for(
int i = 0; i < childCount; i++) {
263 var childNode = Context.ParserStack[firstChildIndex + i];
264 if(ShouldSkipChildNode(childNode))
266 CheckCreateAstNode(childNode);
269 if(childCount == 1 && childNode.Precedence != BnfTerm.NoPrecedence) {
270 newNode.Precedence = childNode.Precedence;
273 newNode.ChildNodes.Add(childNode);
278 private SourceSpan ComputeNewNodeSpan(
int childCount) {
280 return new SourceSpan(Context.CurrentParserInput.Span.Location, 0);
281 var first = Context.ParserStack[Context.ParserStack.Count - childCount];
282 var last = Context.ParserStack.Top;
283 return new SourceSpan(first.Span.Location, last.Span.EndPosition - first.Span.Location.Position);
286 private void CheckCreateAstNode(ParseTreeNode parseNode) {
290 if (parseNode.AstNode != null || parseNode.Term.FlagIsSet(
TermFlags.IsTransient |
TermFlags.NoAstNode))
return;
294 _grammar.CreateAstNode(Context, parseNode);
295 if (parseNode.AstNode != null)
296 parseNode.Term.OnAstNodeCreated(parseNode);
303 private void ExecuteConflictAction(ParserAction action) {
304 var args = action.ResolveConflict(_grammar, Context);
305 switch(args.Result) {
306 case ParserActionType.Reduce:
307 ExecuteReduce(
new ParserAction(
ParserActionType.Reduce, null, args.ReduceProduction));
309 case ParserActionType.Operator:
310 ExecuteOperatorAction(
new ParserAction(
ParserActionType.Operator, action.NewState, args.ReduceProduction));
312 case ParserActionType.Shift:
314 ExecuteShift(action);
320 private void ExecuteAccept(ParserAction action) {
321 var root = Context.ParserStack.Pop();
322 CheckCreateAstNode(root);
323 Context.CurrentParseTree.Root = root;
324 Context.Status = ParserStatus.Accepted;
327 private void ExecuteOperatorAction(ParserAction action) {
328 var realActionType = GetActionTypeForOperation(action);
330 switch (realActionType) {
331 case ParserActionType.Shift: ExecuteShift(action);
break;
332 case ParserActionType.Reduce: ExecuteReduce(action);
break;
337 for (
int i = Context.ParserStack.Count - 1; i >= 0; i--) {
338 var prevNode = Context.ParserStack[i];
339 if (prevNode == null)
continue;
340 if (prevNode.Precedence == BnfTerm.NoPrecedence)
continue;
343 var input = Context.CurrentParserInput;
344 if (prevNode.Precedence == input.Precedence)
345 result = input.Associativity == Associativity.Left ? ParserActionType.Reduce : ParserActionType.Shift;
347 result = prevNode.Precedence > input.Precedence ? ParserActionType.Reduce : ParserActionType.Shift;
351 return ParserActionType.Shift;
355 #region Braces handling
356 private Token CheckBraceToken(Token token) {
357 if (token.Terminal.FlagIsSet(
TermFlags.IsOpenBrace)) {
358 Context.OpenBraces.Push(token);
362 if (Context.OpenBraces.Count == 0)
363 return CreateBraceMismatchErrorToken(token);
365 var lastBrace = Context.OpenBraces.Peek();
366 if (lastBrace.Terminal.IsPairFor != token.Terminal)
367 return CreateBraceMismatchErrorToken(token);
369 Token.LinkMatchingBraces(lastBrace, token);
370 Context.OpenBraces.Pop();
374 private Token CreateBraceMismatchErrorToken(Token closingBrace) {
375 return new Token(_grammar.SyntaxError, closingBrace.Location, closingBrace.Text,
376 string.Format(Resources.ErrUnmatchedCloseBrace, closingBrace.Text));
static string MsgTracePoppedState
Looks up a localized string similar to Popped state from stack, pushing {0}.
CoreParser(Parser parser)
static string ErrFailedCreateNode
Looks up a localized string similar to Failed to create AST node for non-terminal [{0}]...
static string MsgTraceConflictResolved
Looks up a localized string similar to Parsing conflict resolved in code..
SiliconStudio.Shaders.Ast.SourceSpan SourceSpan
static string MsgTraceOpResolved
Looks up a localized string similar to Operator - resolved to {0}.