Parser.BuildExpressionTree

This commit is contained in:
Timerix22 2023-12-22 20:17:56 +06:00
parent c3e3b4aed5
commit cc6cda554c
11 changed files with 226 additions and 58 deletions

View File

@ -3,14 +3,15 @@ set -eo pipefail
OUT_FILE="out/FusionCalculator.c"
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"
INCLUDES="$(pkg-config --cflags glib-2.0)"
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
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

View File

@ -6,21 +6,17 @@ public static class Calculator
joined += arg;
}
double rezult = Calculate(joined);
// Console.WriteLine(rezult);
Console.WriteLine(rezult);
}
public static double Calculate(string exprStr)
{
Lexer() lexer = { ExprStr = exprStr};
List<Token()> tokens = lexer.Lex();
for(int i = 0; i < tokens.Count; i++){
Token() tok = tokens[i];
int tokType = tok.GetType();
string() tokStr = tok.GetStr();
Console.WriteLine($"'{tokStr}' {tokType:D1}");
}
// lexer.PrintTokens();
Parser() parser = { TokenStorage = tokens };
IExpression expr = parser.Parse();
// parser.PrintGraphVizCode();
return expr.Calculate();
}
}

View File

@ -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());
}

View 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);
}

View File

@ -0,0 +1,4 @@
abstract class IExpression
{
internal abstract double Calculate();
}

View File

@ -0,0 +1,5 @@
class NumericExpression : IExpression
{
double N;
internal override double Calculate() => N;
}

View 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);
}

View File

@ -27,6 +27,15 @@ class Lexer
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!()
{
while (i < ExprStr.Length)

View File

@ -1,18 +1,27 @@
class Parser
{
List<Token()> TokenStorage;
Stack<Token>() RPNStack;
IExpression# RootNode;
IExpression# RootExpression;
TokenLinkedList() TokensInRPN;
internal Parser(){
RootExpression = new NumericExpression { N = Math.NaN };
}
internal IExpression# Parse!(){
SortTokensInRPN();
BuildTreeFromRPN();
return RootNode;
BuildExpressionTree();
return RootExpression;
}
internal void PrintGraphVizCode(){
string() graphviz = TokensInRPN.ToGraphVizCode();
Console.WriteLine(graphviz);
}
// Implementation of https://en.wikipedia.org/wiki/Shunting_yard_algorithm
void SortTokensInRPN!(){
Stack<Token>() RPNStack;
for(int i = 0; i < TokenStorage.Count; i++){
Token tok = TokenStorage[i];
int type = tok.GetType();
@ -38,15 +47,18 @@ class Parser
case Token.Type_BracketClose:
while(RPNStack.Count != 0){
Token op2 = RPNStack.Pop();
if(op2.GetType() == Token.Type_BracketOpen){
break;
}
TokensInRPN.AddToEnd(op2);
}
break;
case Token.Type_Literal:
// not implemented
assert false;
ThrowError("not implemented");
break;
default:
// unexpected token type
assert false;
ThrowError("unexpected token type");
break;
}
}
@ -57,9 +69,89 @@ class Parser
}
}
void BuildTreeFromRPN!(){
RootNode = new NumericExpression { N = 0 };
string() graphviz = TokensInRPN.ToGraphVizCode();
Console.WriteLine(graphviz);
// 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
void BuildExpressionTree!(){
Stack<IExpression#>() expressionStack;
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;
}
}

View File

@ -7,14 +7,14 @@ class Token
// The Type is also the priority of the token in calculation (see Parser).
int Type;
public const int Type_BracketOpen=10;
public const int Type_BracketClose=9;
public const int Type_OperatorPow=8;
public const int Type_OperatorMul=7;
public const int Type_OperatorMod=6;
public const int Type_OperatorDiv=5;
public const int Type_OperatorAdd=4;
public const int Type_OperatorSub=3;
public const int Type_OperatorPow=10;
public const int Type_OperatorMul=9;
public const int Type_OperatorMod=8;
public const int Type_OperatorDiv=7;
public const int Type_OperatorAdd=6;
public const int Type_OperatorSub=5;
public const int Type_BracketOpen=4;
public const int Type_BracketClose=3;
public const int Type_Number=2;
public const int Type_Literal=1;

View File

@ -57,6 +57,9 @@ class TokenLinkedList {
// enumerating the tree from FirstNode
while(nextNode != null){
string() nextTokStr = nextNode.GetValue().GetStr();
// % is an escape character in GraphViz
if(nextTokStr[0]=='%')
nextTokStr = "\\" + nextTokStr;
string() nextNodeName = "\"";
nextNodeName += nextTokStr;
nextNodeName += "\"";