/// <summary> /// Parses ok, or throws /// </summary> /// <param name="terminatingCharacter"> /// Stops parsing if it sees this CodePoint in an unnested context. /// </param> /// <returns> /// AbstractSyntaxTree representing parse, or throws /// </returns> public AbstractSyntaxTree Parse(CodePoint terminatingCharacter) { _operatorStack.Clear(); _operatorStack.Push(Operator.None); // make Peek () safe to do without first checking if empty _operandStack.Clear(); return(ParseToResult(terminatingCharacter)); }
private void ReadIntoNext() { if (!_next.AtEOF()) { _nextCursor++; _next = _cps.Read(); } }
private AbstractSyntaxTree ParseToResult(CodePoint terminatingCharacter) { ParseExpressionToStack(terminatingCharacter); while (_operatorStack.Peek() != Operator.None) { ReduceTopOperator(); } if (_operandStack.Count != 1) { throw new AssertionFailedException("operand stack should have only 1 operand"); } return(_operandStack.Pop()); }
/// <summary> /// Attempts to parse. Does not throw on error. /// </summary> /// <param name="terminatingCharacter"> /// Stops parsing if it sees this CodePoint in an unnested context. /// </param> /// <returns> /// Either the result or a list of errors /// (Could/should return list of warnings with results as well.) /// </returns> public ResultOrErrorList <AbstractSyntaxTree> TryParse(CodePoint terminatingCharacter) { _operatorStack.Clear(); _operatorStack.Push(Operator.None); // make Peek () safe to do without first checking if empty _operandStack.Clear(); try { return(new ResultOrErrorList <AbstractSyntaxTree> (ParseToResult(terminatingCharacter))); } catch (Exceptions.CompilationException p) { return(new ResultOrErrorList <AbstractSyntaxTree> (new List <Exceptions.CompilationException> () { p })); } }
public void Advance() { if (!_curr.AtEOF( )) { _cursor = _nextCursor; _curr = _next; _currLineMark = _nextLineMark; ReadIntoNext( ); switch (_curr.Value) { case '\r': _curr = new CodePoint(( byte )'\n'); if (_next.Value == '\n') { ReadIntoNext( ); } goto case '\n'; case '\n': _line++; _nextLineMark = _nextCursor; _indentationLevel = 0; _nonBlankSeen = false; HandlePPDirectivesFromNormalMode( ); break; case ' ': _indentationLevel++; break; case '\t': if ((_indentationLevel & 7) != 0) { throw new CompilationException("tab after space is illegal for indentation"); } _indentationLevel += 8; // tab level break; default: _nonBlankSeen = true; break; } } }
private readonly CodePoint [] _idMores = { new CodePoint((byte)'_'), new CodePoint((byte)'.') }; //, new CodePoint ( (byte) '-' ) }; public ScanIt(CodePointStream cps, string job, System.IO.TextWriter lg) { _defdDict = new HashSet <ByteString> { new ByteString("true"), new ByteString("1") }; _cps = cps; _job = job; _lg = lg; _line = 0; _currTokenCursorStart = _cursor = _currLineMark = -2; _nextCursor = _nextLineMark = -1; _indentationLevel = 0; _tokenModeStack = new Stack <TokenModeEnum> (); PushMode(TokenModeEnum.Illegal); PushMode(TokenModeEnum.Normal); _curr = new CodePoint((byte)' '); _next = new CodePoint((byte)'\n'); Advance(); Advance(); }
private void ParseExpressionToStack(CodePoint terminatingCharacter) { for ( ; ;) // Alternate between the States { // initial State: Unary State for ( ; ;) // Unary State { var token = _scanner.Token(); switch (token.Value) { case '(': _scanner.Advance(); _operatorStack.Push(Operator .PrecedenceGroupingParenthesis); // nothing to reduce, as '(' has highest precedence continue; case ')': _scanner.Advance(); if (_operatorStack.Peek() != Operator.FunctionCall) { _scanner.ErrorAtMark("unexpected ) in unary state"); } _operatorStack.Pop(); // NB: We have a function call with no argument list, and we can either: // provide a unary function call operator // but our automated operator generators don't have that concept, or, // push an empty operand onto the stack so there's two operands for it to work _operandStack.Push(null); BuildAndPushOperator(Operator.FunctionCall); break; case '!': _scanner.Advance(); _operatorStack.Push(Operator.LogicalNot); // prefix unary operators have implicit highest precedence continue; case '&': _scanner.Advance(); _operatorStack.Push(Operator.AddressOf); continue; case '*': _scanner.Advance(); _operatorStack.Push(Operator.Indirection); continue; case '+': _scanner.Advance(); ReduceAndPushByChoice('+', Operator.PrefixIncrement, Operator.FixPoint); continue; case '-': _scanner.Advance(); ReduceAndPushByChoice('-', Operator.PrefixDecrement, Operator.Negation); continue; case '~': _scanner.Advance(); _operatorStack.Push(Operator.BitwiseComplement); continue; case 'A': var id = _scanner.GetIdentifier(); // we can look up the variable in a symbol table here _operandStack.Push(_symbolTable.LookupSymbol(id)); break; case '0': var num = _scanner.GetNonNegativeIntegralLiteral(); _operandStack.Push(new LongIntegerTreeNode(num)); break; case '\"': var str = _scanner.GetStringLiteral(); _operandStack.Push(new StringTreeNode(str)); break; case '\'': var chStr = _scanner.GetStringLiteral(); var cps = new CodePointStream(chStr); var cp1 = cps.Read(); if (cp1.AtEOF()) { _scanner.ErrorAtMark("not enough characters in character literal"); } var cp2 = cps.Read(); if (!cp2.AtEOF()) { _scanner.ErrorAtMark("too many characters in character literal"); } _operandStack.Push(new LongIntegerTreeNode(cp1.Value)); break; default: _scanner.ErrorAtMark("unrecognized token: " + (char)token.Value); return; } break; // switch to Binary State } // for (;;) { end of Unary State for ( ; ;) // Binary State { var cp = _scanner.Token(); if (cp.AtEOF() || cp == terminatingCharacter && AtTopLevelAndUnblocked()) { return; } switch (cp.Value) { case '(': _scanner.Advance(); ReduceThenPushOperator(Operator.FunctionCall); break; case ',': _scanner.Advance(); AcceptComma(); break; case ')': _scanner.Advance(); AcceptCloseParen(); continue; // stay in Binary State case '[': _scanner.Advance(); ReduceThenPushOperator(Operator.Subscript); break; case ']': _scanner.Advance(); // we have a [ b ], so we reduce until we reach the '[' ReduceUntilMatch(Operator.Subscript); // reduction pops the operator, and, leaves us with a & b on the operand stack BuildAndPushOperator(Operator.Subscript); continue; // stay in Binary State case '!': _scanner.Advance(); if (!_scanner.IfCharacter('=')) { _scanner.ErrorAtMark("expected = for !="); } ReduceThenPushOperator(Operator.NotEqual); break; case '*': _scanner.Advance(); ReduceAndPushByChoice('=', Operator.AssignmentMultiplication, Operator.Multiplication); break; case '/': _scanner.Advance(); ReduceAndPushByChoice('=', Operator.AssignmentDivision, Operator.Division); break; case '%': _scanner.Advance(); ReduceAndPushByChoice('=', Operator.AssignmentModulo, Operator.Modulo); break; case '=': _scanner.Advance(); ReduceAndPushByChoice('=', Operator.EqualEqual, Operator.Assignment); break; case '^': _scanner.Advance(); ReduceAndPushByChoice('=', Operator.AssignmentBitwiseXor, Operator.BitwiseXor); break; case '+': _scanner.Advance(); if (_scanner.IfCharacter('+')) { // C/C++ postfix ++ ReduceThenPushOperator(Operator.PostfixIncrement); continue; // stay in Binary State } ReduceAndPushByChoice('=', Operator.AssignmentAddition, Operator.Addition); break; case '-': _scanner.Advance(); if (_scanner.IfCharacter('>')) { // at least -> if (_scanner.IfCharacter('*')) { // C++: member pointer: ->* // ToDo: parse rhs of ->* (which is a member name) and generate an binary node to push on the operand stack throw new System.NotImplementedException("->*"); } else { // C/C++ indirect selection: -> var memberName = _scanner.ExpectIdentifier("member identifier"); // ToDo: parse rhs of -> (which is a member name) and generate an operand to push on throw new System.NotImplementedException("->"); } } else { ReduceAndPushByChoice('-', Operator.PostfixDecrement, '=', Operator.AssignmentSubtraction, Operator.Subtraction); } break; case '&': _scanner.Advance(); ReduceAndPushByChoice('&', Operator.ShortCircutAnd, '=', Operator.AssignmentBitwiseAnd, Operator.BitwiseAnd); break; case '|': _scanner.Advance(); ReduceAndPushByChoice('|', Operator.ShortCircutOr, '=', Operator.AssignmentBitwiseOr, Operator.BitwiseOr); break; case '.': throw new System.NotImplementedException(". operator"); case '?': _scanner.Advance(); // Operator.TernaryTest is used for grouping of the expressions during parsing, // This operator won't appear in the final tree (similar to Operator.GroupingParen which doesn't appear in the abstract tree either) ReduceThenPushOperator(Operator.TernaryTest); // Test 1003: a?b,c:d, which should parse ok as: //// a?(b,c):d //// -and not- //// (a?b),(c:d) //// as this makes no sense and thus is not helpful break; case ':': _scanner.Advance(); if (_scanner.IfCharacter(':')) { throw new System.NotImplementedException(":: operator"); } else { ReduceUntilMatch(Operator.TernaryTest); // this will leave two operands on the stack, so for // a ? b : -- which is what we have so far // a and b will be on the operand stack. // now we push the true ternary operator: _operatorStack.Push(Operator.TernaryChoice); // when it gets reduced later, so for // a ? b : c; // reducing this operator will consume a, b, and c. } break; case '<': _scanner.Advance(); ReduceAndPushByChoice('<', '=', Operator.AssignmentBitwiseLeftShift, Operator.BitwiseLeftShift, '=', Operator.LessOrEqual, Operator.LessThan); break; case '>': _scanner.Advance(); ReduceAndPushByChoice('>', '=', Operator.AssignmentBitwiseRightShift, Operator.BitwiseRightShift, '=', Operator.GreaterOrEqual, Operator.GreaterThan); break; default: return; // let caller deal with the "unexpected" input, like ; } break; // switch to Unary State } // end of for (;;) { Binary State } // end of for(;;) { Alternating between the states }