From 3015ea4677201060777435cf76815e898d221f8c Mon Sep 17 00:00:00 2001
From: Mike Buland <eichlan@xagasoft.com>
Date: Thu, 1 Dec 2016 09:31:45 -0700
Subject: The parser works.

There's still more to do, however.  It doesn't do math anymore, it produces
a script that can then be executed.  Now we have to capture that script and
execute it.
---
 src/lexer.cpp  |  24 ++-----
 src/parser.cpp | 213 +++++++++++++++++++++++++++++++++++++++++++++++----------
 src/parser.h   |   4 +-
 src/token.cpp  |  12 ++++
 src/token.h    |   4 +-
 5 files changed, 201 insertions(+), 56 deletions(-)

diff --git a/src/lexer.cpp b/src/lexer.cpp
index 538e088..87d603a 100644
--- a/src/lexer.cpp
+++ b/src/lexer.cpp
@@ -6,7 +6,7 @@
 
 Lexer::Lexer( Bu::Stream &rIn ) :
     rIn( rIn ),
-    iBufPos( 0 ),
+    iBufPos( -1 ),
     iScale( 0 ),
     iRadix( 10 ),
     numRangeTop('9'),
@@ -55,28 +55,12 @@ void Lexer::fillToken()
         default:
             throw Bu::ExceptionBase("Invalid mode.");
     }
-/*
-    Bu::sio << "read["
-        << ((iLookAheadUsed+iLookAheadStart)%iLookAheadSize)
-        << "]: "
-        << aLookAhead[(iLookAheadUsed+iLookAheadStart)%iLookAheadSize].eType;
-    if( aLookAhead[(iLookAheadUsed+iLookAheadStart)%iLookAheadSize].eType == Token::tNumber )
-    Bu::sio << "("
-        << aLookAhead[(iLookAheadUsed+iLookAheadStart)%iLookAheadSize].nVal->toString() << ")";
-    Bu::sio << Bu::sio.nl;
-*/
 }
 
 Token Lexer::nextTokenNormal()
 {
     for(;;)
     {
-        if( iBufPos >= sBuf.getSize() )
-        {
-            iBufPos = -1;
-            return Token( Token::tEndOfLine );
-        }
-
         if( iBufPos < 0 )
         {
             if( rIn.isEos() )
@@ -90,8 +74,12 @@ Token Lexer::nextTokenNormal()
             }
             iBufPos = 0;
         }
+        if( iBufPos >= sBuf.getSize() )
+        {
+            iBufPos = -1;
+            return Token( Token::tEndOfLine );
+        }
 
-        //Bu::println("Testing char '%1' at %2").arg( sBuf[iBufPos] ).arg( iBufPos );
         switch( sBuf[iBufPos] )
         {
             case ' ':
diff --git a/src/parser.cpp b/src/parser.cpp
index 510b471..f88ffe7 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -26,49 +26,34 @@ void Parser::parse()
         if( lex[0].eType == Token::tEndOfInput )
             break;
 
-        expr();
+        exprR();
+        reduce();
 
-        Bu::sio << "Final stack:";
-        for( TokenStack::iterator i = tsParse.begin(); i; i++ )
-        {
-            Bu::sio << " " << (*i).eType;
-            if( (*i).eType == Token::tNumber )
-            {
-                Bu::sio << "(" << (*i).nVal->toString() << ")";
-            }
-        }
-        Bu::sio << Bu::sio.nl;
-        Bu::sio << "Script:";
-        for( TokenStack::iterator i = tsScript.begin(); i; i++ )
-        {
-            Bu::sio << " " << (*i).eType;
-            if( (*i).eType == Token::tNumber )
-            {
-                Bu::sio << "(" << (*i).nVal->toString() << ")";
-            }
-        }
-        Bu::sio << Bu::sio.nl;
+        printState("Final");
+
+        tsParse.clear();
+        tsScript.clear();
     }
 }
 
+void Parser::exprR()
+{
+    exprP();
+    expr();
+}
+
 void Parser::expr()
 {
+    Bu::sio << "::expr " << lex[0] << Bu::sio.nl;
     if( lex[0].eType == Token::tEndOfInput )
         return;
-    if( lex[0].eType == Token::tVariable &&
-        lex[1].eType == Token::tEquals )
-    {
-        Token t = lex[0];
-        lex.nextToken();
-        lex.nextToken();
-        expr();
-
-        return;
-    }
-    exprP();
 
     switch( lex[0].eType )
     {
+        case Token::tEquals:
+            throw Bu::ExceptionBase("misplaced equals.");
+            break;
+
         case Token::tPlus:
         case Token::tMinus:
         case Token::tMultiply:
@@ -76,30 +61,111 @@ void Parser::expr()
         case Token::tModulus:
             Token t = lex[0];
             lex.nextToken();
-            expr();
-            shift( t );
+            Bu::sio << "->expr " << t << " " << lex[0] << Bu::sio.nl;
+            if( lex[0].eType == Token::tOpenParen )
+            {
+                exprP();
+                shift( t );
+                reduce();
+                expr();
+            }
+            else
+            {
+                if( lex[0].eType == Token::tNumber ||
+                    lex[0].eType == Token::tVariable )
+                {
+                    Bu::sio << "->expr " << t <<
+                        " " << lex[0] <<
+                        " " << lex[1] <<
+                        Bu::sio.nl;
+                    shift( lex[0] );
+                    if( lex[1].eType == Token::tPlus ||
+                        lex[1].eType == Token::tMinus ||
+                        lex[1].eType == Token::tDivide ||
+                        lex[1].eType == Token::tMultiply ||
+                        lex[1].eType == Token::tModulus ||
+                        lex[1].eType == Token::tEquals )
+                    {
+                        if( getPriority(lex[1].eType) <=
+                            getPriority(t.eType) )
+                        {
+                            shift( t );
+                            reduce();
+                            printState("reduce");
+                            lex.nextToken();
+                            expr();
+                        }
+                        else
+                        {
+                            printState("no reduce");
+                            lex.nextToken();
+                            expr();
+                            if( !tsParse.isEmpty() &&
+                                tsParse.peek().eType != Token::tComputedValue )
+                            {
+                                reduce();
+                                printState("no reduce reduce");
+                            }
+                            shift( t );
+                            printState("post no reduce");
+                        }
+                    }
+                    else
+                    {
+                        shift( t );
+                        lex.nextToken();
+                        printState("no next op");
+                    }
+                }
+                else
+                {
+                    Bu::println("???");
+                }
+            }
             break;
     }
 }
 
 void Parser::exprP()
 {
+    if( lex[0].eType == Token::tVariable &&
+        lex[1].eType == Token::tEquals )
+    {
+        Token t = lex[0];
+        lex.nextToken( 2 );
+        exprR();
+        reduce();
+        printState("pre-equals");
+        shift( t );
+        shift( Token( Token::tEquals ) );
+        printState("post-equals");
+        reduce();
+        printState("post-equals-reduce");
+        return;
+    }
+
     switch( lex[0].eType )
     {
         case Token::tNumber:
         case Token::tVariable:
-           shift( lex[0] );
+            shift( lex[0] );
             lex.nextToken();
             break;
 
         case Token::tOpenParen:
+            shift( lex[0] );
             lex.nextToken();
-            expr();
+            exprR();
             if( lex[0].eType != Token::tCloseParen )
             {
+                Bu::sio << "::exprP " << lex[0] << Bu::sio.nl;
                 throw Bu::ExceptionBase("Expected close paren");
             }
+            shift( lex[0] );
+            printState("closeParen");
+            reduce();
             lex.nextToken();
+            printState("post closeParen");
             break;
 
         case Token::tMinus:
@@ -206,6 +272,63 @@ void Parser::shift( const Token &t )
 
 void Parser::reduce()
 {
+    if( tsParse.isEmpty() || tsParse.peek().eType == Token::tOpenParen )
+        return;
+    Token tOp = tsParse.peekPop();
+    switch( tOp.eType )
+    {
+        case Token::tNumber:
+        case Token::tVariable:
+            tsScript.append( tOp );
+            tsParse.push( Token( Token::tComputedValue ) );
+            break;
+
+        case Token::tComputedValue:
+            tsParse.push( Token( Token::tComputedValue ) );
+            break;
+
+        case Token::tPlus:
+        case Token::tMinus:
+        case Token::tDivide:
+        case Token::tMultiply:
+        case Token::tModulus:
+        case Token::tEquals:
+            for(int j = 0; j < 2; j++ )
+            {
+                Token t = tsParse.peekPop();
+                if( t.eType == Token::tNumber ||
+                    t.eType == Token::tVariable )
+                {
+                    tsScript.append( t );
+                }
+                else if( t.eType == Token::tComputedValue )
+                {
+                    // Nope, we don't care
+                }
+            }
+            tsScript.append( tOp );
+            shift( Token( Token::tComputedValue ) );
+            break;
+
+        case Token::tCloseParen:
+            if( tsParse.peek().eType != Token::tComputedValue )
+            {
+                printState("paren-innerReduce-pre");
+                reduce();
+                printState("paren-innerReduce-post");
+            }
+            tsParse.pop();
+            if( tsParse.peek().eType == Token::tOpenParen )
+            {
+                tsParse.pop();
+                shift( Token( Token::tComputedValue ) );
+            }
+            else
+            {
+                throw Bu::ExceptionBase("Error?");
+            }
+            break;
+    }
 }
 
 int Parser::reqTokens( Token::Type eType )
@@ -263,3 +386,21 @@ int Parser::getPriority( Token::Type eType )
     }
 }
 
+void Parser::printState( const Bu::String &sTag )
+{
+    Bu::sio << "----------------" << Bu::sio.nl;
+    Bu::sio << sTag << " stack:";
+    for( TokenStack::iterator i = tsParse.begin(); i; i++ )
+    {
+        Bu::sio << " " << (*i);
+    }
+    Bu::sio << Bu::sio.nl;
+    Bu::sio << sTag << " script:";
+    for( TokenStack::iterator i = tsScript.begin(); i; i++ )
+    {
+        Bu::sio << " " << (*i);
+    }
+    Bu::sio << Bu::sio.nl;
+    Bu::sio << "----------------" << Bu::sio.nl;
+}
+
diff --git a/src/parser.h b/src/parser.h
index 1caa229..b0a1231 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -53,13 +53,15 @@ public:
 private:
     void expr();
     void exprP();
+    void exprR();
 
 private:
     void shift( const Token &t );
     void reduce();
     int reqTokens( Token::Type eType );
     int getPriority( Token::Type eType );
-    Number &deref( Token &t );
+
+    void printState( const Bu::String &sTag );
 
 private:
     Lexer &lex;
diff --git a/src/token.cpp b/src/token.cpp
index 1eaa92a..0c7bda1 100644
--- a/src/token.cpp
+++ b/src/token.cpp
@@ -100,8 +100,20 @@ Bu::Formatter &operator<<( Bu::Formatter &f, Token::Type eType )
         case Token::tEndOfLine:     return f << "eol";
         case Token::tEndOfInput:    return f << "eoi";
         case Token::tNegate:        return f << "neg";
+        case Token::tUninitialized: return f << "<->";
+        case Token::tComputedValue: return f << "cmp";
 
         default:                    return f << "???";
     }
 }
 
+Bu::Formatter &operator<<( Bu::Formatter &f, const Token &t )
+{
+    f << t.eType;
+    if( t.eType == Token::tNumber )
+        f << "(" << (t.nVal?t.nVal->toString():"<null>") << ")";
+    else if( t.eType == Token::tString || t.eType == Token::tVariable )
+        f << "(" << (t.sVal?*(t.sVal):"<null>") << ")";
+    return f;
+}
+
diff --git a/src/token.h b/src/token.h
index 8d7dc20..072a96b 100644
--- a/src/token.h
+++ b/src/token.h
@@ -31,7 +31,8 @@ public:
 
         tEndOfInput,
 
-        tUninitialized
+        tUninitialized,
+        tComputedValue
     };
 
     Token();
@@ -52,5 +53,6 @@ public:
 };
 
 Bu::Formatter &operator<<( Bu::Formatter &f, Token::Type eType );
+Bu::Formatter &operator<<( Bu::Formatter &f, const Token &t );
 
 #endif
-- 
cgit v1.2.3