Parser.BuildExpressionTree
This commit is contained in:
parent
c3e3b4aed5
commit
cc6cda554c
5
build.sh
5
build.sh
@ -3,14 +3,15 @@ set -eo pipefail
|
|||||||
|
|
||||||
OUT_FILE="out/FusionCalculator.c"
|
OUT_FILE="out/FusionCalculator.c"
|
||||||
BIN_FILE="bin/FusionCalculator.exe"
|
BIN_FILE="bin/FusionCalculator.exe"
|
||||||
|
SRC_FILES="$(find src/ -name '*.fu')"
|
||||||
WARNINGS="-Wall -Wno-unused-value -Wno-unused-function -Wno-unused-variable -Wno-discarded-qualifiers"
|
WARNINGS="-Wall -Wno-unused-value -Wno-unused-function -Wno-unused-variable -Wno-discarded-qualifiers"
|
||||||
INCLUDES="$(pkg-config --cflags glib-2.0)"
|
INCLUDES="$(pkg-config --cflags glib-2.0)"
|
||||||
COMPILER_ARGS="-O0 -g"
|
COMPILER_ARGS="-O0 -g"
|
||||||
LINKER_ARGS="$(pkg-config --libs glib-2.0)"
|
LINKER_ARGS="$(pkg-config --libs glib-2.0) -lm"
|
||||||
|
|
||||||
rm -rf out bin
|
rm -rf out bin
|
||||||
mkdir out bin
|
mkdir out bin
|
||||||
|
|
||||||
fut -l c -o "$OUT_FILE" src/*.fu
|
fut -l c -D C -o "$OUT_FILE" $SRC_FILES
|
||||||
|
|
||||||
gcc $WARNINGS $COMPILER_ARGS "$OUT_FILE" -o "$BIN_FILE" $INCLUDES $LINKER_ARGS
|
gcc $WARNINGS $COMPILER_ARGS "$OUT_FILE" -o "$BIN_FILE" $INCLUDES $LINKER_ARGS
|
||||||
|
|||||||
@ -6,21 +6,17 @@ public static class Calculator
|
|||||||
joined += arg;
|
joined += arg;
|
||||||
}
|
}
|
||||||
double rezult = Calculate(joined);
|
double rezult = Calculate(joined);
|
||||||
// Console.WriteLine(rezult);
|
Console.WriteLine(rezult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double Calculate(string exprStr)
|
public static double Calculate(string exprStr)
|
||||||
{
|
{
|
||||||
Lexer() lexer = { ExprStr = exprStr};
|
Lexer() lexer = { ExprStr = exprStr};
|
||||||
List<Token()> tokens = lexer.Lex();
|
List<Token()> tokens = lexer.Lex();
|
||||||
for(int i = 0; i < tokens.Count; i++){
|
// lexer.PrintTokens();
|
||||||
Token() tok = tokens[i];
|
|
||||||
int tokType = tok.GetType();
|
|
||||||
string() tokStr = tok.GetStr();
|
|
||||||
Console.WriteLine($"'{tokStr}' {tokType:D1}");
|
|
||||||
}
|
|
||||||
Parser() parser = { TokenStorage = tokens };
|
Parser() parser = { TokenStorage = tokens };
|
||||||
IExpression expr = parser.Parse();
|
IExpression expr = parser.Parse();
|
||||||
|
// parser.PrintGraphVizCode();
|
||||||
return expr.Calculate();
|
return expr.Calculate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
abstract class IExpression
|
|
||||||
{
|
|
||||||
internal abstract double Calculate();
|
|
||||||
}
|
|
||||||
|
|
||||||
class NumericExpression : IExpression
|
|
||||||
{
|
|
||||||
double N;
|
|
||||||
internal override double Calculate() => N;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class OperatorExpression : IExpression
|
|
||||||
{
|
|
||||||
IExpression a;
|
|
||||||
IExpression b;
|
|
||||||
|
|
||||||
internal abstract double OperatorImplementation(double a, double b);
|
|
||||||
|
|
||||||
internal override double Calculate() => OperatorImplementation(a.Calculate(), b.Calculate());
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class FunctionCallExpression : IExpression
|
|
||||||
{
|
|
||||||
IExpression x;
|
|
||||||
|
|
||||||
internal abstract double FunctionImplementation(double x);
|
|
||||||
|
|
||||||
internal override double Calculate() => FunctionImplementation(x.Calculate());
|
|
||||||
}
|
|
||||||
36
src/Expressions/FunctionCallExpression.fu
Normal file
36
src/Expressions/FunctionCallExpression.fu
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
abstract class FunctionCallExpression : IExpression
|
||||||
|
{
|
||||||
|
IExpression X;
|
||||||
|
|
||||||
|
internal void Init!(IExpression x){
|
||||||
|
X = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract double FunctionImplementation(double x);
|
||||||
|
|
||||||
|
internal override double Calculate() => FunctionImplementation(X.Calculate());
|
||||||
|
}
|
||||||
|
|
||||||
|
class FunctionCallExpressionSin : FunctionCallExpression {
|
||||||
|
internal override double FunctionImplementation(double x) => Math.Sin(x);
|
||||||
|
}
|
||||||
|
class FunctionCallExpressionCos : FunctionCallExpression {
|
||||||
|
internal override double FunctionImplementation(double x) => Math.Cos(x);
|
||||||
|
}
|
||||||
|
class FunctionCallExpressionTan : FunctionCallExpression {
|
||||||
|
internal override double FunctionImplementation(double x) => Math.Tan(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FunctionCallExpressionAsin : FunctionCallExpression {
|
||||||
|
internal override double FunctionImplementation(double x) => Math.Asin(x);
|
||||||
|
}
|
||||||
|
class FunctionCallExpressionAcos : FunctionCallExpression {
|
||||||
|
internal override double FunctionImplementation(double x) => Math.Acos(x);
|
||||||
|
}
|
||||||
|
class FunctionCallExpressionAtan : FunctionCallExpression {
|
||||||
|
internal override double FunctionImplementation(double x) => Math.Atan(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FunctionCallExpressionLog : FunctionCallExpression{
|
||||||
|
internal override double FunctionImplementation(double x) => Math.Log(x);
|
||||||
|
}
|
||||||
4
src/Expressions/IExpression.fu
Normal file
4
src/Expressions/IExpression.fu
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
abstract class IExpression
|
||||||
|
{
|
||||||
|
internal abstract double Calculate();
|
||||||
|
}
|
||||||
5
src/Expressions/NumericalExpression.fu
Normal file
5
src/Expressions/NumericalExpression.fu
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class NumericExpression : IExpression
|
||||||
|
{
|
||||||
|
double N;
|
||||||
|
internal override double Calculate() => N;
|
||||||
|
}
|
||||||
51
src/Expressions/OperatorExpression.fu
Normal file
51
src/Expressions/OperatorExpression.fu
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
abstract class OperatorExpression : IExpression
|
||||||
|
{
|
||||||
|
IExpression A;
|
||||||
|
IExpression B;
|
||||||
|
|
||||||
|
internal void Init!(IExpression a, IExpression b) {
|
||||||
|
A = a;
|
||||||
|
B = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract double OperatorImplementation(double a, double b);
|
||||||
|
|
||||||
|
internal override double Calculate() => OperatorImplementation(A.Calculate(), B.Calculate());
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorExpressionAdd : OperatorExpression {
|
||||||
|
internal override double OperatorImplementation(double a, double b) => a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorExpressionSub : OperatorExpression {
|
||||||
|
internal override double OperatorImplementation(double a, double b) => a-b;
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorExpressionMul : OperatorExpression {
|
||||||
|
internal override double OperatorImplementation(double a, double b) => a*b;
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorExpressionDiv : OperatorExpression {
|
||||||
|
internal override double OperatorImplementation(double a, double b) => a/b;
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorExpressionMod : OperatorExpression {
|
||||||
|
// returns if b>0 then returns a%b else returns a
|
||||||
|
internal override double OperatorImplementation(double a, double b) {
|
||||||
|
if(b <= 0)
|
||||||
|
return a;
|
||||||
|
if(a > 0){
|
||||||
|
while(a >= b)
|
||||||
|
a -= b;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while(a <= b)
|
||||||
|
a += b;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorExpressionPow : OperatorExpression {
|
||||||
|
internal override double OperatorImplementation(double a, double b) => Math.Pow(a, b);
|
||||||
|
}
|
||||||
@ -27,6 +27,15 @@ class Lexer
|
|||||||
TokSub = Token.Create("-", 0, 1, Token.Type_OperatorSub);
|
TokSub = Token.Create("-", 0, 1, Token.Type_OperatorSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void PrintTokens(){
|
||||||
|
for(int i = 0; i < TokenStorage.Count; i++){
|
||||||
|
Token() tok = TokenStorage[i];
|
||||||
|
int tokType = tok.GetType();
|
||||||
|
string() tokStr = tok.GetStr();
|
||||||
|
Console.WriteLine($"'{tokStr}' {tokType:D1}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal List<Token()> Lex!()
|
internal List<Token()> Lex!()
|
||||||
{
|
{
|
||||||
while (i < ExprStr.Length)
|
while (i < ExprStr.Length)
|
||||||
|
|||||||
116
src/Parser.fu
116
src/Parser.fu
@ -1,18 +1,27 @@
|
|||||||
class Parser
|
class Parser
|
||||||
{
|
{
|
||||||
List<Token()> TokenStorage;
|
List<Token()> TokenStorage;
|
||||||
Stack<Token>() RPNStack;
|
IExpression# RootExpression;
|
||||||
IExpression# RootNode;
|
|
||||||
TokenLinkedList() TokensInRPN;
|
TokenLinkedList() TokensInRPN;
|
||||||
|
|
||||||
|
internal Parser(){
|
||||||
|
RootExpression = new NumericExpression { N = Math.NaN };
|
||||||
|
}
|
||||||
|
|
||||||
internal IExpression# Parse!(){
|
internal IExpression# Parse!(){
|
||||||
SortTokensInRPN();
|
SortTokensInRPN();
|
||||||
BuildTreeFromRPN();
|
BuildExpressionTree();
|
||||||
return RootNode;
|
return RootExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void PrintGraphVizCode(){
|
||||||
|
string() graphviz = TokensInRPN.ToGraphVizCode();
|
||||||
|
Console.WriteLine(graphviz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of https://en.wikipedia.org/wiki/Shunting_yard_algorithm
|
// Implementation of https://en.wikipedia.org/wiki/Shunting_yard_algorithm
|
||||||
void SortTokensInRPN!(){
|
void SortTokensInRPN!(){
|
||||||
|
Stack<Token>() RPNStack;
|
||||||
for(int i = 0; i < TokenStorage.Count; i++){
|
for(int i = 0; i < TokenStorage.Count; i++){
|
||||||
Token tok = TokenStorage[i];
|
Token tok = TokenStorage[i];
|
||||||
int type = tok.GetType();
|
int type = tok.GetType();
|
||||||
@ -38,15 +47,18 @@ class Parser
|
|||||||
case Token.Type_BracketClose:
|
case Token.Type_BracketClose:
|
||||||
while(RPNStack.Count != 0){
|
while(RPNStack.Count != 0){
|
||||||
Token op2 = RPNStack.Pop();
|
Token op2 = RPNStack.Pop();
|
||||||
|
if(op2.GetType() == Token.Type_BracketOpen){
|
||||||
|
break;
|
||||||
|
}
|
||||||
TokensInRPN.AddToEnd(op2);
|
TokensInRPN.AddToEnd(op2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Token.Type_Literal:
|
case Token.Type_Literal:
|
||||||
// not implemented
|
ThrowError("not implemented");
|
||||||
assert false;
|
break;
|
||||||
default:
|
default:
|
||||||
// unexpected token type
|
ThrowError("unexpected token type");
|
||||||
assert false;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,9 +69,89 @@ class Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildTreeFromRPN!(){
|
// Implementation of https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D0%B0%D1%8F_%D0%BF%D0%BE%D0%BB%D1%8C%D1%81%D0%BA%D0%B0%D1%8F_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D1%8C#%D0%9E%D0%B1%D1%89%D0%B8%D0%B9_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA
|
||||||
RootNode = new NumericExpression { N = 0 };
|
void BuildExpressionTree!(){
|
||||||
string() graphviz = TokensInRPN.ToGraphVizCode();
|
Stack<IExpression#>() expressionStack;
|
||||||
Console.WriteLine(graphviz);
|
|
||||||
|
TokenLinkedListNode? tokenNode = TokensInRPN.GetFirstNode();
|
||||||
|
while(tokenNode != null){
|
||||||
|
Token tok = tokenNode.GetValue();
|
||||||
|
|
||||||
|
switch(tok.GetType()){
|
||||||
|
case Token.Type_Number:
|
||||||
|
expressionStack.Push(new NumericExpression { N = StringToDouble(tok.GetStr()) });
|
||||||
|
break;
|
||||||
|
case Token.Type_OperatorPow:
|
||||||
|
PushOperatorExpression(expressionStack, tok, new OperatorExpressionPow());
|
||||||
|
break;
|
||||||
|
case Token.Type_OperatorMul:
|
||||||
|
PushOperatorExpression(expressionStack, tok, new OperatorExpressionMul());
|
||||||
|
break;
|
||||||
|
case Token.Type_OperatorDiv:
|
||||||
|
PushOperatorExpression(expressionStack, tok, new OperatorExpressionDiv());
|
||||||
|
break;
|
||||||
|
case Token.Type_OperatorMod:
|
||||||
|
PushOperatorExpression(expressionStack, tok, new OperatorExpressionMod());
|
||||||
|
break;
|
||||||
|
case Token.Type_OperatorAdd:
|
||||||
|
PushOperatorExpression(expressionStack, tok, new OperatorExpressionAdd());
|
||||||
|
break;
|
||||||
|
case Token.Type_OperatorSub:
|
||||||
|
PushOperatorExpression(expressionStack, tok, new OperatorExpressionSub());
|
||||||
|
break;
|
||||||
|
case Token.Type_BracketClose:
|
||||||
|
case Token.Type_BracketOpen:
|
||||||
|
ThrowError("brackets should be handled at SortTokensInRPN");
|
||||||
|
break;
|
||||||
|
case Token.Type_Literal:
|
||||||
|
ThrowError("not implemented");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ThrowError("unexpected token type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenNode = tokenNode.GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(expressionStack.Count == 1)
|
||||||
|
RootExpression = expressionStack.Pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the number or NaN
|
||||||
|
static double StringToDouble(string s){
|
||||||
|
double d = Math.NaN;
|
||||||
|
#if C
|
||||||
|
native{
|
||||||
|
d = strtod(s, NULL);
|
||||||
|
}
|
||||||
|
#elif CS
|
||||||
|
native {
|
||||||
|
d = Convert.ToDouble(s, System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
native {
|
||||||
|
#error "UNKNOWN PROGRAMMING LANGUAGE (define C or CS)";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushOperatorExpression(Stack<IExpression#>! expressionStack, Token tok, OperatorExpression# opExpr) {
|
||||||
|
if(expressionStack.Count < 2){
|
||||||
|
ThrowError("input error: unexpected operator "+tok.GetStr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IExpression b = expressionStack.Pop();
|
||||||
|
IExpression a = expressionStack.Pop();
|
||||||
|
opExpr.Init(a, b);
|
||||||
|
expressionStack.Push(opExpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ThrowError(string errmsg){
|
||||||
|
#if C
|
||||||
|
Console.WriteLine("ERROR: "+errmsg);
|
||||||
|
#endif
|
||||||
|
assert false, errmsg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/Token.fu
16
src/Token.fu
@ -7,14 +7,14 @@ class Token
|
|||||||
// The Type is also the priority of the token in calculation (see Parser).
|
// The Type is also the priority of the token in calculation (see Parser).
|
||||||
int Type;
|
int Type;
|
||||||
|
|
||||||
public const int Type_BracketOpen=10;
|
public const int Type_OperatorPow=10;
|
||||||
public const int Type_BracketClose=9;
|
public const int Type_OperatorMul=9;
|
||||||
public const int Type_OperatorPow=8;
|
public const int Type_OperatorMod=8;
|
||||||
public const int Type_OperatorMul=7;
|
public const int Type_OperatorDiv=7;
|
||||||
public const int Type_OperatorMod=6;
|
public const int Type_OperatorAdd=6;
|
||||||
public const int Type_OperatorDiv=5;
|
public const int Type_OperatorSub=5;
|
||||||
public const int Type_OperatorAdd=4;
|
public const int Type_BracketOpen=4;
|
||||||
public const int Type_OperatorSub=3;
|
public const int Type_BracketClose=3;
|
||||||
public const int Type_Number=2;
|
public const int Type_Number=2;
|
||||||
public const int Type_Literal=1;
|
public const int Type_Literal=1;
|
||||||
|
|
||||||
|
|||||||
@ -57,6 +57,9 @@ class TokenLinkedList {
|
|||||||
// enumerating the tree from FirstNode
|
// enumerating the tree from FirstNode
|
||||||
while(nextNode != null){
|
while(nextNode != null){
|
||||||
string() nextTokStr = nextNode.GetValue().GetStr();
|
string() nextTokStr = nextNode.GetValue().GetStr();
|
||||||
|
// % is an escape character in GraphViz
|
||||||
|
if(nextTokStr[0]=='%')
|
||||||
|
nextTokStr = "\\" + nextTokStr;
|
||||||
string() nextNodeName = "\"";
|
string() nextNodeName = "\"";
|
||||||
nextNodeName += nextTokStr;
|
nextNodeName += nextTokStr;
|
||||||
nextNodeName += "\"";
|
nextNodeName += "\"";
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user