A Mathematical Expression Calculator developed based on the grammar analyzer GOLD Parser and a parser Expression Calculator

Recently found a grammar analysis artifact, read the official website (http://goldparser.org/) after the introduction of the feeling very sharp look, so it was used to test some, write a Mathematical Expression Analysis of small programs, the supported mathematical operators are as follows:

General calculation: +-*/^ sqrt sqrt2 (a, B) pow2 (a) pow (a, B)

Trigonometric function: sin cos tan cot asin acos atan ACO

Exponential logarithm: log2 (a) log10 (a) ln (a) logn (a, B) e ^

Max and min: max (a, B,...) min (a, B ,...)

**I,****GOLD Parser****Introduction**** **

GOLD Parser is a powerful grammar analysis tool, supporting c ++, c, c #, Java, Python, Pascal and other languages, for more information, see the official website http://goldparser.org/

The tool consists of three steps:

**II,****Syntax definition of Mathematical Expressions**

Download the GOLD Parser Builder Tool from the official website and install it as prompted. After installation, you can write the syntax definition. The main interface is as follows. The test tool included in the tool is very powerful. After writing the syntax definition, you can directly test the syntax to generate a syntax tree.

Before writing a syntax description, first familiarize yourself with the basic features of GOLD Meta-Language, which consists of the following parts:

1. Syntax file attribute description

This section describes the information about the syntax file to be compiled, such as the syntax name, author, and version number. The format is as follows:

"Name" = 'my Programming Language'

"Version" = '1. 0 beta'

"Author" = 'John Q. public'

"Start Symbol" = <Statement> // required, indicating the Start of the definition, which can be left empty

2. Character Set Definition

This section describes the character sets used in our Language. Many character sets are pre-defined in GOLD Meta-Language, for example, a common Number set {Number}, a Letter set {Letter}, and a Printable character set {Printable} can also be used to specify the character set range {& 4F00 .. & 99E0} indicates all characters from 4F00 to 99E0. The format is as follows:

{String Char }={ Printable}-["] // indicates that the" character is subtracted from the Printable character.

We can define multiple character sets for the language we define.

3. Terminal Definition

Terminator refers to the smallest unit that can be recognized by the syntax analyzer in our defined language. For example, the following mathematical expression is as follows: 3.3 + sin (a + b1 ), the Terminator is "3.3" "+" "sin" ("" a "" b1 ")". The Terminator is usually defined by a regular expression, if we do not know the regular expression, we strongly recommend that you complete the knowledge of the regular expression. In the syntax file, the terminator of variables and numbers is defined as follows:

Variable = {Letter} {Number} * // represents a Letter followed by 0 or multiple numbers, such as a, B, x1, y34

NumberValue = {Number} + | ({Number} + '.' {Number} *) // indicates an integer or decimal Number.

4. Definition of Productions (this is not easy to translate o (translated □production) o, so it should be expressed in English)

The syntax of the language we describe is defined by a series of Production, and a Production is composed of several terminals and Nonterminal, A non-Terminator is usually defined by Angle brackets, and is defined by several terminologies and non-terminologies. It indicates a Production, indicating the if-then-end statement in the language. <Stm>, <Exp>, <shortts> are non-terminologies, if, then, and end are terminologies.

A series of Production functions of the same type constitute a rule set (Role). the syntax of the language we describe is defined by the rule set. The two representations below are equivalent, is the same rule set.

After familiarizing yourself with the syntax of GOLD Meta-Language, you can start to write the syntax definition of a mathematical expression. The syntax file defined by myself is as follows:

! Welcome to GOLD Parser Builder 5.2 "Name" = 'calculator' "Version" = 'v1. 0 '"Author" = 'xxchen' "Start Symbol" = <Exp> Variable = {Letter} {Number} * NumberValue = {Number} + | ({Number} + '. '{Number} *) <Exp> :: = <Exp> '+' <Exp Mult> | <Exp> '-' <Exp Mult> | <Exp Mult> :: = <Exp Mult> '*' <Value> | <Exp Mult> Variable | <Exp Mult> '/' <Value> | <Value> <Exp Func> :: = <Exp Func1> | <Exp Func2> | <Exp Funcn> <Exp Func1> :: = 'sin' <Value> | 'cos '<Value> | 'tan' <Value> | 'cot' <Value> | 'asin' <Value> | 'acs' <value> | 'ata' <Value> | 'acot' <Value> | 'sqrt '<Value> | 'log2 (' <Value> ') '| 'log10 (' <Value> ')' | 'pow2 ('<Value> ') '| 'e ^' <Value> | 'ln '<Value> <Exp Func2> :: = <ExpValue> '^' <Value> | 'pow ('<Exp>', '<Exp>') '| 'sqrt2 (' <Exp> ', '<Exp>') '| 'logn (' <Exp> ',' <Exp> ')' <Params >::= <Params> ', '<Exp> | <Exp> <Exp Funcn >:: = 'max (' <Params> ')' | 'min ('<Params>') '<Param>:: = NumberValue | Variable <ExpValue >::=< Param> | '-' <Param> | '(' <Exp> ') '|' <Exp> '|' <Value >::= <ExpValue >|< Exp Func>View Code

After writing the script, click the Next button in the lower-right corner of the software to generate a. egt grammar table file without prompting an error. This file will be used in subsequent programming.

**III,****Write code using the parsing Engine**

I am familiar with the c # language, so I use the c # language version of the parsing engine. Other language versions of the engine are also available on the official website. Before writing the code, you can also use the Builder Tool to generate the parsing framework of the corresponding engine. In the Project-Create a Skeleton Program menu, you can open the Wizard to set it, select the corresponding language and resolution engine to generate the corresponding parsing framework.

The automatically generated parsing framework is very simple, as shown below. There are two main functions to note: the first is the Parse function, which accepts a TextReader type parameter, it is used to read the content to be parsed, And the parsing logic in it has been automatically generated. The second is the CreateNewObject function. What we need to modify is this function. During the engine parsing process, we need to generate the required Objects Based on the parsing results of each step to implement the logic we need. Other parts can be modified without affecting the overall framework. Here I add a constructor with parameters. The parameters are the path of the grammar table file, then initialize the parsing engine in the constructor.

To implement the computing logic, a simple expression class is defined here. The constructor of this class can accept a constant, a variable, or several expressions.

/// <Summary> // Expression class // </summary> public class Expression {// <summary> // Initializes a new instance of the <see cref = "Expression"/> class. /// </summary> /// <param name = "value"> accepts a constant </param> public Expression (double value) {_ value = t => value;} // <summary> // Initializes a new instance of the <see cref = "Expression"/> class. /// </summary> /// <param name = "variable"> accepts a variable </param> publi C Expression (string variable) {_ value = t => t [variable]; _ varList = new List <string >{ variable };} /// <summary> // Initializes a new instance of the <see cref = "Expression"/> class. /// </summary> /// <param name = "func"> Expression calculation function </param> /// <param name = "exps"> accepts several expressions </param> public Expression (Func <double [], double> func, params Expression [] exps) {_ value = t => func (exps. select (e => e. _ value (T )). toArray (); foreach (var exp in exps) {if (exp. _ varList = null) continue; if (_ varList = null) _ varList = new List <string> (); _ varList. addRange (exp. _ varList);} if (_ varList! = Null) _ varList = _ varList. distinct (). toList () ;}//< summary> // The linked List storing the variable name /// </summary> private readonly List <string> _ varList; /// <summary> /// get the variable in the expression /// </summary> /// <returns> </returns> public IEnumerable <string> GetVariables () {if (_ varList = null) yield break; foreach (var in _ varList) yield return var ;} /// <summary> // The _ value // </summary> private readonly Func <Dictionary <string, double>, double> _ value; /// <summary> /// obtain the value of the expression, used to calculate the expression without variables /// </summary> /// <returns> System. double. </returns> public double GetValue () {return GetValue (null) ;}/// <summary> // obtain the expression value, used to calculate a variable expression // </summary> /// <param name = "varTable"> parameter table </param> /// <returns> System. double. </returns> public double GetValue (Dictionary <string, double> varTable) {try {return _ value (varTable);} catch (Exception) {return double. naN ;}}}View Code

Let's take a look at the CreateNewObject function generated by the parsing engine. only part of the code is intercepted below, and the logic in it is also very simple. For example, after the engine parses the number, it can follow the annotations, here is // <Param >:: = NumberValue, which indicates that the number of data in r is 1, where r [0]. data corresponds to the value of NumberValue. In this case, we only need to return a constant expression. After the Variable is parsed, the annotated code is // <Param >:: = Variable, and a Variable expression is returned. When the + number is parsed, the corresponding annotation code is // <Exp >::= <Exp> '+' <Exp Mult> indicates that the number of data in r is 3, r [0]. data and r [2]. data is the expression returned when the previous Data is parsed. It corresponds to <Exp> and <Exp Mult>, r [1] in the parsing tree. data is "+", so we need to generate a new addition expression on this node, and then return this expression.

Expression exp1, exp2; switch (ProductionIndex) r. parent. tableIndex () {case ProductionIndex. exp_Plus: // <Exp >::= <Exp> '+' <Exp Mult> exp1 = r [0]. data as Expression; exp2 = r [2]. data as Expression; result = new Expression (t => t [0] + t [1], exp1, exp2); break; case ProductionIndex. exp_Minus: // <Exp >::= <Exp> '-' <Exp Mult> exp1 = r [0]. data as Expression; exp2 = r [2]. data as Expression; result = New Expression (t => t [0]-t [1], exp1, exp2); break; case ProductionIndex. param_Numbervalue: // <Param >:: = NumberValue result = new Expression (double. parse (r [0]. data. toString (); break; case ProductionIndex. param_Variable: // <Param >:: = Variable result = new Expression (r [0]. data. toString (); break ;...... Omitted similar partView Code

At this point, the parsing engine of the mathematical expression has been constructed and used as follows:

// Construct the parsing engine var filePath = Path based on the published file. combine (Directory. getCurrentDirectory (), "calculator. egt "); var parser = new CalculatorParser (filePath); // parse the read string parser. parse (new StringReader (line); // read the parsing result, that is, an expression var exp = parser. exp; // calculated expression value result = exp. getValue ();

**IV,****Lab results**

The program can calculate any expression entered by the user. If the expression is found to be incorrect, it will prompt the user at which location an error occurs. The program can also recognize variables and understand the expression of the variable following the number as a multiplication operation, for example, 3d represents 3 * d. The cos-3-4.d in the figure is understood as cos (-3)-4.0xd, where d is the variable

**V,****Summary**

In general, GOLD Parser is a very powerful grammar analysis tool that can parse arbitrary regular text files, such as xml, json, html, c, c ++, java, c # and so on. The syntax description files of these languages can also be found on the official website (you don't have to write them again ). If you want to parse a new language or data description file, you have to write the syntax description file by yourself. For a language that is not very complex, find some information on the official website, then write the code twice as shown in the example (it took less than one day from getting started with the GOLD Parser to completing the applet ). After the syntax is written, the programming is very simple with the help of the existing parsing engine.

Source code: http://vdisk.weibo.com/s/yVSnUWjONKKp0

[Original] reprinted please explain the source!