Skip to content

Commit

Permalink
Merge pull request #88 from b3b00/feature/#87-postfix-operators
Browse files Browse the repository at this point in the history
feature/#87-postfix-operators
  • Loading branch information
b3b00 authored Oct 26, 2018
2 parents e2aae7c + 497ee9d commit cf4cffa
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 56 deletions.
12 changes: 11 additions & 1 deletion ParserTests/ExpressionGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void TestBuild()
Assert.Contains("TIMES", nt.Name);
Assert.Contains("DIVIDE", nt.Name);
nt = nonterminals[4];
Assert.Equal(2, nt.Rules.Count);
Assert.Equal(3, nt.Rules.Count);
Assert.Contains("100", nt.Name);
Assert.Contains("MINUS", nt.Name);
nt = nonterminals[5];
Expand Down Expand Up @@ -131,6 +131,16 @@ public void TestUnaryPrecedence()
Assert.False(r.IsError);
Assert.Equal(-2, r.Result);
}

[Fact]
public void TestPostFix()
{
BuildParser();
ParseResult<ExpressionToken, int> r = Parser.Result.Parse("10!", StartingRule);
Assert.False(r.IsError);
Assert.Equal(3628800, r.Result);
}



[Fact]
Expand Down
23 changes: 17 additions & 6 deletions samples/SimpleExpressionParser/SimpleExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public class SimpleExpressionParser
{


[Operation((int)ExpressionToken.PLUS, 2, Associativity.Right, 10)]
[Operation((int)ExpressionToken.MINUS, 2, Associativity.Left, 10)]
[Operation((int)ExpressionToken.PLUS, Affix.InFix, Associativity.Right, 10)]
[Operation((int)ExpressionToken.MINUS, Affix.InFix, Associativity.Left, 10)]
public int binaryTermExpression(int left, Token<ExpressionToken> operation, int right)
{
int result = 0;
Expand All @@ -33,8 +33,8 @@ public int binaryTermExpression(int left, Token<ExpressionToken> operation, int
}


[Operation((int)ExpressionToken.TIMES, 2, Associativity.Right, 50)]
[Operation((int)ExpressionToken.DIVIDE, 2, Associativity.Left, 50)]
[Operation((int)ExpressionToken.TIMES, Affix.InFix, Associativity.Right, 50)]
[Operation((int)ExpressionToken.DIVIDE, Affix.InFix, Associativity.Left, 50)]
public int binaryFactorExpression(int left, Token<ExpressionToken> operation, int right)
{
int result = 0;
Expand All @@ -55,11 +55,22 @@ public int binaryFactorExpression(int left, Token<ExpressionToken> operation, in
}


[Operation((int)ExpressionToken.MINUS, 1, Associativity.Right, 100)]
public int unaryExpression(Token<ExpressionToken> operation, int value)
[Operation((int)ExpressionToken.MINUS, Affix.PreFix, Associativity.Right, 100)]
public int preFixExpression(Token<ExpressionToken> operation, int value)
{
return -value;
}

[Operation((int)ExpressionToken.FACTORIAL, Affix.PostFix, Associativity.Right, 100)]
public int postFixExpression( int value, Token<ExpressionToken> operation)
{
int factorial = 1;
for (int i = 1; i <= value; i++)
{
factorial = factorial * i;
}
return factorial;
}

[Operand]
[Production("operand : primary_value")]
Expand Down
14 changes: 9 additions & 5 deletions samples/SimpleExpressionParser/SimpleExpressionToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,30 @@ public enum SimpleExpressionToken
// the + operator
[Lexeme(GenericToken.SugarToken,"+")]
PLUS = 5,

// the ++ operator
[Lexeme(GenericToken.SugarToken,"++")]
INCREMENT = 6,

// the - operator
[Lexeme(GenericToken.SugarToken,"-")]
MINUS = 6,
MINUS = 7,

// the * operator
[Lexeme(GenericToken.SugarToken,"*")]
TIMES = 7,
TIMES = 8,

// the / operator
[Lexeme(GenericToken.SugarToken,"/")]
DIVIDE = 8,
DIVIDE = 9,

// a left paranthesis (
[Lexeme(GenericToken.SugarToken,"(")]
LPAREN = 9,
LPAREN = 10,

// a right paranthesis )
[Lexeme(GenericToken.SugarToken,")")]
RPAREN = 10,
RPAREN = 11,

}
}
4 changes: 4 additions & 0 deletions samples/expressionParser/ExpressionToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ public enum ExpressionToken
// a right paranthesis )
[Lexeme("\\)")]
RPAREN = 10,

[Lexeme("!")]
FACTORIAL = 13,


// a whitespace
[Lexeme("[ \\t]+",true)]
Expand Down
26 changes: 13 additions & 13 deletions samples/while/parser/WhileParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ public WhileAST Operand(WhileAST prim)
#endregion

#region NUMERIC OPERATIONS
[Operation((int)WhileToken.PLUS, 2, Associativity.Right, 10)]
[Operation((int)WhileToken.MINUS, 2, Associativity.Right, 10)]
[Operation((int)WhileToken.PLUS, Affix.InFix, Associativity.Right, 10)]
[Operation((int)WhileToken.MINUS, Affix.InFix, Associativity.Right, 10)]
public WhileAST binaryTermNumericExpression(WhileAST left, Token<WhileToken> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.ADD;
Expand All @@ -148,8 +148,8 @@ public WhileAST binaryTermNumericExpression(WhileAST left, Token<WhileToken> ope
return operation;
}

[Operation((int)WhileToken.TIMES, 2, Associativity.Right, 50)]
[Operation((int)WhileToken.DIVIDE, 2, Associativity.Right, 50)]
[Operation((int)WhileToken.TIMES, Affix.InFix, Associativity.Right, 50)]
[Operation((int)WhileToken.DIVIDE, Affix.InFix, Associativity.Right, 50)]
public WhileAST binaryFactorNumericExpression(WhileAST left, Token<WhileToken> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.MULTIPLY;
Expand All @@ -175,7 +175,7 @@ public WhileAST binaryFactorNumericExpression(WhileAST left, Token<WhileToken> o
return operation;
}

[Operation((int)WhileToken.MINUS, 1, Associativity.Right, 100)]
[Operation((int)WhileToken.MINUS, Affix.PreFix, Associativity.Right, 100)]
public WhileAST unaryNumericExpression(Token<WhileToken> operation, WhileAST value)
{
return new Neg(value as Expression);
Expand All @@ -188,7 +188,7 @@ public WhileAST unaryNumericExpression(Token<WhileToken> operation, WhileAST val

#region BOOLEAN OPERATIONS

[Operation((int)WhileToken.OR, 2, Associativity.Right, 10)]
[Operation((int)WhileToken.OR, Affix.InFix, Associativity.Right, 10)]
public WhileAST binaryOrExpression(WhileAST left, Token<WhileToken> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.OR;
Expand All @@ -198,7 +198,7 @@ public WhileAST binaryOrExpression(WhileAST left, Token<WhileToken> operatorToke
return operation;
}

[Operation((int)WhileToken.AND, 2, Associativity.Right, 50)]
[Operation((int)WhileToken.AND, Affix.InFix, Associativity.Right, 50)]
public WhileAST binaryAndExpression(WhileAST left, Token<WhileToken> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.AND;
Expand All @@ -208,7 +208,7 @@ public WhileAST binaryAndExpression(WhileAST left, Token<WhileToken> operatorTok
return operation;
}

[Operation((int)WhileToken.NOT, 1, Associativity.Right, 100)]
[Operation((int)WhileToken.NOT, Affix.PreFix, Associativity.Right, 100)]
public WhileAST binaryOrExpression(Token<WhileToken> operatorToken, WhileAST value)
{

Expand All @@ -218,10 +218,10 @@ public WhileAST binaryOrExpression(Token<WhileToken> operatorToken, WhileAST val

#region COMPARISON OPERATIONS

[Operation((int)WhileToken.LESSER, 2, Associativity.Right, 50)]
[Operation((int)WhileToken.GREATER, 2, Associativity.Right, 50)]
[Operation((int)WhileToken.EQUALS, 2, Associativity.Right, 50)]
[Operation((int)WhileToken.DIFFERENT, 2, Associativity.Right, 50)]
[Operation((int)WhileToken.LESSER, Affix.InFix, Associativity.Right, 50)]
[Operation((int)WhileToken.GREATER, Affix.InFix, Associativity.Right, 50)]
[Operation((int)WhileToken.EQUALS, Affix.InFix, Associativity.Right, 50)]
[Operation((int)WhileToken.DIFFERENT, Affix.InFix, Associativity.Right, 50)]
public WhileAST binaryComparisonExpression(WhileAST left, Token<WhileToken> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.ADD;
Expand Down Expand Up @@ -262,7 +262,7 @@ public WhileAST binaryComparisonExpression(WhileAST left, Token<WhileToken> oper

#region STRING OPERATIONS

[Operation((int)WhileToken.CONCAT, 2, Associativity.Right, 10)]
[Operation((int)WhileToken.CONCAT, Affix.InFix, Associativity.Right, 10)]
public WhileAST binaryStringExpression(WhileAST left, Token<WhileToken> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.CONCAT;
Expand Down
26 changes: 13 additions & 13 deletions samples/while/parser/WhileParserGeneric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ public WhileAST Operand(WhileAST prim)
#endregion

#region NUMERIC OPERATIONS
[Operation((int)WhileTokenGeneric.PLUS, 2, Associativity.Right, 10)]
[Operation((int)WhileTokenGeneric.MINUS, 2, Associativity.Right, 10)]
[Operation((int)WhileTokenGeneric.PLUS, Affix.InFix, Associativity.Right, 10)]
[Operation((int)WhileTokenGeneric.MINUS, Affix.InFix, Associativity.Right, 10)]
public WhileAST binaryTermNumericExpression(WhileAST left, Token<WhileTokenGeneric> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.ADD;
Expand All @@ -141,8 +141,8 @@ public WhileAST binaryTermNumericExpression(WhileAST left, Token<WhileTokenGener
return operation;
}

[Operation((int)WhileTokenGeneric.TIMES, 2, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.DIVIDE, 2, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.TIMES, Affix.InFix, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.DIVIDE, Affix.InFix, Associativity.Right, 50)]
public WhileAST binaryFactorNumericExpression(WhileAST left, Token<WhileTokenGeneric> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.MULTIPLY;
Expand All @@ -168,7 +168,7 @@ public WhileAST binaryFactorNumericExpression(WhileAST left, Token<WhileTokenGen
return operation;
}

[Operation((int)WhileTokenGeneric.MINUS, 1, Associativity.Right, 100)]
[Operation((int)WhileTokenGeneric.MINUS, Affix.PreFix, Associativity.Right, 100)]
public WhileAST unaryNumericExpression(Token<WhileTokenGeneric> operation, WhileAST value)
{
return new Neg(value as Expression);
Expand All @@ -181,7 +181,7 @@ public WhileAST unaryNumericExpression(Token<WhileTokenGeneric> operation, While

#region BOOLEAN OPERATIONS

[Operation((int)WhileTokenGeneric.OR, 2, Associativity.Right, 10)]
[Operation((int)WhileTokenGeneric.OR, Affix.InFix, Associativity.Right, 10)]
public WhileAST binaryOrExpression(WhileAST left, Token<WhileTokenGeneric> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.OR;
Expand All @@ -191,7 +191,7 @@ public WhileAST binaryOrExpression(WhileAST left, Token<WhileTokenGeneric> opera
return operation;
}

[Operation((int)WhileTokenGeneric.AND, 2, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.AND, Affix.InFix, Associativity.Right, 50)]
public WhileAST binaryAndExpression(WhileAST left, Token<WhileTokenGeneric> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.AND;
Expand All @@ -201,7 +201,7 @@ public WhileAST binaryAndExpression(WhileAST left, Token<WhileTokenGeneric> oper
return operation;
}

[Operation((int)WhileTokenGeneric.NOT, 1, Associativity.Right, 100)]
[Operation((int)WhileTokenGeneric.NOT, Affix.PreFix, Associativity.Right, 100)]
public WhileAST binaryOrExpression(Token<WhileTokenGeneric> operatorToken, WhileAST value)
{

Expand All @@ -211,10 +211,10 @@ public WhileAST binaryOrExpression(Token<WhileTokenGeneric> operatorToken, While

#region COMPARISON OPERATIONS

[Operation((int)WhileTokenGeneric.LESSER, 2, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.GREATER, 2, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.EQUALS, 2, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.DIFFERENT, 2, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.LESSER, Affix.InFix, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.GREATER, Affix.InFix, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.EQUALS, Affix.InFix, Associativity.Right, 50)]
[Operation((int)WhileTokenGeneric.DIFFERENT, Affix.InFix, Associativity.Right, 50)]
public WhileAST binaryComparisonExpression(WhileAST left, Token<WhileTokenGeneric> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.ADD;
Expand Down Expand Up @@ -255,7 +255,7 @@ public WhileAST binaryComparisonExpression(WhileAST left, Token<WhileTokenGeneri

#region STRING OPERATIONS

[Operation((int)WhileTokenGeneric.CONCAT, 2, Associativity.Right, 10)]
[Operation((int)WhileTokenGeneric.CONCAT, Affix.InFix, Associativity.Right, 10)]
public WhileAST binaryStringExpression(WhileAST left, Token<WhileTokenGeneric> operatorToken, WhileAST right)
{
BinaryOperator oper = BinaryOperator.CONCAT;
Expand Down
38 changes: 26 additions & 12 deletions sly/parser/generator/ExpressionRulesGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@ public class OperationMetaData<T> where T : struct

public T OperatorToken { get; set; }

public int Arity { get; set; }
public Affix Affix { get; set; }

public bool IsBinary => Arity == 2;
public bool IsBinary => Affix == Affix.InFix;

public bool IsUnary => Arity == 1;
public bool IsUnary => Affix != Affix.InFix;


public OperationMetaData(int precedence, Associativity assoc, MethodInfo method, int arity, T oper)
public OperationMetaData(int precedence, Associativity assoc, MethodInfo method, Affix affix, T oper)
{
Precedence = precedence;
Associativity = assoc;
VisitorMethod = method;
OperatorToken = oper;
Arity = arity;
Affix = affix;
}

public override string ToString()
{
return $"{OperatorToken} / {Arity} : {Precedence} / {Associativity}";
return $"{OperatorToken} / {Affix} : {Precedence} / {Associativity}";
}
}

Expand All @@ -64,7 +64,7 @@ public static BuildResult<ParserConfiguration<IN, OUT>> BuildExpressionRules<IN,

foreach (OperationAttribute attr in attributes)
{
OperationMetaData<IN> operation = new OperationMetaData<IN>(attr.Precedence, attr.Assoc, m, attr.Arity, ConvertIntToEnum<IN>(attr.Token));
OperationMetaData<IN> operation = new OperationMetaData<IN>(attr.Precedence, attr.Assoc, m, attr.Affix, ConvertIntToEnum<IN>(attr.Token));
var operations = new List<OperationMetaData<IN>>();
if (operationsByPrecedence.ContainsKey(operation.Precedence))
{
Expand Down Expand Up @@ -135,7 +135,7 @@ private static void GenerateExpressionParser<IN, OUT>(ParserConfiguration<IN, OU
string name = GetNonTerminalNameForPrecedence(precedence, operationsByPrecedence, operandNonTerminal);
string nextName = GetNonTerminalNameForPrecedence(nextPrecedence, operationsByPrecedence, operandNonTerminal);

NonTerminal<IN> nonTerminal = BuilNonTerminal<IN>(i == precedences.Count - 1, name, nextName, operations, operationsByPrecedence);
NonTerminal<IN> nonTerminal = BuildNonTerminal<IN>(i == precedences.Count - 1, name, nextName, operations, operationsByPrecedence);

configuration.NonTerminals[nonTerminal.Name] = nonTerminal;
}
Expand All @@ -147,33 +147,46 @@ private static void GenerateExpressionParser<IN, OUT>(ParserConfiguration<IN, OU
Rule<IN> rule = new Rule<IN>();
rule.Clauses.Add(new NonTerminalClause<IN>(lowestname));
rule.IsByPassRule = true;
rule.IsExpressionRule = true;
rule.IsExpressionRule = true;
rule.ExpressionAffix = Affix.NotOperator;
configuration.NonTerminals[entrypoint.Name] = entrypoint;
entrypoint.Rules.Add(rule);
}


private static NonTerminal<IN> BuilNonTerminal<IN>(bool last, string name, string nextName, List<OperationMetaData<IN>> operations, Dictionary<int, List<OperationMetaData<IN>>> operationsByPrecedence) where IN : struct
private static NonTerminal<IN> BuildNonTerminal<IN>(bool last, string name, string nextName, List<OperationMetaData<IN>> operations, Dictionary<int, List<OperationMetaData<IN>>> operationsByPrecedence) where IN : struct
{
NonTerminal<IN> nonTerminal = new NonTerminal<IN>(name, new List<Rule<IN>>());
foreach (OperationMetaData<IN> operation in operations)
{
if (operation.IsBinary)
if (operation.Affix == Affix.InFix)
{
Rule<IN> rule = new Rule<IN>();
rule.Clauses.Add(new NonTerminalClause<IN>(nextName));
rule.Clauses.Add(new TerminalClause<IN>(operation.OperatorToken));
rule.Clauses.Add(new NonTerminalClause<IN>(name));
rule.IsExpressionRule = true;
rule.ExpressionAffix = operation.Affix;
rule.SetVisitor(operation);
nonTerminal.Rules.Add(rule);
}
else if (operation.IsUnary)
else if (operation.Affix == Affix.PreFix)
{
Rule<IN> rule = new Rule<IN>();
rule.Clauses.Add(new TerminalClause<IN>(operation.OperatorToken));
rule.Clauses.Add(new NonTerminalClause<IN>(nextName));
rule.IsExpressionRule = true;
rule.ExpressionAffix = operation.Affix;
rule.SetVisitor(operation);
nonTerminal.Rules.Add(rule);
}
else if (operation.Affix == Affix.PostFix)
{
Rule<IN> rule = new Rule<IN>();
rule.Clauses.Add(new NonTerminalClause<IN>(nextName));
rule.Clauses.Add(new TerminalClause<IN>(operation.OperatorToken));
rule.IsExpressionRule = true;
rule.ExpressionAffix = operation.Affix;
rule.SetVisitor(operation);
nonTerminal.Rules.Add(rule);
}
Expand All @@ -182,6 +195,7 @@ private static NonTerminal<IN> BuilNonTerminal<IN>(bool last, string name, strin
Rule<IN> rule0 = new Rule<IN>();
rule0.Clauses.Add(new NonTerminalClause<IN>(nextName));
rule0.IsExpressionRule = true;
rule0.ExpressionAffix = Affix.NotOperator;
rule0.IsByPassRule = true;
nonTerminal.Rules.Add(rule0);

Expand Down
Loading

0 comments on commit cf4cffa

Please sign in to comment.