Parser.SortTokensInRPN and TokenLinkedList

This commit is contained in:
Timerix22 2023-12-22 16:57:17 +06:00
parent 05cfeb2bda
commit c3e3b4aed5
6 changed files with 178 additions and 22 deletions

View File

@ -19,8 +19,8 @@ public static class Calculator
string() tokStr = tok.GetStr(); string() tokStr = tok.GetStr();
Console.WriteLine($"'{tokStr}' {tokType:D1}"); Console.WriteLine($"'{tokStr}' {tokType:D1}");
} }
Parser() parser = { Tokens = tokens }; Parser() parser = { TokenStorage = tokens };
IExpression# expr = parser.Parse(); IExpression expr = parser.Parse();
return expr.Calculate(); return expr.Calculate();
} }
} }

View File

@ -2,7 +2,7 @@ class Lexer
{ {
string ExprStr; string ExprStr;
List<Token()>() tokens; List<Token()>() TokenStorage;
int tokType = Token.Type_Number; int tokType = Token.Type_Number;
int tokBegin = 0; int tokBegin = 0;
int i = 0; int i = 0;
@ -62,7 +62,7 @@ class Lexer
// end last token // end last token
TryEndToken(); TryEndToken();
return tokens; return TokenStorage;
} }
void TryEndToken!() void TryEndToken!()
@ -70,8 +70,8 @@ class Lexer
if (tokBegin != i) if (tokBegin != i)
{ {
Token() tok = Token.Create(ExprStr, tokBegin, i - tokBegin, tokType); Token() tok = Token.Create(ExprStr, tokBegin, i - tokBegin, tokType);
tokens.Add(); TokenStorage.Add();
tokens[tokens.Count-1] = tok; TokenStorage[TokenStorage.Count-1] = tok;
tokType = Token.Type_Number; tokType = Token.Type_Number;
tokBegin = i; tokBegin = i;
} }
@ -80,8 +80,8 @@ class Lexer
void AddStaticToken!(Token() tok) void AddStaticToken!(Token() tok)
{ {
TryEndToken(); TryEndToken();
tokens.Add(); TokenStorage.Add();
tokens[tokens.Count-1] = tok; TokenStorage[TokenStorage.Count-1] = tok;
tokType = Token.Type_Number; tokType = Token.Type_Number;
tokBegin = ++i; tokBegin = ++i;
} }

View File

@ -1,9 +1,65 @@
class Parser class Parser
{ {
List<Token()> Tokens; List<Token()> TokenStorage;
Stack<Token>() RPNStack;
IExpression# RootNode;
TokenLinkedList() TokensInRPN;
internal IExpression# Parse(){ internal IExpression# Parse!(){
NumericExpression# n = new NumericExpression { N = 1 }; SortTokensInRPN();
return n; BuildTreeFromRPN();
return RootNode;
}
// Implementation of https://en.wikipedia.org/wiki/Shunting_yard_algorithm
void SortTokensInRPN!(){
for(int i = 0; i < TokenStorage.Count; i++){
Token tok = TokenStorage[i];
int type = tok.GetType();
switch(type){
case Token.Type_Number:
TokensInRPN.AddToEnd(tok);
break;
case Token.Type_OperatorPow:
case Token.Type_OperatorMul:
case Token.Type_OperatorDiv:
case Token.Type_OperatorMod:
case Token.Type_OperatorAdd:
case Token.Type_OperatorSub:
while(RPNStack.Count != 0 && RPNStack.Peek().GetType() >= type){
Token op2 = RPNStack.Pop();
TokensInRPN.AddToEnd(op2);
}
RPNStack.Push(tok);
break;
case Token.Type_BracketOpen:
RPNStack.Push(tok);
break;
case Token.Type_BracketClose:
while(RPNStack.Count != 0){
Token op2 = RPNStack.Pop();
TokensInRPN.AddToEnd(op2);
}
break;
case Token.Type_Literal:
// not implemented
assert false;
default:
// unexpected token type
assert false;
}
}
// add remaining operators
while(RPNStack.Count != 0){
Token op2 = RPNStack.Pop();
TokensInRPN.AddToEnd(op2);
}
}
void BuildTreeFromRPN!(){
RootNode = new NumericExpression { N = 0 };
string() graphviz = TokensInRPN.ToGraphVizCode();
Console.WriteLine(graphviz);
} }
} }

View File

@ -7,16 +7,16 @@ 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=1; public const int Type_BracketOpen=10;
public const int Type_BracketClose=2; public const int Type_BracketClose=9;
public const int Type_OperatorPow=3; public const int Type_OperatorPow=8;
public const int Type_OperatorMul=4; public const int Type_OperatorMul=7;
public const int Type_OperatorMod=5; public const int Type_OperatorMod=6;
public const int Type_OperatorDiv=6; public const int Type_OperatorDiv=5;
public const int Type_OperatorAdd=7; public const int Type_OperatorAdd=4;
public const int Type_OperatorSub=8; public const int Type_OperatorSub=3;
public const int Type_Number=9; public const int Type_Number=2;
public const int Type_Literal=10; public const int Type_Literal=1;
internal static Token() Create(string str, int startIndex, int length, int type){ internal static Token() Create(string str, int startIndex, int length, int type){
Token() tok = { Token() tok = {

74
src/TokenLinkedList.fu Normal file
View File

@ -0,0 +1,74 @@
class TokenLinkedList {
TokenLinkedListNode!? FirstNode = null;
TokenLinkedListNode!? LastNode = null;
List<TokenLinkedListNode()>() Storage;
internal TokenLinkedListNode! GetFirstNode() => FirstNode;
internal TokenLinkedListNode! GetLastNode() => LastNode;
internal void AddToStart!(Token tok) {
TokenLinkedListNode! node = CreateOrphanedNode(tok);
if(FirstNode == null){
assert LastNode == null;
FirstNode = node;
LastNode = node;
}
else {
assert FirstNode.GetPrev() == null;
FirstNode.SetPrev(node);
FirstNode = node;
}
}
internal void AddToEnd!(Token tok) {
TokenLinkedListNode! node = CreateOrphanedNode(tok);
if(LastNode == null){
assert FirstNode == null;
FirstNode = node;
LastNode = node;
}
else {
assert LastNode.GetNext() == null;
LastNode.SetNext(node);
LastNode = node;
}
}
internal TokenLinkedListNode# CreateOrphanedNode!(Token tok) {
TokenLinkedListNode# sharedPtr = new TokenLinkedListNode {
Value = tok,
Prev = null,
Next = null
};
return sharedPtr;
}
// Can be used by GraphViz to create node graph.
// GraphViz online: https://dreampuf.github.io/GraphvizOnline/
internal string() ToGraphVizCode() {
string() s = "strict digraph {\n" + /* directed graph with no multi-edges */
" start [shape=Mdiamond];\n" + /* 'start' node style */
" end [shape=Msquare];\n" + /* 'end' node style */
" node [style=filled,color=white];\n"; /* regular node style */
TokenLinkedListNode? currentNode = null;
TokenLinkedListNode? nextNode = FirstNode;
string() currentNodeName = "start";
// enumerating the tree from FirstNode
while(nextNode != null){
string() nextTokStr = nextNode.GetValue().GetStr();
string() nextNodeName = "\"";
nextNodeName += nextTokStr;
nextNodeName += "\"";
s += $" {currentNodeName} -> {nextNodeName};\n";
currentNodeName = nextNodeName;
currentNode = nextNode;
nextNode = currentNode.GetNext();
}
if(currentNode == LastNode)
s += $" {currentNodeName} -> end;\n";
s += "}";
return s;
}
}

View File

@ -0,0 +1,26 @@
class TokenLinkedListNode {
Token Value;
TokenLinkedListNode!? Prev = null;
TokenLinkedListNode!? Next = null;
internal Token GetValue() => Value;
internal void SetValue!(Token value) { Value = value; }
internal TokenLinkedListNode!? GetPrev() => Prev;
internal void SetPrev!(TokenLinkedListNode! prev) { Prev = prev; }
internal TokenLinkedListNode!? GetNext() => Next;
internal void SetNext!(TokenLinkedListNode! next) { Next = next; }
internal void InsertAfter!(TokenLinkedListNode! prev){
Next = prev.GetNext();
Prev = prev;
prev.SetNext(this);
}
internal void InsertBefore!(TokenLinkedListNode! next){
Next = next;
Prev = next.GetPrev();
next.SetPrev(this);
}
}