Parser.SortTokensInRPN and TokenLinkedList
This commit is contained in:
parent
05cfeb2bda
commit
c3e3b4aed5
@ -19,8 +19,8 @@ public static class Calculator
|
||||
string() tokStr = tok.GetStr();
|
||||
Console.WriteLine($"'{tokStr}' {tokType:D1}");
|
||||
}
|
||||
Parser() parser = { Tokens = tokens };
|
||||
IExpression# expr = parser.Parse();
|
||||
Parser() parser = { TokenStorage = tokens };
|
||||
IExpression expr = parser.Parse();
|
||||
return expr.Calculate();
|
||||
}
|
||||
}
|
||||
|
||||
12
src/Lexer.fu
12
src/Lexer.fu
@ -2,7 +2,7 @@ class Lexer
|
||||
{
|
||||
string ExprStr;
|
||||
|
||||
List<Token()>() tokens;
|
||||
List<Token()>() TokenStorage;
|
||||
int tokType = Token.Type_Number;
|
||||
int tokBegin = 0;
|
||||
int i = 0;
|
||||
@ -62,7 +62,7 @@ class Lexer
|
||||
|
||||
// end last token
|
||||
TryEndToken();
|
||||
return tokens;
|
||||
return TokenStorage;
|
||||
}
|
||||
|
||||
void TryEndToken!()
|
||||
@ -70,8 +70,8 @@ class Lexer
|
||||
if (tokBegin != i)
|
||||
{
|
||||
Token() tok = Token.Create(ExprStr, tokBegin, i - tokBegin, tokType);
|
||||
tokens.Add();
|
||||
tokens[tokens.Count-1] = tok;
|
||||
TokenStorage.Add();
|
||||
TokenStorage[TokenStorage.Count-1] = tok;
|
||||
tokType = Token.Type_Number;
|
||||
tokBegin = i;
|
||||
}
|
||||
@ -80,8 +80,8 @@ class Lexer
|
||||
void AddStaticToken!(Token() tok)
|
||||
{
|
||||
TryEndToken();
|
||||
tokens.Add();
|
||||
tokens[tokens.Count-1] = tok;
|
||||
TokenStorage.Add();
|
||||
TokenStorage[TokenStorage.Count-1] = tok;
|
||||
tokType = Token.Type_Number;
|
||||
tokBegin = ++i;
|
||||
}
|
||||
|
||||
@ -1,9 +1,65 @@
|
||||
class Parser
|
||||
{
|
||||
List<Token()> Tokens;
|
||||
List<Token()> TokenStorage;
|
||||
Stack<Token>() RPNStack;
|
||||
IExpression# RootNode;
|
||||
TokenLinkedList() TokensInRPN;
|
||||
|
||||
internal IExpression# Parse(){
|
||||
NumericExpression# n = new NumericExpression { N = 1 };
|
||||
return n;
|
||||
internal IExpression# Parse!(){
|
||||
SortTokensInRPN();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
20
src/Token.fu
20
src/Token.fu
@ -7,16 +7,16 @@ class Token
|
||||
// The Type is also the priority of the token in calculation (see Parser).
|
||||
int Type;
|
||||
|
||||
public const int Type_BracketOpen=1;
|
||||
public const int Type_BracketClose=2;
|
||||
public const int Type_OperatorPow=3;
|
||||
public const int Type_OperatorMul=4;
|
||||
public const int Type_OperatorMod=5;
|
||||
public const int Type_OperatorDiv=6;
|
||||
public const int Type_OperatorAdd=7;
|
||||
public const int Type_OperatorSub=8;
|
||||
public const int Type_Number=9;
|
||||
public const int Type_Literal=10;
|
||||
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_Number=2;
|
||||
public const int Type_Literal=1;
|
||||
|
||||
internal static Token() Create(string str, int startIndex, int length, int type){
|
||||
Token() tok = {
|
||||
|
||||
74
src/TokenLinkedList.fu
Normal file
74
src/TokenLinkedList.fu
Normal 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;
|
||||
}
|
||||
}
|
||||
26
src/TokenLinkedListNode.fu
Normal file
26
src/TokenLinkedListNode.fu
Normal 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);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user