diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | parser.cpp | 105 |
2 files changed, 95 insertions, 12 deletions
@@ -14,7 +14,7 @@ remake: clean $(TARGET): $(patsubst %.cpp,%.o,$(wildcard *.cpp)) - $(CXX) -o $@ $< + $(CXX) -o $@ $^ %.o: %.cpp $(wildcard *.h) $(CXX) $(CXXFLAGS) -c -o $@ $< @@ -1,4 +1,5 @@ #include <stdexcept> +#include <stack> #include <cstring> #include <cctype> #include <cassert> @@ -52,6 +53,7 @@ public: number, string, symbol, + terminator, }; Type type; @@ -70,6 +72,14 @@ class Tokeniser{ i64 lnum,linex; Token::Type ttype; + /*struct State{ + i64 idx,nextidx; + i64 lnum,lineidx; + Token::Type ttype; + }; + + stack<State> statestack;*/ + bool eof(i64 at){ return at>=(i64)source.size(); } @@ -88,11 +98,39 @@ public: idx(0),nextidx(-1), lnum(1),linex(1){} + Tokeniser& operator=(const Tokeniser &other){ + if(&source!=&other.source||&filename!=&other.filename){ + throw runtime_error("Tokeniser::operator= on incompatible Tokeniser"); + } + idx=other.idx; nextidx=other.nextidx; + lnum=other.lnum; linex=other.linex; + ttype=other.ttype; + return *this; + } + + /*void save(){ + statestack.push({idx,nextidx,lnum,lineidx,ttype}); + } + + void restore(){ + if(statestack.size()==0)throw runtime_error("Tokeniser::restore() on empty stack"); + const State &st=statestack.top(); + idx=st.idx; nextidx=st.nextidx; + lnum=st.lnum; linex=st.linex; + ttype=st.ttype; + statestack.pop(); + } + + void discardstate(){ + if(statestack.size()==0)throw runtime_error("Tokeniser::discardstate() on empty stack"); + statestack.pop(); + }*/ + bool eof() const { return idx>=(i64)source.size(); } - Token get() const { + Token get(){ return Token(ttype,get_(),Site(filename,lnum,linex)); } @@ -100,6 +138,7 @@ public: bool advance(){ if(eof())return false; + // Let nextidx catch up with idx while(idx<nextidx){ if(source[idx]=='\n'){ lnum++; @@ -110,25 +149,26 @@ public: idx++; } + // Skip any whitespace and/or comments, emitting a terminator on a newline while(true){ i64 origidx=idx; while(!eof()&&isspace(source[idx])){ if(source[idx]=='\n'){ - lnum++; - linex=1; - } else { - linex++; + nextidx=idx+1; + ttype=Token::Type::terminator; + return true; } + linex++; idx++; } if(eof())return false; if(source[idx]=='#'){ while(!eof()&&source[idx]!='\n')idx++; - idx++; - lnum++; - linex=1; if(eof())return false; + nextidx=idx+1; + ttype=Token::Type::terminator; + return true; } if(idx==origidx)break; @@ -136,6 +176,13 @@ public: nextidx=idx; + // Terminator semicolon + if(source[nextidx]==';'){ + ttype=Token::Type::terminator; + nextidx++; + return true; + } + // Word if(isinitwordchar(source[nextidx])){ ttype=Token::Type::word; @@ -200,12 +247,48 @@ public: } }; + +static Expression parseExpression(Tokeniser &tokeniser){ + ; +} + +static Statement parseStatement(Tokeniser &tokeniser){ + Token tok=tokeniser.get(); + switch(tok.type){ + case Token::Type::word:{ + Tokeniser copyiser(tokeniser); + copyiser.advance(); + Token tok2=copyiser.get(); + if(tok2.type==Token::Type::symbol&&tok2.str==":="){ + tokeniser=copyiser; + tokeniser.advance(); + return Statement(Statement::Type::create,tok.str,parseExpression(tokeniser)); + } else if(tok2.type==Token::Type::symbol&&tok2.str=="="){ + tokeniser=copyiser; + tokeniser.advance(); + return Statement(Statement::Type::assign,tok.str,parseExpression(tokeniser)); + } else { + return Statement(Statement::Type::expression,parseExpression(tokeniser)); + } + } + + case Token::Type::number: + case Token::Type::string: + case Token::Type::symbol: + return Statement(Statement::Type::expression,parseExpression(tokeniser)); + + case Token::Type::terminator: + throw runtime_error("Unexpected terminator in parseStatement()"); + } +} + StatementList parse(const string &source,const string &filename){ Tokeniser tokeniser(source,filename); + if(!tokeniser.advance())return {}; StatementList stl; - while(tokeniser.advance()){ - Token tok=tokeniser.get(); - + while(!tokeniser.eof()){ + if(tokeniser.get().type==Token::Type::terminator)continue; + stl.push_back(parseStatement(tokeniser)); } return stl; } |