= var4\"). Very simple. The problem is that I do not ha" />
开发者

JavaScript expression parser in Silverlight

Hey everybody! I have a Silverlight project that needs to help users create JavaScript logical expressions (e.g. "var1 != var2 && var3 >= var4"). Very simple. The problem is that I do not have much time to create one myself because tweaking the transition table would be a little time consuming.

So I was searching online for one, but all I found was a couple classes that help you validate the JavaScript, but I need a way to load it, parse it and then write it back. So I was wondering if anyone has any ideas about how I can do it. I am assuming it will not require much code, and it does not have to be a C# example either. If only you could give me some ideas in C++ or even pseudo code, that would help a lot.

Thank you,

V开发者_运维百科ladimir


Create a recursive descent parser by hand. It's fun!

First define a grammar:

Expression -> SimpleExpression ExpressionTail
              (Expression)
SimpleExpression -> Atom Inequality Atom
ExpressionTail -> && Expression |
                  || Expression |
                  e
Atom -> Variable | Literal
Inequality -> == | != | > | >= | < | <=

(This grammar doesn't handle operator precedence, but it is easy to write a grammar that will.)

Next, create a lexical analyzer that will read the input string and create tokens so the string "var1 != 4.0" would be translated to a list of {Variable, !=, Literal}. This can be hacked together, or if you want to get fancy you can use a finite state machine to analyze the string.

Now create a recursive descent parser to parse the list of tokens into an expression tree.

public class Parser {

    public Parser() {
    }

    public Expression parse( LexicalAnalyzer lex) {
        lex.advance();
        return expression( lex);
    }

    private Expression expression( LexicalAnalyzer lex) {  

        switch( lex.current().type() ) {
            case Token.OpenParen:
                lex.advance();
                Expression expression = expression( lex);
                lex.eat( Token.CloseParen);
                return expression;
            case Token.Literal:
            case Token.Variable:
                return expressionTail( lex, simpleExpression(lex));
            default:
                throw new Exception( "ParseError: Expecting (, variable, or literal at character " + 
                                      lex.character());
        }
    }

    private SimpleExpression simpleExpression( LexicalAnalyzer lex) {

        Atom atom = atom( lex);
        switch( lex.current().type() ) {
            case Token.Equal:
                lex.advance();
                return new Equal( atom, atom(lex));
            case Token.NotEqual:
                lex.advance();
                return new NotEqual( atom, atom(lex));
            ...
            default:
                throw new Exception( "ParseError: Expecting ==, !=, <, <=, >, >= at" + 
                                     lex.character());
        }
     }

     private Expression expressionTail( LexicalAnalyzer lex, SimpleExpression expression) {

        switch( lex.current().type() ) {
            case Token.LogicalOr:
                lex.advance();
                return new OrExpression( expression, expression(lex) );
            case Token.LogicalAnd:
                lex.advance();
                return new AndExpression( expression, exptression(lex) );
            default:
                return expression;
        }
     }

     private Atom atom( LexicalAnalyzer lex) {
         switch( lex.current().type() ) {
             case Token.Literal:
                 Literal literal = new Literal( lex.current() );
                 lex.advance();
                 return literal;
             case Token.Variable:
                 Variable var = new Variable( lex.current() );
                 lex.advance();
                 return var;
             default:
                 throw new Exception("ParseError: ...");
          }
      }
}


public interface Expression {
    boolean evaluate( VariableValues values);
}

public interface SimpleExpression implements Expression {
}

public class Equal implements SimpleExpression {
    private final Atom left, right;
    public Equal( Atom left, Atom right) {
        this.left = left;
        this.right = right;
    }
    public boolean evaluate( VariableValues values) {
        return left.evaluate(values) == right.evaluate(values);
    }
}
public class NotEqual implements SimpleExpression {
    private final Atom left, right;
    public NotEqual( Atom left, Atom right) {
        this.left = left;
        this.right = right;
    }
    public boolean evaluate( VariableValues values) {
        return left.evaluate(values) != right.evaluate(values);
    }
}

public class OrExpression implements Expression {
    private final Expression left, right;

    public OrExpression( Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    public boolean evaluate( VariableValues values) {
        return left.evaluate(values) || right.evaluate(values);
    }
}
public class AndExpression implements Expression {
    private final Expression left, right;

    public AndExpression( Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    public boolean evaluate( VariableValues values) {
        return left.evaluate(values) && right.evaluate(values);
    }
}
public interface Atom {
    double evaluate( VariableValues values);
}
public class Literal implements Atom {
    private final double value;
    public Literal( double value) {
        this.value = value;
    }
    public double evaluate( VariableValues values) {
        return value;
    }
}
public class Variable implements Atom {
    private final String name;
    public Variable( String name) {
        this.name = name;
    }
    public double evaluate( VariableValues values) {
        return values.getValue( name);
    }
}


Here is one written in JavaScript: http://silentmatt.com/parser3.js (from: Javascript parser for simple expression). It will be a pain to port, but it's a start.


There is an implementation of a subset of JavaScript available in C# here at CodeProject.


I did something like this in flash/actionscrpt. I assume it's pretty much the same in Silverlight. After a quick google search I see that RegisterScriptableObject is similar to ActionScript's ExternalInterface. Anyway, here is my example.

This Silverlight example comes pretty close to doing the same thing.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜