I want to let the users input mathematics expression in terms of x and y as natural as possible. For example, instead of typing Complex.Sin(x), I prefer to use just Sin(x).
The following code fails when Sin(x), for example, is defined by the user.
using Microsoft.CodeAnalysis.CSharp.Scripting;
using System;
using System.Numerics;
using static System.Console;
using static System.Numerics.Complex;
namespace MathEvaluator
{
public class Globals
{
public Complex x;
public Complex y;
}
class Program
{
async static void JobAsync(Microsoft.CodeAnalysis.Scripting.Script<Complex> script)
{
Complex x = new Complex(1, 0);
Complex y = new Complex(0, 1);
try
{
var result = await script.RunAsync(new Globals { x = x, y = y });
WriteLine($"{x} * {y} = {result.ReturnValue}\n");
}
catch (Exception e)
{
WriteLine(e.Message);
}
}
static void Main(string[] args)
{
Console.Write("Define your expression in x and y: ");
string expression = Console.ReadLine(); //user input
var script = CSharpScript.Create<Complex>(expression, globalsType: typeof(Globals));
script.Compile();
JobAsync(script);
}
}
}
Question
How to use using static directive for dynamically generated code?
You can supply script options to the Create function that define the references and imports that should be set for your script:
var scriptOptions = ScriptOptions.Default
.WithReferences("System.Numerics")
.WithImports("System.Numerics.Complex");
var script = CSharpScript.Create<Complex>(expression, options: scriptOptions, globalsType: typeof(Globals));
That way, you can use Sin(x) in the input:
Define your expression in x and y: Sin(x)
(1, 0) * (0, 1) = (0,841470984807897, 0)
However, when dealing with user input, you should consider writing your own parser. This allows you on one hand to define your own “aliases” for functions (e.g. a lower case sin) or even a more lenient syntax; on the other hand, it also adds more security because right now, nothing prevents me from doing this:
Define your expression in x and y: System.Console.WriteLine("I hacked this calculator!")
I hacked this calculator!
(1, 0) * (0, 1) = (0, 0)
I created a quick (and dirty) parser using Roslyn’s syntax tree parsing. Obviously this is rather limited (e.g. since it requires all return values of subexpressions to be Complex), but this could give you an idea of how this could work:
void Main()
{
string input = "y + 3 * Sin(x)";
var options = CSharpParseOptions.Default.WithKind(Microsoft.CodeAnalysis.SourceCodeKind.Script);
var expression = CSharpSyntaxTree.ParseText(input, options).GetRoot().DescendantNodes().OfType<ExpressionStatementSyntax>().FirstOrDefault()?.Expression;
Console.WriteLine(EvaluateExpression(expression));
}
Complex EvaluateExpression(ExpressionSyntax expr)
{
if (expr is BinaryExpressionSyntax)
{
var binExpr = (BinaryExpressionSyntax)expr;
var left = EvaluateExpression(binExpr.Left);
var right = EvaluateExpression(binExpr.Right);
switch (binExpr.OperatorToken.ValueText)
{
case "+":
return left + right;
case "-":
return left - right;
case "*":
return left * right;
case "/":
return left / right;
default:
throw new NotSupportedException(binExpr.OperatorToken.ValueText);
}
}
else if (expr is IdentifierNameSyntax)
{
return GetValue(((IdentifierNameSyntax)expr).Identifier.ValueText);
}
else if (expr is LiteralExpressionSyntax)
{
var value = ((LiteralExpressionSyntax)expr).Token.Value;
return float.Parse(value.ToString());
}
else if (expr is InvocationExpressionSyntax)
{
var invocExpr = (InvocationExpressionSyntax)expr;
var args = invocExpr.ArgumentList.Arguments.Select(arg => EvaluateExpression(arg.Expression)).ToArray();
return Call(((IdentifierNameSyntax)invocExpr.Expression).Identifier.ValueText, args);
}
else
throw new NotSupportedException(expr.GetType().Name);
}
Complex Call(string identifier, Complex[] args)
{
switch (identifier.ToLower())
{
case "sin":
return Complex.Sin(args[0]);
default:
throw new NotImplementedException(identifier);
}
}
Complex GetValue(string identifier)
{
switch (identifier)
{
case "x":
return new Complex(1, 0);
case "y":
return new Complex(0, 1);
default:
throw new ArgumentException("Identifier not found", nameof(identifier));
}
}
Related
I've got this ugly bit of code that looks a bit like this ...
TestResult GetFirstTestResult()
{
var result = TestMethod1();
if(result is EmptyResult)
{
result = TestMethod2();
}
if(result is EmptyResult)
{
result = TestMethod3();
}
// ...
if(result is EmptyResult)
{
result = TestMethodN();
}
return result;
}
Basically, I need to run a number of tests until I find one that has some values.
Now whilst the above code isn't pretty, for a small(ish) value of N is is managable. Sadly, in my case, N could get fairly big.
Is there a way of writing this using a loop, something along the lines of this pseudo code...
TestResult GetFirstTestResult()
{
TestResult[] results = {TestMethod1(), TestMethod2(), TestMethod3(), .. TestMethodN()};
return results.First(test=>!test.Result is Emptyresult);
}
such that each of the test methods were invoked in the loop so only the minimum number of them were actually executed?
EDIT
With thanks to Ric and Simon I've got this...
TestResult GetFirstTestResult()
{
return new Func<TestResult>[]
{
TestMethod1,
TestMethod2,
TestMethodN
}.Select(t => t())
.FirstOrDefault(r => !(r is EmptyResult)) ?? new EmptyResult();
}
which calls each method in turn until it finds one where the result is not of type EmptyResult and returns that. If no such result is found it returns new EmptyResult()
Something like this? Obviously I don't have all your code so cannot verify the correctness, but you should be able to modify as you require:
List<Func<TestResult>> methods = new List<Func<TestResult>>() { TestMethod1, TestMethod2, TestMethod3 };
foreach(var f in methods)
{
if(f().Result != EmptyResult)
{
break; //or something else
}
}
Simple solution using delegates:
class Program
{
static void Main(string[] args)
{
List<Func<int>> tests = new List<Func<int>>() { T1, T2, T3 };
Func<int> test = tests.First(t => t() != 0);
Console.WriteLine("Test is " + test.Method.Name);
}
static int T1() { return 0; }
static int T2() { return 1; }
static int T3() { return 1; }
}
I've found similar questions asked before but the answers I've seen have been specific to the example given by the person or workarounds for that person's example, not a general solution.
I'd like to pass a class' property to a function to do an operation on that property. The example I'm going to use is incrementing a value, but I have more complicated scenarios so I'm looking for a general solution, not an answer for specifically incrementing.
How I used to do it is I'd either have multiple functions IncrementPassengerCount, IncrementDistanceTravelled, IncrementPlaneAge, but that's unweildly and horrible.
I'd like one general function that I can call using something like this pseudocode:
Increment(myPlane, myPlane.DistanceTravelled);
Increment(myPlane, myPlane.PlaneAge);
//where
public void Increment(Airplane myPlane, Property propToIncrement)
{
myPlane.propToIncrement++; //or do whatever like I now have myPlane.DistanceTravelled
}
I've tried this:
Increment(myPlane, x => x.DistanceTravelled);
//where
public void Increment(Airplane myPlane, Func<Log, IComparable> property)
{
property(myPlane)++;
}
But this causes a
Operator '++' cannot be applied to operand of type 'System.IComparable'
Is there a way to do what I'm imagining or am I looking at it wrong? Thanks in advance.
Is is possible, though convoluted and probably a sign that you should perhaps do it a different way, but here it is. (I would recommend as Jon Skeet mentioned, to just use the ++ operator instead of invoking the Increment method. In addition to the method I included two classes that will allow you to test the code in a console app. There would need to be plenty of error checking. I have a few null checks, but there may be more locations it is needed. If you have overloaded the ++ operator, it works for those types too, but any errors cannot be anticipated.
public static void Increment(this object o, string propertyName)
{
var property = o.GetType().GetProperty(propertyName);
if (property == null)
return;
var val = property.GetValue(o, null);
var op_Inc = o.GetType().GetMethod("op_Increment");
if(op_Inc != null)
{
var val2 = op_Inc.Invoke(val, null);
property.SetValue(o,val2);
}
switch (Type.GetTypeCode(property.PropertyType))
{
case TypeCode.UInt16:
{
var x = (UInt16)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.UInt32:
{
var x = (UInt32)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.UInt64:
{
var x = (UInt64)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Int16:
{
var x = (Int16)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Int32:
{
var x = (Int32)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Int64:
{
var x = (Int64)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Decimal:
{
var x = (Decimal)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Double:
{
var x = (Double)val;
x++;
property.SetValue(o, x);
}
break;
case TypeCode.Single:
{
var x = (Single)val;
x++;
property.SetValue(o, x);
}
break;
}
}
}
public class Example
{
public static void Main()
{
var plane = new Plane(){DistanceTravelled = 0, PlaneAge = 0};
Console.WriteLine("Before invoking increment: dist = {0}, age = {1}", plane.DistanceTravelled, plane.PlaneAge);
plane.Increment("DistanceTravelled");
plane.Increment("PlaneAge");
Console.WriteLine("After invoking increment: dist = {0}, age = {1}", plane.DistanceTravelled, plane.PlaneAge);
Console.ReadKey();
}
}
public class Plane
{
public int DistanceTravelled { get; set; }
public int PlaneAge { get; set; }
}
I am trying to search for fairly complex queries with Lucene.Net like
"inject* needle*" OR "point* thingy"~2
So basically I need wildcards in regular as well as proximity phrases. However, the basic Lucene.Net QueryParser gets rid of these wildcards.
I understand that ComplexPhraseQueryParser would work for that, unfortunately this is not included in Lucene.Net.
Is there any way of constructing queries like this in Lucene.Net?
I ended up by actually porting the ComplexPhraseQueryParser from Java to C#. It was a lot easier than expected and was a good excercise for learning C# a bit better.
I have provided the code below in case it is helpfull to anyone else. Please note that it is still very Java-like Code as I am a lot more familiar with Java than I am with C# ;-)
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Ported to C# from Java source at http://grepcode.com/file/repo1.maven.org/maven2/org.apache.lucene/lucene-misc/3.0.3/org/apache/lucene/queryParser/complexPhrase/ComplexPhraseQueryParser.java
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Search.Spans;
using System;
using System.Collections.Generic;
using Version = Lucene.Net.Util.Version;
public class ComplexPhraseQueryParser : QueryParser
{
private List<ComplexPhraseQuery> complexPhrases = null;
private Boolean isPass2ResolvingPhrases;
private ComplexPhraseQuery currentPhraseQuery = null;
public ComplexPhraseQueryParser(Version matchVersion, String f, Analyzer a) : base(matchVersion, f, a) { }
protected override Query GetFieldQuery(String field, String queryText, int slop)
{
ComplexPhraseQuery cpq = new ComplexPhraseQuery(field, queryText, slop);
complexPhrases.Add(cpq); // add to list of phrases to be parsed once
// we
// are through with this pass
return cpq;
}
public override Query Parse(String query)
{
if (isPass2ResolvingPhrases)
{
RewriteMethod oldMethod = MultiTermRewriteMethod;
try
{
// Temporarily force BooleanQuery rewrite so that Parser will
// generate visible
// collection of terms which we can convert into SpanQueries.
// ConstantScoreRewrite mode produces an
// opaque ConstantScoreQuery object which cannot be interrogated for
// terms in the same way a BooleanQuery can.
// QueryParser is not guaranteed threadsafe anyway so this temporary
// state change should not
// present an issue
MultiTermRewriteMethod = MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE;
return base.Parse(query);
}
finally
{
MultiTermRewriteMethod = oldMethod;
}
}
// First pass - parse the top-level query recording any PhraseQuerys
// which will need to be resolved
complexPhrases = new List<ComplexPhraseQuery>();
Query q = base.Parse(query);
// Perform second pass, using this QueryParser to parse any nested
// PhraseQueries with different
// set of syntax restrictions (i.e. all fields must be same)
isPass2ResolvingPhrases = true;
try
{
using (IEnumerator<ComplexPhraseQuery> enumerator = complexPhrases.GetEnumerator())
{
while (enumerator.MoveNext())
{
currentPhraseQuery = enumerator.Current;
currentPhraseQuery.ParsePhraseElements(this);
}
}
}
finally
{
isPass2ResolvingPhrases = false;
}
return q;
}
// There is No "getTermQuery throws ParseException" method to override so
// unfortunately need
// to throw a runtime exception here if a term for another field is embedded
// in phrase query
protected override Query NewTermQuery(Term term)
{
if (isPass2ResolvingPhrases)
{
try
{
CheckPhraseClauseIsForSameField(term.Field);
}
catch (ParseException pe)
{
throw new SystemException("Error parsing complex phrase", pe);
}
}
return base.NewTermQuery(term);
}
// Helper method used to report on any clauses that appear in query syntax
private void CheckPhraseClauseIsForSameField(String field)
{
if (!field.Equals(currentPhraseQuery.Field))
{
throw new ParseException("Cannot have clause for field \"" + field
+ "\" nested in phrase " + " for field \"" + currentPhraseQuery.Field
+ "\"");
}
}
protected override Query GetWildcardQuery(String field, String termStr)
{
if (isPass2ResolvingPhrases)
{
CheckPhraseClauseIsForSameField(field);
}
return base.GetWildcardQuery(field, termStr);
}
protected override Query GetRangeQuery(String field, String part1, String part2, Boolean inclusive)
{
if (isPass2ResolvingPhrases)
{
CheckPhraseClauseIsForSameField(field);
}
return base.GetRangeQuery(field, part1, part2, inclusive);
}
protected override Query NewRangeQuery(String field, String part1, String part2,
Boolean inclusive)
{
if (isPass2ResolvingPhrases)
{
// Must use old-style RangeQuery in order to produce a BooleanQuery
// that can be turned into SpanOr clause
TermRangeQuery rangeQuery = new TermRangeQuery(field, part1, part2, inclusive, inclusive, RangeCollator);
rangeQuery.RewriteMethod = MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE;
return rangeQuery;
}
return base.NewRangeQuery(field, part1, part2, inclusive);
}
protected Query GetFuzzyQuery(String field, String termStr, float minSimilarity)
{
if (isPass2ResolvingPhrases)
{
CheckPhraseClauseIsForSameField(field);
}
return base.GetFuzzyQuery(field, termStr, minSimilarity);
}
/*
* Used to handle the query content in between quotes and produced Span-based
* interpretations of the clauses.
*/
class ComplexPhraseQuery : Query
{
public string Field { get; set; }
public string PhrasedQueryStringContents { get; set; }
public int SlopFactor { get; set; }
private Query Contents;
public ComplexPhraseQuery(string Field, string PhrasedQueryStringContents, int SlopFactor)
: base()
{
this.Field = Field;
this.PhrasedQueryStringContents = PhrasedQueryStringContents;
this.SlopFactor = SlopFactor;
}
// Called by ComplexPhraseQueryParser for each phrase after the main
// parse
// thread is through
public void ParsePhraseElements(QueryParser qp)
{
// TODO ensure that field-sensitivity is preserved ie the query
// string below is parsed as
// field+":("+phrasedQueryStringContents+")"
// but this will need code in rewrite to unwrap the first layer of
// boolean query
Contents = qp.Parse(PhrasedQueryStringContents);
}
public override Query Rewrite(IndexReader reader)
{
// ArrayList spanClauses = new ArrayList();
if (Contents is TermQuery)
{
return Contents;
}
// Build a sequence of Span clauses arranged in a SpanNear - child
// clauses can be complex
// Booleans e.g. nots and ors etc
int numNegatives = 0;
if (!(Contents is BooleanQuery))
{
throw new ArgumentException("Unknown query type \""
+ Contents.GetType()
+ "\" found in phrase query string \"" + PhrasedQueryStringContents
+ "\"");
}
BooleanQuery bq = (BooleanQuery)Contents;
BooleanClause[] bclauses = bq.GetClauses();
SpanQuery[] allSpanClauses = new SpanQuery[bclauses.Length];
// For all clauses e.g. one* two~
for (int i = 0; i < bclauses.Length; i++)
{
// HashSet bclauseterms=new HashSet();
Query qc = bclauses[i].Query;
// Rewrite this clause e.g one* becomes (one OR onerous)
qc = qc.Rewrite(reader);
if (bclauses[i].Occur.Equals(Occur.MUST_NOT))
{
numNegatives++;
}
if (qc is BooleanQuery)
{
List<SpanQuery> sc = new List<SpanQuery>();
AddComplexPhraseClause(sc, (BooleanQuery)qc);
if (sc.Count > 0)
{
allSpanClauses[i] = sc[0];
}
else
{
// Insert fake term e.g. phrase query was for "Fred Smithe*" and
// there were no "Smithe*" terms - need to
// prevent match on just "Fred".
allSpanClauses[i] = new SpanTermQuery(new Term(Field,
"Dummy clause because no terms found - must match nothing"));
}
}
else
{
if (qc is TermQuery)
{
TermQuery tq = (TermQuery)qc;
allSpanClauses[i] = new SpanTermQuery(tq.Term);
}
else
{
throw new ArgumentException("Unknown query type \""
+ qc.GetType()
+ "\" found in phrase query string \""
+ PhrasedQueryStringContents + "\"");
}
}
}
if (numNegatives == 0)
{
// The simple case - no negative elements in phrase
return new SpanNearQuery(allSpanClauses, SlopFactor, true);
}
// Complex case - we have mixed positives and negatives in the
// sequence.
// Need to return a SpanNotQuery
List<SpanQuery> positiveClauses = new List<SpanQuery>();
for (int j = 0; j < allSpanClauses.Length; j++)
{
if (!bclauses[j].Occur.Equals(Occur.MUST_NOT))
{
positiveClauses.Add(allSpanClauses[j]);
}
}
//SpanQuery[] includeClauses = positiveClauses.ToArray(new SpanQuery[positiveClauses.Count]);
SpanQuery[] includeClauses = positiveClauses.ToArray();
SpanQuery include = null;
if (includeClauses.Length == 1)
{
include = includeClauses[0]; // only one positive clause
}
else
{
// need to increase slop factor based on gaps introduced by
// negatives
include = new SpanNearQuery(includeClauses, SlopFactor + numNegatives,
true);
}
// Use sequence of positive and negative values as the exclude.
SpanNearQuery exclude = new SpanNearQuery(allSpanClauses, SlopFactor,
true);
SpanNotQuery snot = new SpanNotQuery(include, exclude);
return snot;
}
private void AddComplexPhraseClause(List<SpanQuery> spanClauses, BooleanQuery qc)
{
List<SpanQuery> ors = new List<SpanQuery>();
List<SpanQuery> nots = new List<SpanQuery>();
BooleanClause[] bclauses = qc.GetClauses();
// For all clauses e.g. one* two~
for (int i = 0; i < bclauses.Length; i++)
{
Query childQuery = bclauses[i].Query;
// select the list to which we will add these options
List<SpanQuery> chosenList = ors;
if (bclauses[i].Occur == Occur.MUST_NOT)
{
chosenList = nots;
}
if (childQuery is TermQuery)
{
TermQuery tq = (TermQuery)childQuery;
SpanTermQuery stq = new SpanTermQuery(tq.Term);
stq.Boost = tq.Boost;
chosenList.Add(stq);
}
else if (childQuery is BooleanQuery)
{
BooleanQuery cbq = (BooleanQuery)childQuery;
AddComplexPhraseClause(chosenList, cbq);
}
else
{
// TODO alternatively could call extract terms here?
throw new ArgumentException("Unknown query type:"
+ childQuery.GetType());
}
}
if (ors.Count == 0)
{
return;
}
SpanOrQuery soq = new SpanOrQuery(ors.ToArray());
if (nots.Count == 0)
{
spanClauses.Add(soq);
}
else
{
SpanOrQuery snqs = new SpanOrQuery(nots.ToArray());
SpanNotQuery snq = new SpanNotQuery(soq, snqs);
spanClauses.Add(snq);
}
}
public override String ToString(String field)
{
return "\"" + PhrasedQueryStringContents + "\"";
}
public override int GetHashCode()
{
const int prime = 31;
int result = 1;
result = prime * result + ((Field == null) ? 0 : Field.GetHashCode());
result = prime
* result
+ ((PhrasedQueryStringContents == null) ? 0
: PhrasedQueryStringContents.GetHashCode());
result = prime * result + SlopFactor;
return result;
}
public override Boolean Equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (GetType() != obj.GetType())
return false;
ComplexPhraseQuery other = (ComplexPhraseQuery)obj;
if (Field == null)
{
if (other.Field != null)
return false;
}
else if (!Field.Equals(other.Field))
return false;
if (PhrasedQueryStringContents == null)
{
if (other.PhrasedQueryStringContents != null)
return false;
}
else if (!PhrasedQueryStringContents
.Equals(other.PhrasedQueryStringContents))
return false;
if (SlopFactor != other.SlopFactor)
return false;
return true;
}
}
}
I am comparing two XML nodes which includes numeric values with comparison operators as shown below
<rule id="rule1" subject="user1" age="60" permission="granted"/>
<rule id="rule2" subject="user1" age=">=50" permission="denied"/>
This is a very simple example where the rule1 states that if the subject is user1 then the permission is granted if his age is 60 whereas the rule2 states that permission is denied for user1 if age is 50 or greater than 50. So it mean these rules are contradictory.
My question is that how could I compare the age attribute which is including numeric values and comparison operators. In the above example I conclude that both the rules have contradictory values.
I am using C# to compare these attribute values.
I would create a syntax tree from xml and use the tree to evaluate the conditions. As for how to evaluate comparison-based rule, you can write your own class like:
public enum BinaryOperator
{
LessThenOrEqual,
LessThen,
Equal,
GreaterThen,
GreaterThenOrEqual
}
public class BinaryOperatorEvaluator
{
public BinaryOperatorEvaluator(BinaryOperator op)
{
Operator = op;
}
public BinaryOperator Operator { get; private set; }
public bool Evaluate(IComparable x, IComparable y)
{
switch (Operator)
{
case BinaryOperator.Equal:
return x.CompareTo(y) == 0;
case BinaryOperator.GreaterThen:
return x.CompareTo(y) > 0;
case BinaryOperator.GreaterThenOrEqual:
return x.CompareTo(y) >= 0;
case BinaryOperator.LessThen:
return x.CompareTo(y) < 0;
case BinaryOperator.LessThenOrEqual:
return x.CompareTo(y) <= 0;
default:
throw new NotImplementedException();
}
}
public static BinaryOperatorEvaluator FromExpression(string expression, out int value)
{
var regexValidTerm = new Regex("^(?<operator>(<=|=|>=|<|>)?)(?<numeric>([0-9]+))$");
var match = regexValidTerm.Match(expression);
if (!match.Success)
{
throw new ArgumentException("Not a valid expression.", "expression");
}
var opValue = match.Groups["operator"].Value;
var op = BinaryOperator.Equal;
if (!string.IsNullOrEmpty(opValue))
{
switch(opValue)
{
case "<=":
op = BinaryOperator.LessThenOrEqual;
break;
case "=":
op = BinaryOperator.Equal;
break;
case ">=":
op = BinaryOperator.GreaterThenOrEqual;
break;
case "<":
op = BinaryOperator.LessThen;
break;
case ">":
op = BinaryOperator.LessThenOrEqual;
break;
default:
throw new NotImplementedException();
}
}
value = int.Parse(match.Groups["numeric"].Value);
return new BinaryOperatorEvaluator(op);
}
}
int number;
var bo = BinaryOperatorEvaluator.FromExpression("<=15", out number);
// false
var foo = bo.Evaluate(16, number);
// true
foo = bo.Evaluate(15, number);
// also true
foo = bo.Evaluate(14, number);
Add the runat="server" inside your tags, then access the attribute with rule1.Attributes["age"] within c# code. And overload operator for comparison if its logic requires this.
You might consider doing this in code behind, makes it a heck lot easier.
if(age > 50)
permission = "denied";
else if(age == 60)
permission = "granted";
I've got the following BoolExpr class:
class BoolExpr
{
public enum BOP { LEAF, AND, OR, NOT };
//
// inner state
//
private BOP _op;
private BoolExpr _left;
private BoolExpr _right;
private String _lit;
//
// private constructor
//
private BoolExpr(BOP op, BoolExpr left, BoolExpr right)
{
_op = op;
_left = left;
_right = right;
_lit = null;
}
private BoolExpr(String literal)
{
_op = BOP.LEAF;
_left = null;
_right = null;
_lit = literal;
}
//
// accessor
//
public BOP Op
{
get { return _op; }
set { _op = value; }
}
public BoolExpr Left
{
get { return _left; }
set { _left = value; }
}
public BoolExpr Right
{
get { return _right; }
set { _right = value; }
}
public String Lit
{
get { return _lit; }
set { _lit = value; }
}
//
// public factory
//
public static BoolExpr CreateAnd(BoolExpr left, BoolExpr right)
{
return new BoolExpr(BOP.AND, left, right);
}
public static BoolExpr CreateNot(BoolExpr child)
{
return new BoolExpr(BOP.NOT, child, null);
}
public static BoolExpr CreateOr(BoolExpr left, BoolExpr right)
{
return new BoolExpr(BOP.OR, left, right);
}
public static BoolExpr CreateBoolVar(String str)
{
return new BoolExpr(str);
}
public BoolExpr(BoolExpr other)
{
// No share any object on purpose
_op = other._op;
_left = other._left == null ? null : new BoolExpr(other._left);
_right = other._right == null ? null : new BoolExpr(other._right);
_lit = new StringBuilder(other._lit).ToString();
}
//
// state checker
//
Boolean IsLeaf()
{
return (_op == BOP.LEAF);
}
Boolean IsAtomic()
{
return (IsLeaf() || (_op == BOP.NOT && _left.IsLeaf()));
}
}
What algorithm should I use to parse an input boolean expression string like "¬((A ∧ B) ∨ C ∨ D)" and load it into the above class?
TL;DR: If you want to see the code, jump to the second portion of the answer.
I would build a tree from the expression to parse and then traverse it depth first. You can refer to the wikipedia article about Binary Expression Trees to get a feel for what I'm suggesting.
Start by adding the omitted optional parentheses to make the next step easier
When you read anything that is not an operator or a parenthese, create a LEAF type node
When you read any operator (in your case not, and, or), create the corresponding operator node
Binary operators get the previous and following nodes as children, unary operators only get the next one.
So, for your example ¬((A ∧ B) ∨ C ∨ D), the algorithm would go like this:
¬((A ∧ B) ∨ C ∨ D) becomes ¬(((A ∧ B) ∨ C) ∨ D)
Create a NOT node, it'll get the result of the following opening paren as a child.
Create A LEAF node, AND node and B LEAF node. AND has A and B as children.
Create OR node, it has the previously created AND as a child and a new LEAF node for C.
Create OR node, it has the previously created OR and a new node for D as children.
At that point, your tree looks like this:
NOT
|
OR
/\
OR D
/ \
AND C
/\
A B
You can then add a Node.Evaluate() method that evaluates recursively based on its type (polymorphism could be used here). For example, it could look something like this:
class LeafEx {
bool Evaluate() {
return Boolean.Parse(this.Lit);
}
}
class NotEx {
bool Evaluate() {
return !Left.Evaluate();
}
}
class OrEx {
bool Evaluate() {
return Left.Evaluate() || Right.Evaluate();
}
}
And so on and so forth. To get the result of your expression, you then only need to call
bool result = Root.Evaluate();
Alright, since it's not an assignment and it's actually a fun thing to implement, I went ahead. Some of the code I'll post here is not related to what I described earlier (and some parts are missing) but I'll leave the top part in my answer for reference (nothing in there is wrong (hopefully!)).
Keep in mind this is far from optimal and that I made an effort to not modify your provided BoolExpr class. Modifying it could allow you to reduce the amount of code. There's also no error checking at all.
Here's the main method
static void Main(string[] args)
{
//We'll use ! for not, & for and, | for or and remove whitespace
string expr = #"!((A&B)|C|D)";
List<Token> tokens = new List<Token>();
StringReader reader = new StringReader(expr);
//Tokenize the expression
Token t = null;
do
{
t = new Token(reader);
tokens.Add(t);
} while (t.type != Token.TokenType.EXPR_END);
//Use a minimal version of the Shunting Yard algorithm to transform the token list to polish notation
List<Token> polishNotation = TransformToPolishNotation(tokens);
var enumerator = polishNotation.GetEnumerator();
enumerator.MoveNext();
BoolExpr root = Make(ref enumerator);
//Request boolean values for all literal operands
foreach (Token tok in polishNotation.Where(token => token.type == Token.TokenType.LITERAL))
{
Console.Write("Enter boolean value for {0}: ", tok.value);
string line = Console.ReadLine();
booleanValues[tok.value] = Boolean.Parse(line);
Console.WriteLine();
}
//Eval the expression tree
Console.WriteLine("Eval: {0}", Eval(root));
Console.ReadLine();
}
The tokenization phase creates a Token object for all tokens of the expression. It helps keep the parsing separated from the actual algorithm. Here's the Token class that performs this:
class Token
{
static Dictionary<char, KeyValuePair<TokenType, string>> dict = new Dictionary<char, KeyValuePair<TokenType, string>>()
{
{
'(', new KeyValuePair<TokenType, string>(TokenType.OPEN_PAREN, "(")
},
{
')', new KeyValuePair<TokenType, string>(TokenType.CLOSE_PAREN, ")")
},
{
'!', new KeyValuePair<TokenType, string>(TokenType.UNARY_OP, "NOT")
},
{
'&', new KeyValuePair<TokenType, string>(TokenType.BINARY_OP, "AND")
},
{
'|', new KeyValuePair<TokenType, string>(TokenType.BINARY_OP, "OR")
}
};
public enum TokenType
{
OPEN_PAREN,
CLOSE_PAREN,
UNARY_OP,
BINARY_OP,
LITERAL,
EXPR_END
}
public TokenType type;
public string value;
public Token(StringReader s)
{
int c = s.Read();
if (c == -1)
{
type = TokenType.EXPR_END;
value = "";
return;
}
char ch = (char)c;
if (dict.ContainsKey(ch))
{
type = dict[ch].Key;
value = dict[ch].Value;
}
else
{
string str = "";
str += ch;
while (s.Peek() != -1 && !dict.ContainsKey((char)s.Peek()))
{
str += (char)s.Read();
}
type = TokenType.LITERAL;
value = str;
}
}
}
At that point, in the main method, you can see I transform the list of tokens in Polish Notation order. It makes the creation of the tree much easier and I use a modified implementation of the Shunting Yard Algorithm for this:
static List<Token> TransformToPolishNotation(List<Token> infixTokenList)
{
Queue<Token> outputQueue = new Queue<Token>();
Stack<Token> stack = new Stack<Token>();
int index = 0;
while (infixTokenList.Count > index)
{
Token t = infixTokenList[index];
switch (t.type)
{
case Token.TokenType.LITERAL:
outputQueue.Enqueue(t);
break;
case Token.TokenType.BINARY_OP:
case Token.TokenType.UNARY_OP:
case Token.TokenType.OPEN_PAREN:
stack.Push(t);
break;
case Token.TokenType.CLOSE_PAREN:
while (stack.Peek().type != Token.TokenType.OPEN_PAREN)
{
outputQueue.Enqueue(stack.Pop());
}
stack.Pop();
if (stack.Count > 0 && stack.Peek().type == Token.TokenType.UNARY_OP)
{
outputQueue.Enqueue(stack.Pop());
}
break;
default:
break;
}
++index;
}
while (stack.Count > 0)
{
outputQueue.Enqueue(stack.Pop());
}
return outputQueue.Reverse().ToList();
}
After this transformation, our token list becomes NOT, OR, OR, C, D, AND, A, B.
At this point, we're ready to create the expression tree. The properties of Polish Notation allow us to just walk the Token List and recursively create the tree nodes (we'll use your BoolExpr class) as we go:
static BoolExpr Make(ref List<Token>.Enumerator polishNotationTokensEnumerator)
{
if (polishNotationTokensEnumerator.Current.type == Token.TokenType.LITERAL)
{
BoolExpr lit = BoolExpr.CreateBoolVar(polishNotationTokensEnumerator.Current.value);
polishNotationTokensEnumerator.MoveNext();
return lit;
}
else
{
if (polishNotationTokensEnumerator.Current.value == "NOT")
{
polishNotationTokensEnumerator.MoveNext();
BoolExpr operand = Make(ref polishNotationTokensEnumerator);
return BoolExpr.CreateNot(operand);
}
else if (polishNotationTokensEnumerator.Current.value == "AND")
{
polishNotationTokensEnumerator.MoveNext();
BoolExpr left = Make(ref polishNotationTokensEnumerator);
BoolExpr right = Make(ref polishNotationTokensEnumerator);
return BoolExpr.CreateAnd(left, right);
}
else if (polishNotationTokensEnumerator.Current.value == "OR")
{
polishNotationTokensEnumerator.MoveNext();
BoolExpr left = Make(ref polishNotationTokensEnumerator);
BoolExpr right = Make(ref polishNotationTokensEnumerator);
return BoolExpr.CreateOr(left, right);
}
}
return null;
}
Now we're golden! We have the expression tree that represents the expression so we'll ask the user for the actual boolean values of each literal operand and evaluate the root node (which will recursively evaluate the rest of the tree as needed).
My Eval function follows, keep in mind I'd use some polymorphism to make this cleaner if I modified your BoolExpr class.
static bool Eval(BoolExpr expr)
{
if (expr.IsLeaf())
{
return booleanValues[expr.Lit];
}
if (expr.Op == BoolExpr.BOP.NOT)
{
return !Eval(expr.Left);
}
if (expr.Op == BoolExpr.BOP.OR)
{
return Eval(expr.Left) || Eval(expr.Right);
}
if (expr.Op == BoolExpr.BOP.AND)
{
return Eval(expr.Left) && Eval(expr.Right);
}
throw new ArgumentException();
}
As expected, feeding our test expression ¬((A ∧ B) ∨ C ∨ D) with values false, true, false, true for A, B, C, D respectively yields the result false.
From the algorithm point of view, to parse an expression, you need one stack.
We use two steps algorithm :
Lexing
The aim of lexing is to get 'keywords', 'identifiers' and 'separators' :
- A keyword is 'if' 'then' 'else' '(' ')' '/\' '/' etc...
- An identifiers in your case is 'A', 'B', 'C' etc...
- A separator is blank space, tabulation, end of line, end of file, etc...
Lexing consist of using an automata. In lexing you will read your input string char by char. When you encouter a char that is compatible with one of your keyword, identifiers, separators, you start a sequence of char. When you encouter a separators you stop the sequence, look in a dictionnary of the sequence is a keyword (if not it is a identifier); then put the tuple [sequence, keyword or identifier/class] on the stack.
I leave you as exercice the case of small keyword '(' that can be also see as separators.
Parsing
Parsing is similar to grammar. In your case the only rules to check are comma, and binary operations, and just a simple identifier.
formaly :
expression::
'(' expression ')'
expression /\ expression
expression \/ expression
identifier
This can be write by a recursive function.
First reverse your stack, then:
myParseExpression(stack, myC#ResultObject)
{
if(stack.top = kewyord.'(' )
then myParseOpenComma(all stack but top, myC#ResultObject)
if(stack.top = keyword.'/\')
then myParseBinaryAnd(stack, myC#ResultObject)
}
myParseOpenComma(stack, myC#ResultObject)
{
...
}
myParseBinaryAnd(stack, myC#ResultObject)
{
myNewRigthPartOfExpr = new C#ResultObject
myParseExpression(stack.top, myNewRigthPartOfExpr)
remove top of stack;
myNewLeftPartOfExpr = new C#ResultObject
myParseExpression(stack.top, myNewLeftPartOfExpr)
C#ResultObject.add("AND", myNewRigthPartOfExpr, myNewLeftPartOfExpr)
}
...
There is multiple function that share recursion on each other.
As exercice, try to add the negation.
Lexing is traditionnally done by a lexer (like lex tool).
Parsing is traditionnaly done by a parser (like bison tool).
Tool allow write of thoses function more like I have done in the formaly expression.
Thoses aspect are fundamental of program compilation.
Coding thoses thing will improve you a lot because it is hard and fundamental.