summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2016-12-01 10:40:43 -0700
committerMike Buland <eichlan@xagasoft.com>2016-12-01 10:40:43 -0700
commitb96daa4e9849ac9caf5c0dfcea8daac28267ea19 (patch)
tree9be42c8cfe8b875f396b5887742bb936bd081c65
parent4efeaef41e57b25d6004e7f91828f7d5b5cd0b20 (diff)
downloadclic-b96daa4e9849ac9caf5c0dfcea8daac28267ea19.tar.gz
clic-b96daa4e9849ac9caf5c0dfcea8daac28267ea19.tar.bz2
clic-b96daa4e9849ac9caf5c0dfcea8daac28267ea19.tar.xz
clic-b96daa4e9849ac9caf5c0dfcea8daac28267ea19.zip
Scripts are executable now!
The main interactive interface doesn't work, and there's a lot left to do with the unit tests, other command line options, etc. but it's pretty exciting. I also still have to figure out how commands will work. I'm thinking they'll be stored in an Expression and executed by the engine as normal.
-rw-r--r--src/expression.cpp10
-rw-r--r--src/expression.h16
-rw-r--r--src/main.cpp2
-rw-r--r--src/options.cpp9
-rw-r--r--src/parser.cpp65
-rw-r--r--src/parser.h9
-rw-r--r--src/scriptengine.cpp82
-rw-r--r--src/scriptengine.h33
-rw-r--r--src/unitparser.cpp2
9 files changed, 188 insertions, 40 deletions
diff --git a/src/expression.cpp b/src/expression.cpp
new file mode 100644
index 0000000..e167ee7
--- /dev/null
+++ b/src/expression.cpp
@@ -0,0 +1,10 @@
1#include "expression.h"
2
3Expression::Expression()
4{
5}
6
7Expression::~Expression()
8{
9}
10
diff --git a/src/expression.h b/src/expression.h
new file mode 100644
index 0000000..e78b54b
--- /dev/null
+++ b/src/expression.h
@@ -0,0 +1,16 @@
1#ifndef EXPRESSION_H
2#define EXPRESSION_H
3
4#include <bu/list.h>
5#include "token.h"
6
7class Expression : public Bu::List<Token>
8{
9public:
10 Expression();
11 virtual ~Expression();
12
13private:
14};
15
16#endif
diff --git a/src/main.cpp b/src/main.cpp
index 1a4ab38..667d19a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -27,7 +27,7 @@ int main( int argc, char *argv[] )
27 Lexer lex( sioRaw ); 27 Lexer lex( sioRaw );
28 lex.setScale( opt.getScale() ); 28 lex.setScale( opt.getScale() );
29 lex.setRadix( opt.getRadix() ); 29 lex.setRadix( opt.getRadix() );
30 Parser parser( lex, sioRaw ); 30 Parser parser( lex );
31 parser.parse(); 31 parser.parse();
32 } 32 }
33 catch( std::exception &e ) 33 catch( std::exception &e )
diff --git a/src/options.cpp b/src/options.cpp
index 3c016a6..672858a 100644
--- a/src/options.cpp
+++ b/src/options.cpp
@@ -7,6 +7,7 @@
7#include "number.h" 7#include "number.h"
8#include "lexer.h" 8#include "lexer.h"
9#include "parser.h" 9#include "parser.h"
10#include "scriptengine.h"
10 11
11#include <bu/streamstack.h> 12#include <bu/streamstack.h>
12#include <bu/sio.h> 13#include <bu/sio.h>
@@ -197,9 +198,11 @@ int Options::execute( Bu::StringArray aArgs )
197 Lexer lex( mbIn ); 198 Lexer lex( mbIn );
198 lex.setScale( iScale ); 199 lex.setScale( iScale );
199 lex.setRadix( iRadix ); 200 lex.setRadix( iRadix );
200 Parser parser( lex, mbOut ); 201 Parser parser( lex );
201 parser.parse(); 202 Expression *pExp = parser.parse();
202 Bu::print( mbOut.getString() ); 203 ScriptEngine se;
204 Number n = se.exec( pExp );
205 Bu::println( n.toString() );
203 exit( 0 ); 206 exit( 0 );
204 return aArgs.getSize(); 207 return aArgs.getSize();
205} 208}
diff --git a/src/parser.cpp b/src/parser.cpp
index 04a81ce..c7cf994 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -3,14 +3,13 @@
3#include "lexer.h" 3#include "lexer.h"
4#include "number.h" 4#include "number.h"
5#include "datafiles.h" 5#include "datafiles.h"
6#include "expression.h"
6 7
7#include <bu/sio.h> 8#include <bu/sio.h>
8#include <stdlib.h> 9#include <stdlib.h>
9 10
10 11Parser::Parser( Lexer &lex ) :
11Parser::Parser( Lexer &lex, Bu::Stream &rOut ) : 12 lex( lex )
12 lex( lex ),
13 rOut( rOut )
14{ 13{
15} 14}
16 15
@@ -18,22 +17,19 @@ Parser::~Parser()
18{ 17{
19} 18}
20 19
21void Parser::parse() 20Expression *Parser::parse()
22{ 21{
23 for(;;) 22 pCurExp = new Expression();
24 { 23 exprR();
25 lex.nextToken(); 24 reduce();
26 if( lex[0].eType == Token::tEndOfInput )
27 break;
28 25
29 exprR(); 26 printState("Final");
30 reduce();
31 27
32 printState("Final"); 28 tsParse.clear();
33 29
34 tsParse.clear(); 30 Expression *pTmp = pCurExp;
35 tsScript.clear(); 31 pCurExp = NULL;
36 } 32 return pTmp;
37} 33}
38 34
39void Parser::exprR() 35void Parser::exprR()
@@ -44,7 +40,7 @@ void Parser::exprR()
44 40
45void Parser::expr() 41void Parser::expr()
46{ 42{
47 Bu::sio << "::expr " << lex[0] << Bu::sio.nl; 43 //Bu::sio << "::expr " << lex[0] << Bu::sio.nl;
48 if( lex[0].eType == Token::tEndOfInput ) 44 if( lex[0].eType == Token::tEndOfInput )
49 return; 45 return;
50 46
@@ -61,7 +57,7 @@ void Parser::expr()
61 case Token::tModulus: 57 case Token::tModulus:
62 Token t = lex[0]; 58 Token t = lex[0];
63 lex.nextToken(); 59 lex.nextToken();
64 Bu::sio << "->expr " << t << " " << lex[0] << Bu::sio.nl; 60 //Bu::sio << "->expr " << t << " " << lex[0] << Bu::sio.nl;
65 if( lex[0].eType == Token::tOpenParen ) 61 if( lex[0].eType == Token::tOpenParen )
66 { 62 {
67 exprP(); 63 exprP();
@@ -74,10 +70,10 @@ void Parser::expr()
74 if( lex[0].eType == Token::tNumber || 70 if( lex[0].eType == Token::tNumber ||
75 lex[0].eType == Token::tVariable ) 71 lex[0].eType == Token::tVariable )
76 { 72 {
77 Bu::sio << "->expr " << t << 73 //Bu::sio << "->expr " << t <<
78 " " << lex[0] << 74 // " " << lex[0] <<
79 " " << lex[1] << 75 // " " << lex[1] <<
80 Bu::sio.nl; 76 // Bu::sio.nl;
81 shift( lex[0] ); 77 shift( lex[0] );
82 if( lex[1].eType&Token::mMetaOperator ) 78 if( lex[1].eType&Token::mMetaOperator )
83 { 79 {
@@ -115,14 +111,14 @@ void Parser::expr()
115 else if( lex[0].eType == Token::tMinus ) 111 else if( lex[0].eType == Token::tMinus )
116 { 112 {
117 // This is negation 113 // This is negation
118 Bu::sio << "next token: " << lex[0] << Bu::sio.nl; 114 //Bu::sio << "next token: " << lex[0] << Bu::sio.nl;
119 printState("inline-negate"); 115 printState("inline-negate");
120 exprP(); 116 exprP();
121 printState("inline-negate-post"); 117 printState("inline-negate-post");
122 shift( t ); 118 shift( t );
123 printState("inline-negate-post2"); 119 printState("inline-negate-post2");
124 120
125 Bu::sio << "??? " << lex[0] << Bu::sio.nl; 121 //Bu::sio << "??? " << lex[0] << Bu::sio.nl;
126 } 122 }
127 } 123 }
128 break; 124 break;
@@ -161,7 +157,7 @@ void Parser::exprP()
161 exprR(); 157 exprR();
162 if( lex[0].eType != Token::tCloseParen ) 158 if( lex[0].eType != Token::tCloseParen )
163 { 159 {
164 Bu::sio << "::exprP " << lex[0] << Bu::sio.nl; 160 //Bu::sio << "::exprP " << lex[0] << Bu::sio.nl;
165 throw Bu::ExceptionBase("Expected close paren"); 161 throw Bu::ExceptionBase("Expected close paren");
166 } 162 }
167 shift( lex[0] ); 163 shift( lex[0] );
@@ -283,7 +279,7 @@ void Parser::reduce()
283 { 279 {
284 case Token::tNumber: 280 case Token::tNumber:
285 case Token::tVariable: 281 case Token::tVariable:
286 tsScript.append( tOp ); 282 output( tOp );
287 tsParse.push( Token( Token::tComputedValue ) ); 283 tsParse.push( Token( Token::tComputedValue ) );
288 break; 284 break;
289 285
@@ -303,14 +299,14 @@ void Parser::reduce()
303 if( t.eType == Token::tNumber || 299 if( t.eType == Token::tNumber ||
304 t.eType == Token::tVariable ) 300 t.eType == Token::tVariable )
305 { 301 {
306 tsScript.append( t ); 302 output( t );
307 } 303 }
308 else if( t.eType == Token::tComputedValue ) 304 else if( t.eType == Token::tComputedValue )
309 { 305 {
310 // Nope, we don't care 306 // Nope, we don't care
311 } 307 }
312 } 308 }
313 tsScript.append( tOp ); 309 output( tOp );
314 shift( Token( Token::tComputedValue ) ); 310 shift( Token( Token::tComputedValue ) );
315 break; 311 break;
316 312
@@ -318,8 +314,8 @@ void Parser::reduce()
318 { 314 {
319 Token t = tsParse.peekPop(); 315 Token t = tsParse.peekPop();
320 if( t.eType != Token::tComputedValue ) 316 if( t.eType != Token::tComputedValue )
321 tsScript.append( t ); 317 output( t );
322 tsScript.append( tOp ); 318 output( tOp );
323 shift( Token( Token::tComputedValue ) ); 319 shift( Token( Token::tComputedValue ) );
324 } 320 }
325 break; 321 break;
@@ -345,6 +341,11 @@ void Parser::reduce()
345 } 341 }
346} 342}
347 343
344void Parser::output( const Token &t )
345{
346 pCurExp->append( t );
347}
348
348int Parser::reqTokens( Token::Type eType ) 349int Parser::reqTokens( Token::Type eType )
349{ 350{
350 switch( eType ) 351 switch( eType )
@@ -402,6 +403,7 @@ int Parser::getPriority( Token::Type eType )
402 403
403void Parser::printState( const Bu::String &sTag ) 404void Parser::printState( const Bu::String &sTag )
404{ 405{
406 /*
405 Bu::sio << "----------------" << Bu::sio.nl; 407 Bu::sio << "----------------" << Bu::sio.nl;
406 Bu::sio << sTag << " stack:"; 408 Bu::sio << sTag << " stack:";
407 for( TokenStack::iterator i = tsParse.begin(); i; i++ ) 409 for( TokenStack::iterator i = tsParse.begin(); i; i++ )
@@ -410,11 +412,12 @@ void Parser::printState( const Bu::String &sTag )
410 } 412 }
411 Bu::sio << Bu::sio.nl; 413 Bu::sio << Bu::sio.nl;
412 Bu::sio << sTag << " script:"; 414 Bu::sio << sTag << " script:";
413 for( TokenStack::iterator i = tsScript.begin(); i; i++ ) 415 for( TokenStack::iterator i = pCurExp->begin(); i; i++ )
414 { 416 {
415 Bu::sio << " " << (*i); 417 Bu::sio << " " << (*i);
416 } 418 }
417 Bu::sio << Bu::sio.nl; 419 Bu::sio << Bu::sio.nl;
418 Bu::sio << "----------------" << Bu::sio.nl; 420 Bu::sio << "----------------" << Bu::sio.nl;
421 */
419} 422}
420 423
diff --git a/src/parser.h b/src/parser.h
index b0a1231..1e0d1c4 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -12,6 +12,7 @@ namespace Bu
12}; 12};
13 13
14class Lexer; 14class Lexer;
15class Expression;
15 16
16/** 17/**
17 * 18 *
@@ -45,10 +46,10 @@ class Lexer;
45class Parser 46class Parser
46{ 47{
47public: 48public:
48 Parser( Lexer &lex, Bu::Stream &rOut ); 49 Parser( Lexer &lex );
49 virtual ~Parser(); 50 virtual ~Parser();
50 51
51 void parse(); 52 Expression *parse();
52 53
53private: 54private:
54 void expr(); 55 void expr();
@@ -58,6 +59,7 @@ private:
58private: 59private:
59 void shift( const Token &t ); 60 void shift( const Token &t );
60 void reduce(); 61 void reduce();
62 void output( const Token &t );
61 int reqTokens( Token::Type eType ); 63 int reqTokens( Token::Type eType );
62 int getPriority( Token::Type eType ); 64 int getPriority( Token::Type eType );
63 65
@@ -65,10 +67,9 @@ private:
65 67
66private: 68private:
67 Lexer &lex; 69 Lexer &lex;
68 Bu::Stream &rOut;
69 typedef Bu::List<Token> TokenStack; 70 typedef Bu::List<Token> TokenStack;
70 TokenStack tsParse; 71 TokenStack tsParse;
71 TokenStack tsScript; 72 Expression *pCurExp;
72}; 73};
73 74
74#endif 75#endif
diff --git a/src/scriptengine.cpp b/src/scriptengine.cpp
new file mode 100644
index 0000000..7b5df03
--- /dev/null
+++ b/src/scriptengine.cpp
@@ -0,0 +1,82 @@
1#include "scriptengine.h"
2#include "lexer.h"
3#include "parser.h"
4#include "expression.h"
5
6#include <bu/staticmembuf.h>
7#include <bu/exceptionbase.h>
8
9ScriptEngine::ScriptEngine()
10{
11}
12
13ScriptEngine::~ScriptEngine()
14{
15}
16
17Number ScriptEngine::exec( const Bu::String &sExpr )
18{
19 Bu::StaticMemBuf mb( sExpr.getStr(), sExpr.getSize() );
20 return exec( sExpr );
21}
22
23Number ScriptEngine::exec( Bu::Stream &sInput )
24{
25 Lexer l( sInput );
26 Parser p( l );
27 Expression *pExp = p.parse();
28 Number n = exec( pExp );
29 delete pExp;
30 return n;
31}
32
33Number ScriptEngine::exec( Expression *pExpr )
34{
35 NumStack sNums;
36
37 for( Expression::iterator i = pExpr->begin(); i; i++ )
38 {
39 switch( (*i).eType )
40 {
41 case Token::tNumber:
42 sNums.push( *(*i).nVal );
43 break;
44
45 case Token::tVariable:
46 if( hVarState.has( *(*i).sVal ) )
47 {
48 sNums.push( hVarState[*(*i).sVal] );
49 }
50 else
51 {
52 throw Bu::ExceptionBase(
53 Bu::String("No such variable: $%1").arg(*(*i).sVal).end().getStr()
54 );
55 }
56 break;
57
58 case Token::tPlus:
59 sNums.push( sNums.peekPop() + sNums.peekPop() );
60 break;
61
62 case Token::tMinus:
63 sNums.push( sNums.peekPop() - sNums.peekPop() );
64 break;
65
66 case Token::tDivide:
67 sNums.push( sNums.peekPop() / sNums.peekPop() );
68 break;
69
70 case Token::tMultiply:
71 sNums.push( sNums.peekPop() * sNums.peekPop() );
72 break;
73
74 case Token::tNegate:
75 sNums.push( -sNums.peekPop() );
76 break;
77 }
78 }
79
80 return sNums.peekPop();
81}
82
diff --git a/src/scriptengine.h b/src/scriptengine.h
new file mode 100644
index 0000000..74924d6
--- /dev/null
+++ b/src/scriptengine.h
@@ -0,0 +1,33 @@
1#ifndef SCRIPT_ENGINE_H
2#define SCRIPT_ENGINE_H
3
4#include "number.h"
5
6#include <bu/hash.h>
7#include <bu/list.h>
8#include <bu/string.h>
9
10
11namespace Bu
12{
13 class Stream;
14}
15class Expression;
16
17class ScriptEngine
18{
19public:
20 ScriptEngine();
21 virtual ~ScriptEngine();
22
23 Number exec( const Bu::String &sExpr );
24 Number exec( Bu::Stream &sInput );
25 Number exec( Expression *pExpr );
26
27private:
28 typedef Bu::Hash<Bu::String, Number> VarHash;
29 typedef Bu::List<Number> NumStack;
30 VarHash hVarState;
31};
32
33#endif
diff --git a/src/unitparser.cpp b/src/unitparser.cpp
index a894647..01a4f80 100644
--- a/src/unitparser.cpp
+++ b/src/unitparser.cpp
@@ -53,7 +53,7 @@ void UnitParser::assignment()
53 Bu::MemBuf mbOut; 53 Bu::MemBuf mbOut;
54 Lexer lex( mbIn ); 54 Lexer lex( mbIn );
55 lex.setScale( 0 ); 55 lex.setScale( 0 );
56 Parser parser( lex, mbOut ); 56 Parser parser( lex );
57 parser.parse(); 57 parser.parse();
58// Bu::println("%1 == %2").arg( mbOut.getString().trimWhitespace() ) 58// Bu::println("%1 == %2").arg( mbOut.getString().trimWhitespace() )
59// .arg( parser.getVariable("test") ); 59// .arg( parser.getVariable("test") );