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();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/Lexer.fu
12
src/Lexer.fu
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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).
|
// 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
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