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"
|
||||
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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
116
src/Parser.fu
116
src/Parser.fu
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
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).
|
||||
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;
|
||||
|
||||
|
||||
@ -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 += "\"";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user