Skip to content

Commit

Permalink
lexer post processing - EBNF
Browse files Browse the repository at this point in the history
  • Loading branch information
b3b00 committed Aug 16, 2021
1 parent cf03732 commit 53c6a54
Show file tree
Hide file tree
Showing 15 changed files with 527 additions and 10 deletions.
4 changes: 4 additions & 0 deletions samples/ParserExample/ParserExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
<ProjectReference Include="..\SimpleExpressionParser\SimpleExpressionParser.csproj" />
<ProjectReference Include="..\while\while.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="expressionModel" />
</ItemGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;1705;1591</NoWarn>
Expand Down
126 changes: 120 additions & 6 deletions samples/ParserExample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using indented;
using jsonparser;
using jsonparser.JsonModel;
using ParserExample.expressionModel;
using ParserTests;
using ParserTests.Issue239;
using ParserTests.lexer;
Expand All @@ -30,6 +31,8 @@
using sly.parser.generator.visitor;
using sly.parser.parser;
using Xunit;
using Expression = ParserExample.expressionModel.Expression;
using ExpressionContext = ParserExample.expressionModel.ExpressionContext;

namespace ParserExample
{
Expand Down Expand Up @@ -930,7 +933,8 @@ private static void Main(string[] args)
// Console.ReadLine();
// TestShortGeneric();
//TestIssue239();
TestLexerPostProcess();
//TestLexerPostProcess();
TestLexerPostProcessEBNF();
}


Expand Down Expand Up @@ -1010,10 +1014,44 @@ private static List<Token<ExpressionToken>> postProcess(List<Token<ExpressionTok
return newTokens;
}


private static List<Token<FormulaToken>> postProcessFormula(List<Token<FormulaToken>> tokens)
{
var mayLeft = new List<FormulaToken>()
{
FormulaToken.INT, FormulaToken.DOUBLE, FormulaToken.IDENTIFIER
};

var mayRight = new List<FormulaToken>()
{
FormulaToken.INT, FormulaToken.DOUBLE, FormulaToken.LPAREN, FormulaToken.IDENTIFIER
};

Func<FormulaToken,bool> mayOmmitLeft = (FormulaToken tokenid) => mayLeft.Contains(tokenid);

Func<FormulaToken,bool> mayOmmitRight = (FormulaToken tokenid) => mayRight.Contains(tokenid);


List<Token<FormulaToken>> newTokens = new List<Token<FormulaToken>>();
for (int i = 0; i < tokens.Count; i++)
{
if ( i >= 1 &&
mayOmmitRight(tokens[i].TokenID) && mayOmmitLeft(tokens[i-1].TokenID))
{
newTokens.Add(new Token<FormulaToken>()
{
TokenID = FormulaToken.TIMES
});
}
newTokens.Add(tokens[i]);
}

return newTokens;
}
private static void TestLexerPostProcess()
{
var parserInstance = new VariableExpressionParser();
var builder = new ParserBuilder<ExpressionToken, expressionparser.model.Expression>();
var builder = new ParserBuilder<ExpressionToken, Expression>();
var build = builder.BuildParser(parserInstance, ParserType.LL_RECURSIVE_DESCENT, "expression",
lexerPostProcess: postProcess);
if (build.IsError)
Expand All @@ -1037,7 +1075,83 @@ private static void TestLexerPostProcess()

return;
}
var res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, int>()
var res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, double>()
{ { "x", 2 } }));
Console.WriteLine("2 * x = "+(res.HasValue ? res.Value.ToString() : "?"));


r = Parser.Parse("2 x");
if (r.IsError)
{
foreach (var error in r.Errors)
{
Console.WriteLine(error.ErrorMessage);
}

return;
}
res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, double>()
{ { "x", 2 } }));
Console.WriteLine("2 x = "+(res.HasValue ? res.Value.ToString() : "?"));

r = Parser.Parse("2 ( x ) ");
if (r.IsError)
{
foreach (var error in r.Errors)
{
Console.WriteLine(error.ErrorMessage);
}

return;
}
res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, double>()
{ { "x", 2 } }));
Console.WriteLine("2 (x) = "+(res.HasValue ? res.Value.ToString() : "?"));

r = Parser.Parse("x x ");
if (r.IsError)
{
foreach (var error in r.Errors)
{
Console.WriteLine(error.ErrorMessage);
}

return;
}
res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, double>()
{ { "x", 2 } }));
Console.WriteLine("x x = "+(res.HasValue ? res.Value.ToString() : "?"));

}

private static void TestLexerPostProcessEBNF()
{
var parserInstance = new FormulaParser();
var builder = new ParserBuilder<FormulaToken, Expression>();
var build = builder.BuildParser(parserInstance, ParserType.EBNF_LL_RECURSIVE_DESCENT, $"{typeof(FormulaParser).Name}_expressions",
lexerPostProcess: postProcessFormula);
if (build.IsError)
{
foreach (var error in build.Errors)
{
Console.WriteLine(error.Message);
}

return;
}

var Parser = build.Result;
var r = Parser.Parse("2 * x");
if (r.IsError)
{
foreach (var error in r.Errors)
{
Console.WriteLine(error.ErrorMessage);
}

return;
}
var res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, double>()
{ { "x", 2 } }));
Console.WriteLine("2 * x = "+(res.HasValue ? res.Value.ToString() : "?"));

Expand All @@ -1052,7 +1166,7 @@ private static void TestLexerPostProcess()

return;
}
res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, int>()
res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, double>()
{ { "x", 2 } }));
Console.WriteLine("2 x = "+(res.HasValue ? res.Value.ToString() : "?"));

Expand All @@ -1066,7 +1180,7 @@ private static void TestLexerPostProcess()

return;
}
res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, int>()
res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, double>()
{ { "x", 2 } }));
Console.WriteLine("2 (x) = "+(res.HasValue ? res.Value.ToString() : "?"));

Expand All @@ -1080,7 +1194,7 @@ private static void TestLexerPostProcess()

return;
}
res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, int>()
res = r.Result.Evaluate(new ExpressionContext(new Dictionary<string, double>()
{ { "x", 2 } }));
Console.WriteLine("x x = "+(res.HasValue ? res.Value.ToString() : "?"));

Expand Down
56 changes: 56 additions & 0 deletions samples/ParserExample/expressionModel/BinaryOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using expressionparser.model;

namespace ParserExample.expressionModel
{
public class BinaryOperation : Expression
{
private readonly Expression LeftExpresion;
private readonly FormulaToken Operator;
private readonly Expression RightExpression;


public BinaryOperation(Expression left, FormulaToken op, Expression right)
{
LeftExpresion = left;
Operator = op;
RightExpression = right;
}

public double? Evaluate(ExpressionContext context)
{
var left = LeftExpresion.Evaluate(context);
var right = RightExpression.Evaluate(context);

if (left.HasValue && right.HasValue)
switch (Operator)
{
case FormulaToken.PLUS:
{
return left.Value + right.Value;
}
case FormulaToken.MINUS:
{
return left.Value - right.Value;
}
case FormulaToken.TIMES:
{
return left.Value * right.Value;
}
case FormulaToken.DIVIDE:
{
return left.Value / right.Value;
}
case FormulaToken.EXP:
{
return Math.Pow(left.Value,right.Value);
}
default:
{
return null;
}
}
return null;
}
}
}
9 changes: 9 additions & 0 deletions samples/ParserExample/expressionModel/Expression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using expressionparser.model;

namespace ParserExample.expressionModel
{
public interface Expression
{
double? Evaluate(ExpressionContext context);
}
}
25 changes: 25 additions & 0 deletions samples/ParserExample/expressionModel/ExpressionContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Collections.Generic;

namespace ParserExample.expressionModel
{
public class ExpressionContext
{
private readonly Dictionary<string, double> Variables;

public ExpressionContext()
{
Variables = new Dictionary<string, double>();
}

public ExpressionContext(Dictionary<string, double> variables)
{
Variables = variables;
}

public double? GetValue(string variable)
{
if (Variables.ContainsKey(variable)) return Variables[variable];
return null;
}
}
}
77 changes: 77 additions & 0 deletions samples/ParserExample/expressionModel/FormulaParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Collections.Generic;
using System.Linq;
using sly.lexer;
using sly.parser.generator;
using sly.parser.parser;

namespace ParserExample.expressionModel
{
public class FormulaParser
{
[Operation((int) FormulaToken.PLUS, Affix.InFix, Associativity.Right, 10)]
[Operation((int) FormulaToken.MINUS, Affix.InFix, Associativity.Left, 10)]
public Expression BinaryTermExpression(Expression left, Token<FormulaToken> operation, Expression right)
{
return new BinaryOperation(left, operation.TokenID, right);
}


[Operation((int) FormulaToken.TIMES, Affix.InFix, Associativity.Right, 50)]
[Operation((int) FormulaToken.DIVIDE, Affix.InFix, Associativity.Left, 50)]
public Expression BinaryFactorExpression(Expression left, Token<FormulaToken> operation, Expression right)
{
return new BinaryOperation(left, operation.TokenID, right);
}


[Operation((int) FormulaToken.MINUS, Affix.PreFix, Associativity.Right, 100)]
public Expression PreFixExpression(Token<FormulaToken> operation, Expression value)
{
return new UnaryOperation(FormulaToken.MINUS,value);
}

[Operation((int) FormulaToken.EXP, Affix.InFix, Associativity.Left, 90)]
public Expression ExpExpression(Expression left, Token<FormulaToken> operation, Expression right)
{
return new BinaryOperation(left, operation.TokenID, right);
}

[Operand]
[Production("operand : primary_value")]
public Expression OperandValue(Expression value)
{
return value;
}


[Production("primary_value : IDENTIFIER")]
public Expression OperandVariable(Token<FormulaToken> identifier)
{
return new Variable(identifier.Value);
}

[Production("primary_value : DOUBLE")]
[Production("primary_value : INT")]
public Expression OperandInt(Token<FormulaToken> value)
{
return new Number(value.DoubleValue);
}

[Production("primary_value : LPAREN FormulaParser_expressions RPAREN")]
public Expression OperandParens(Token<FormulaToken> lparen, Expression value, Token<FormulaToken> rparen)
{
return value;
}

[Production(
"primary_value : IDENTIFIER LPAREN[d] FormulaParser_expressions (COMMA FormulaParser_expressions)* RPAREN[d]")]
public Expression FunctionCall(Token<FormulaToken> funcName, Expression first,
List<Group<FormulaToken, Expression>> others)
{
List<Expression> parameters = new List<Expression>();
parameters.Add(first);
parameters.AddRange(others.Select(x => x.Value(0)));
return new FunctionCall(funcName.Value, parameters);
}
}
}
Loading

0 comments on commit 53c6a54

Please sign in to comment.