From 7c785439fca59b3801ca2a1118ae25a98d03750d Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Fri, 3 Feb 2017 22:00:23 +0100 Subject: Initial --- .gitignore | 2 + Makefile | 20 ++++++ ast.cpp | 0 ast.h | 90 ++++++++++++++++++++++++++ global.h | 8 +++ list.squig | 136 +++++++++++++++++++++++++++++++++++++++ main.cpp | 11 ++++ parser.cpp | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ parser.h | 14 ++++ 9 files changed, 492 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 ast.cpp create mode 100644 ast.h create mode 100644 global.h create mode 100644 list.squig create mode 100644 main.cpp create mode 100644 parser.cpp create mode 100644 parser.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..19e39f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +squig diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4e9ed24 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +CXX = g++ +CXXFLAGS = -Wall -Wextra -std=c++11 -g -fwrapv +TARGET = squig + +.PHONY: all clean remake + +all: $(TARGET) + +clean: + rm -f $(TARGET) *.o + +remake: clean + $(MAKE) all + + +$(TARGET): $(patsubst %.cpp,%.o,$(wildcard *.cpp)) + $(CXX) -o $@ $< + +%.o: %.cpp $(wildcard *.h) + $(CXX) $(CXXFLAGS) -c -o $@ $< diff --git a/ast.cpp b/ast.cpp new file mode 100644 index 0000000..e69de29 diff --git a/ast.h b/ast.h new file mode 100644 index 0000000..78abd55 --- /dev/null +++ b/ast.h @@ -0,0 +1,90 @@ +#pragma once + +#include +#include +#include "global.h" + +using namespace std; + + +class Statement; +using Name = string; +using StatementList = vector; + +class Site{ +public: + string filename; + i64 lnum,linex; + + Site(); + Site(const string &filename,i64 lnum,i64 linex); +}; + +class Scope{ +public: + enum class Type{ + direct, + lazy, + function, + async, + }; + + Type type; + StatementList body; + vector args; + + Site site; + + Scope(); + Scope(Type type,const StatementList &body,const vector &args); +}; + +class Expression{ +public: + enum class Type{ + binop, // name, args[0], args[1] + unop, // name, args[0] + call, // name, args + dive, // name, args, body + number, // numval + string, // strval + scope, // scope + }; + + Type type; + Name name; + vector args; + double numval; + string strval; + Scope scope; + StatementList body; + + Site site; + + Expression(); + Expression(Type type,const Name &name,const vector &args); // binop, call + Expression(Type type,const Name &name,const Expression &arg); // unop + Expression(Type type,const Name &name,const vector &args,const StatementList &body); // dive + Expression(Type type,double numval); // number + Expression(Type type,const string &strval); // string + Expression(Type type,const Scope &scope); // scope +}; + +class Statement{ +public: + enum class Type{ + create, // dstvar, expr + assign, // dstvar, expr + expression, // expr + }; + + Type type; + Name dstvar; + Expression expr; + + Site site; + + Statement(); + Statement(Type type,const Name &dstvar,const Expression &expr); // create, assign + Statement(Type type,const Expression &expr); // expr +}; diff --git a/global.h b/global.h new file mode 100644 index 0000000..4abd67a --- /dev/null +++ b/global.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +using namespace std; + +using i64 = int64_t; +using u64 = uint64_t; diff --git a/list.squig b/list.squig new file mode 100644 index 0000000..ea0d333 --- /dev/null +++ b/list.squig @@ -0,0 +1,136 @@ +new_list := ??{ + front := nil + back := nil +} + +list_push_front := ??(list, item){ + list { + if front == nil { + front = { + value := item + next := nil + prev := nil + } + back = front + } else { + front = { + value := item + next := front + prev := nil + } + } + } +} + +list_push_back := ??(list, item){ + list { + if back == nil { + front = { + value := item + next := nil + prev := nil + } + back = front + } else { + back = { + value := item + next := nil + prev := back + } + } + } +} + +list_pop_front := ??(list){ + x := nil + list { + if front == nil { + throw_error("Call to 'list_pop_front' on empty list") + } + front { + x = value + front = next + } + if front == nil { + back = nil + } + } +} + +list_pop_back := ??(list){ + x := nil + list { + if back == nil { + throw_error("Call to 'list_pop_back' on empty list") + } + back { + x = value + back = prev + } + if back == nil { + front = nil + } + } +} + +list_get := nil +{ + get_helper := ??(front, idx){ + if front == nil { + throw_error("Index past end of list in 'list_get'") + } + x := nil + if idx == 0 { + front { + x = value + } + } else { + front { + found := nil + get_helper(next, idx - 1){ + found = x + } + x = found + } + } + } + list_get = ??(list, idx){ + if idx < 0 { + throw_error("Negative index in 'list_get'") + } + x := nil + list { + found := nil + get_helper(front, idx){ + found = x + } + x = found + } + } +} + +list_set := nil +{ + set_helper := ??(front, idx, val){ + if front == nil { + throw_error("Index past end of list in 'list_set'") + } + if idx == 0 { + front { + value = val + } + } else { + front { + set_helper(next, idx - 1, val){} + } + } + } + list_set = ??(list, idx, val){ + if idx < 0 { + throw_error("Negative index in 'list_set'") + } + list { + set_helper(front, idx, val) + } + } +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..b28e446 --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include +#include "parser.h" + +using namespace std; + + +int main(int argc,char **argv){ + (void)argc; + (void)argv; + return 0; +} diff --git a/parser.cpp b/parser.cpp new file mode 100644 index 0000000..73ae368 --- /dev/null +++ b/parser.cpp @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include "parser.h" + +using namespace std; + + +ParseError::ParseError(const string &what_arg) + :runtime_error(what_arg){} +ParseError::ParseError(const char *what_arg) + :runtime_error(what_arg){} + + +static bool isinitwordchar(char c){ + return isalpha(c)||c=='_'; +} + +static bool iswordchar(char c){ + return isalpha(c)||isdigit(c)||c=='_'; +} + +static const vector tok_symbols={ + "==", "!=", ">", "<", ">=", "<=", + ":=", "=", + "+", "-", "*", "/", "%", + "(", ")", ",", + "{", "}", "?{", "??{", "}&", +}; + +static bool isSymbolPrefix(const string &s){ + for(const string &sym : tok_symbols){ + if(s.size()<=sym.size()&&sym.substr(0,s.size())==s)return true; + } + return false; +} + +template +static bool contains(const vector &v,const T &target){ + for(const T &t : v){ + if(t==target)return true; + } + return false; +} + + +class Token{ +public: + enum class Type{ + word, + number, + string, + symbol, + }; + + Type type; + string str; + Site site; + + Token(Type type,const string &str,const Site &site) + :type(type),str(str),site(site){} +}; + + +class Tokeniser{ + const string &source; + const string &filename; + i64 idx,nextidx; + i64 lnum,linex; + Token::Type ttype; + + bool eof(i64 at){ + return at>=(i64)source.size(); + } + + string get_() const { + if(eof())throw runtime_error("Tokeniser::get() on eof"); + if(nextidx==-1)throw runtime_error("Tokeniser::get() before advance"); + if(nextidx==-2)throw runtime_error("Tokeniser::get() after eof"); + assert(nextidx>=0); + return source.substr(idx,nextidx-idx); + } + +public: + Tokeniser(const string &source,const string &filename) + :source(source),filename(filename), + idx(0),nextidx(-1), + lnum(1),linex(1){} + + bool eof() const { + return idx>=(i64)source.size(); + } + + Token get() const { + return Token(ttype,get_(),Site(filename,lnum,linex)); + } + + // Returns whether there are more tokens + bool advance(){ + if(eof())return false; + + while(idx