/// <summary> /// Parses an unary operator expression /// </summary> /// <param name="funcCall">Indicates if the primary is parsed in a function call</param> /// <returns>An expression syntax tree</returns> private ExpressionSyntaxTree ParseUnary(bool funcCall = false) { //If the current token is not an operator, it must be a primary expression CharacterToken charToken = this.currentToken as CharacterToken; if (charToken == null) { return this.ParsePrimary(funcCall); } if (charToken != null && (charToken.Value == '(' || charToken.Value == ')' || charToken.Value == ',')) { return this.ParsePrimary(funcCall); } charToken = this.currentToken as CharacterToken; char op = charToken.Value; this.NextToken(); ExpressionSyntaxTree operand = this.ParseUnary(funcCall); if (operand == null) { return null; } return new UnaryExpressionSyntaxTree(op, operand); }
/// <summary> /// Creates a new for expression syntax tree /// </summary> /// <param name="variableName">The name of the loop variable</param> /// <param name="start">The start value</param> /// <param name="end">The stop value</param> /// <param name="step">The step</param> /// <param name="body">The body</param> public ForExpressionSyntaxTree(string variableName, ExpressionSyntaxTree start, ExpressionSyntaxTree end, ExpressionSyntaxTree step, ExpressionSyntaxTree body) { this.variableName = variableName; this.start = start; this.end = end; this.step = step; this.body = body; }
/// <summary> /// Parses an expression /// </summary> /// <param name="funcCall">Indicates if the primary is parsed in a function call</param> /// <returns>An expression syntax tree</returns> private ExpressionSyntaxTree ParseExpression(bool funcCall = false) { ExpressionSyntaxTree leftHandSide = this.ParseUnary(funcCall); if (leftHandSide == null) { return null; } return this.ParseBinaryOpRHS(0, leftHandSide); }
/// <summary> /// Parses a top level expression /// </summary> /// <returns>An expression syntax tree</returns> private ExpressionSyntaxTree ParseTopLevelExpression() { ExpressionSyntaxTree expression = this.ParseExpression(); if (expression != null) { //Make an anonymous prototype PrototypeSyntaxTree prototype = new PrototypeSyntaxTree("", new List<string>()); return new FunctionSyntaxTree(prototype, expression); } return null; }
/// <summary> /// Parses the right hand side of binary operator expression /// </summary> /// <param name="expressionPrecedence">The expression precedence</param> /// <param name="leftHandSide">The left hand side</param> /// <returns>An expression syntax tree</returns> private ExpressionSyntaxTree ParseBinaryOpRHS(int expressionPrecedence, ExpressionSyntaxTree leftHandSide) { //If this is a binop, find its precedence while (true) { int tokenPrec = this.GetTokenPrecedence(); //If this is a binop that binds at least as tightly as the current binop, //consume it, otherwise we are done. if (tokenPrec < expressionPrecedence) { return leftHandSide; } //Okay, we know this is a binop. CharacterToken opToken = this.currentToken as CharacterToken; this.NextToken(); //Consume the binop //Parse the primary expression after the binary operator. ExpressionSyntaxTree rightHandSide = this.ParseUnary(); if (rightHandSide == null) { return null; } if (rightHandSide == null) { return null; } //If the bin op binds less tightly with RHS than the operator after RHS, let //the pending operator take RHS as its LHS. int nextPrec = this.GetTokenPrecedence(); if (tokenPrec < nextPrec) { rightHandSide = this.ParseBinaryOpRHS(tokenPrec + 1, rightHandSide); if (rightHandSide == null) { return null; } } //Merge the left and right hand side leftHandSide = new BinaryExpressionSyntaxTree(opToken.Value, leftHandSide, rightHandSide); } }
/// <summary> /// Parses a identifier expression /// </summary> /// <returns>An expression syntax tree</returns> private ExpressionSyntaxTree ParseIdentifierExpression() { string identifierName = ((IdentifierToken)this.currentToken).Value; this.NextToken(); //Consume the identifier CharacterToken charToken = this.currentToken as CharacterToken; //Simple variable ref if ((charToken != null && charToken.Value != '(') || charToken == null) { return new VariableExpressionSyntaxTree(identifierName); } //Call this.NextToken(); //Consume the ( List<ExpressionSyntaxTree> args = new List<ExpressionSyntaxTree>(); if (charToken != null && charToken.Value != ')') { while (true) { ExpressionSyntaxTree arg = this.ParseExpression(true); if (arg != null) { args.Add(arg); } charToken = this.currentToken as CharacterToken; if (charToken != null && charToken.Value == ')') { break; } if ((charToken != null && charToken.Value != ',') || charToken == null) { throw new ParserException("Expected ')' or ',' in argument list"); } this.NextToken(); } } this.NextToken(); //Consume the ) return new CallExpressionSyntaxTree(identifierName, args); }
/// <summary> /// Parses an if expression /// </summary> /// <returns>An expression syntax tree</returns> private ExpressionSyntaxTree ParseIfExpression() { this.NextToken(); //Consume the if //Condition ExpressionSyntaxTree cond = this.ParseExpression(); if (cond == null) { return null; } if (this.currentToken.Type != TokenType.Then) { throw new ParserException("expected then"); } this.NextToken(); //Consume the then ExpressionSyntaxTree thenBody = this.ParseExpression(); if (thenBody == null) { return null; } if (this.currentToken.Type != TokenType.Else) { throw new ParserException("expected else"); } this.NextToken(); //Consume the else ExpressionSyntaxTree elseBody = this.ParseExpression(); if (elseBody == null) { return null; } return new IfExpressionSyntaxTree(cond, thenBody, elseBody); }
/// <summary> /// Parses a function definition /// </summary> /// <returns>A function syntax tree</returns> private FunctionSyntaxTree ParseDefinition() { this.NextToken(); //Consume the def PrototypeSyntaxTree prototype = this.ParsePrototype(); if (prototype == null) { return null; } //Parse the body ExpressionSyntaxTree bodyExpression = this.ParseExpression(); if (bodyExpression != null) { return new FunctionSyntaxTree(prototype, bodyExpression); } return null; }
/// <summary> /// Parses a parenthese expression /// </summary> /// <returns>An expression syntax tree</returns> private ExpressionSyntaxTree ParseParentheseExpression() { this.NextToken(); //Consume ( ExpressionSyntaxTree expr = this.ParseExpression(); if (expr == null) { return null; } CharacterToken charToken = this.currentToken as CharacterToken; if ((charToken != null && charToken.Value != ')') ||charToken == null) { Console.WriteLine("expected ')'"); return null; } this.NextToken(); //Consume ) return expr; }
/// <summary> /// Creates a new binary expression syntax tree /// </summary> /// <param name="op">The operator</param> /// <param name="leftHandSide">The left hand side</param> /// <param name="rightHandSide">The right hand side</param> public BinaryExpressionSyntaxTree(char op, ExpressionSyntaxTree leftHandSide, ExpressionSyntaxTree rightHandSide) { this.op = op; this.leftHandSide = leftHandSide; this.rightHandSide = rightHandSide; }
/// <summary> /// Parses a for expression /// </summary> /// <returns>An expression syntax tree</returns> private ExpressionSyntaxTree ParseForExpression() { this.NextToken(); //Consume the for if (this.currentToken.Type != TokenType.Identifier) { throw new ParserException("expected identifier after for"); } string varName = ((IdentifierToken)this.currentToken).Value; this.NextToken(); //Consume the identifier CharacterToken charToken = this.currentToken as CharacterToken; if ((charToken != null && charToken.Value != '=') ||charToken == null) { throw new ParserException("expected '=' after for"); } this.NextToken(); //Consume the '=' ExpressionSyntaxTree startExpression = this.ParseExpression(); if (startExpression == null) { return null; } charToken = this.currentToken as CharacterToken; if ((charToken != null && charToken.Value != ',') ||charToken == null) { throw new ParserException("expected ',' after for start value"); } this.NextToken(); //Consume the ',' ExpressionSyntaxTree endExpression = this.ParseExpression(); if (endExpression == null) { return null; } //The step value is optional ExpressionSyntaxTree stepExpression = null; charToken = this.currentToken as CharacterToken; if ((charToken != null && charToken.Value == ',') ||charToken == null) { this.NextToken(); //Consume the ',' stepExpression = this.ParseExpression(); if (stepExpression == null) { return null; } } if (this.currentToken.Type != TokenType.In) { throw new ParserException("expected 'in' after for"); } this.NextToken(); //Consume the 'in' ExpressionSyntaxTree bodyExpression = this.ParseExpression(); if (bodyExpression == null) { return null; } return new ForExpressionSyntaxTree(varName, startExpression, endExpression, stepExpression, bodyExpression); }
/// <summary> /// Creates a new function syntax tree /// </summary> /// <param name="name">The prototype</param> /// <param name="arguments">The body</param> public FunctionSyntaxTree(PrototypeSyntaxTree prototype, ExpressionSyntaxTree body) { this.prototype = prototype; this.body = body; }
/// <summary> /// Creates a new if expression syntax tree /// </summary> /// <param name="condition">The condition</param> /// <param name="thenBody">The then body</param> /// <param name="elseBody">The else body</param> public IfExpressionSyntaxTree(ExpressionSyntaxTree condition, ExpressionSyntaxTree thenBody, ExpressionSyntaxTree elseBody) { this.condition = condition; this.thenBody = thenBody; this.elseBody = elseBody; }
/// <summary> /// Creates a new unary expression syntax tree /// </summary> /// <param name="op">The operator</param> /// <param name="operand">The operand</param> public UnaryExpressionSyntaxTree(char op, ExpressionSyntaxTree operand) { this.op = op; this.operand = operand; }
/// <summary> /// Creates a new function syntax tree /// </summary> /// <param name="name">The prototype</param> /// <param name="arguments">The body</param> public FunctionSyntaxTree(PrototypeSyntaxTree prototype, ExpressionSyntaxTree body) { this.prototype = prototype; this.body = body; }
/// <summary> /// Creates a new unary expression syntax tree /// </summary> /// <param name="op">The operator</param> /// <param name="operand">The operand</param> public UnaryExpressionSyntaxTree(char op, ExpressionSyntaxTree operand) { this.op = op; this.operand = operand; }
/// <summary> /// Creates a new binary expression syntax tree /// </summary> /// <param name="op">The operator</param> /// <param name="leftHandSide">The left hand side</param> /// <param name="rightHandSide">The right hand side</param> public BinaryExpressionSyntaxTree(char op, ExpressionSyntaxTree leftHandSide, ExpressionSyntaxTree rightHandSide) { this.op = op; this.leftHandSide = leftHandSide; this.rightHandSide = rightHandSide; }
/// <summary> /// Creates a new for expression syntax tree /// </summary> /// <param name="variableName">The name of the loop variable</param> /// <param name="start">The start value</param> /// <param name="end">The stop value</param> /// <param name="step">The step</param> /// <param name="body">The body</param> public ForExpressionSyntaxTree(string variableName, ExpressionSyntaxTree start, ExpressionSyntaxTree end, ExpressionSyntaxTree step, ExpressionSyntaxTree body) { this.variableName = variableName; this.start = start; this.end = end; this.step = step; this.body = body; }
/// <summary> /// Creates a new if expression syntax tree /// </summary> /// <param name="condition">The condition</param> /// <param name="thenBody">The then body</param> /// <param name="elseBody">The else body</param> public IfExpressionSyntaxTree(ExpressionSyntaxTree condition, ExpressionSyntaxTree thenBody, ExpressionSyntaxTree elseBody) { this.condition = condition; this.thenBody = thenBody; this.elseBody = elseBody; }