├── .gitignore ├── BUILD ├── COPYING ├── Makefile.am ├── README.md ├── THANKS ├── c2 ├── Atom.cpp ├── Atom.h ├── Cmd.cpp ├── Cmd.h ├── Code.cpp ├── Code.h ├── Common.h ├── CompileError.h ├── Compiler.cpp ├── Compiler.h ├── ExpParser.h ├── Expression.cpp ├── Expression.h ├── Function.cpp ├── Function.h ├── IntLiteral.cpp ├── IntLiteral.h ├── Literal.h ├── Makefile.am ├── NewInit.cpp ├── NewInit.h ├── Object.cpp ├── Object.h ├── Operator.cpp ├── Operator.h ├── Scope.cpp ├── Scope.h ├── StdLib.cpp ├── StdLib.h ├── StringLiteral.cpp ├── StringLiteral.h ├── SymbolTable.h ├── Type.cpp ├── Type.h ├── Variable.cpp ├── Variable.h ├── bytecode.txt └── compiler.cpp ├── compiler ├── AST.cpp ├── AST.h ├── Arg.cpp ├── Arg.h ├── ArgSpec.h ├── Args.cpp ├── Args.h ├── Block.cpp ├── Block.h ├── Brace.cpp ├── Brace.h ├── Command.cpp ├── Command.h ├── CommandFragment.cpp ├── CommandFragment.h ├── Common.h ├── CompileError.h ├── Expression.cpp ├── Expression.h ├── Function.cpp ├── Function.h ├── Identifier.cpp ├── Identifier.h ├── IsVar.cpp ├── IsVar.h ├── Makefile.am ├── Method.cpp ├── Method.h ├── New.cpp ├── New.h ├── NewInit.cpp ├── NewInit.h ├── Node.cpp ├── Node.h ├── Object.cpp ├── Object.h ├── ObjectLiteral.cpp ├── ObjectLiteral.h ├── Operator.cpp ├── Operator.h ├── OperatorParser.cpp ├── OperatorParser.h ├── ProcCall.cpp ├── ProcCall.h ├── Returns.cpp ├── Returns.h ├── RootNode.cpp ├── RootNode.h ├── Scope.cpp ├── Scope.h ├── Statement.h ├── StdLib.cpp ├── StdLib.h ├── Symbol.h ├── SymbolTable.cpp ├── SymbolTable.h ├── Token.cpp ├── Token.h ├── Type.cpp ├── Type.h ├── TypeSpec.cpp ├── TypeSpec.h ├── TypedNode.cpp ├── TypedNode.h ├── Variable.cpp ├── Variable.h └── compile.cpp ├── configure.ac ├── exstatik ├── Codegen.cpp ├── Codegen.h ├── Compiler.cpp ├── Compiler.h ├── Lexer.cpp ├── Lexer.h ├── Makefile.am ├── Parser.cpp ├── Parser.h └── main.cpp ├── g ├── cleanup.sh └── convert.sh ├── info ├── chain.txt ├── llvm.txt ├── notes.txt └── vm.txt ├── istatik ├── ISError.h ├── ISLog.cpp ├── ISLog.h ├── IStatik.cpp ├── IStatik.h ├── InputWindow.cpp ├── InputWindow.h ├── Makefile.am ├── ParserWindow.cpp ├── ParserWindow.h ├── WindowAction.h ├── WindowResponse.h └── main.cpp ├── lexer ├── Common.h ├── Emitter.cpp ├── Emitter.h ├── LexError.h ├── Lexer.cpp ├── Lexer.h ├── Makefile.am ├── Tokenizer.h └── lexer.cpp ├── m4 ├── boost.m4 └── m4_ax_with_curses.m4 ├── p2 ├── Makefile.am ├── ParseError.h ├── Parser.cpp ├── Parser.h ├── Shok.h ├── Token.cpp ├── Token.h └── parser.cpp ├── parser ├── Makefile.am ├── shok_parser.in ├── shokparser │ ├── ActionParser.py │ ├── DecentSeqParser.py │ ├── DispParser.py │ ├── LexToken.py │ ├── MakeRule.py │ ├── Makefile.am │ ├── NiceSeqParser.py │ ├── OrParser.py │ ├── Parser.py │ ├── ParserRunner.py │ ├── ParserTest.py │ ├── PlusParser.py │ ├── Rule.py │ ├── SeqParser.py │ ├── ShokParser.py │ ├── StableSeqParser.py │ ├── StarParser.py │ ├── TerminalParser.py │ └── __init__.py └── shokparsertest │ └── ShokParserTest.py ├── shell ├── Makefile.am └── shell.cpp ├── statik ├── Batch.cpp ├── Batch.h ├── Grapher.cpp ├── Grapher.h ├── IConnection.cpp ├── IConnection.h ├── IncParser.cpp ├── IncParser.h ├── Keyword.cpp ├── Keyword.h ├── List.cpp ├── List.h ├── ListenerTable.h ├── Makefile.am ├── Meta.cpp ├── Meta.h ├── ObjectPool.h ├── Opt.cpp ├── Opt.h ├── Or.cpp ├── Or.h ├── OrderList.cpp ├── OrderList.h ├── OutputFunc.cpp ├── OutputFunc.h ├── ParseAction.h ├── ParseFunc.h ├── README.md ├── Regexp.cpp ├── Regexp.h ├── Root.cpp ├── Root.h ├── Rule.cpp ├── Rule.h ├── SError.h ├── SLog.cpp ├── SLog.h ├── STree.cpp ├── STree.h ├── Seq.cpp ├── Seq.h ├── Star.cpp ├── Star.h ├── State.cpp ├── State.h ├── notes.txt ├── reorg.txt └── test │ ├── Battery.cpp │ ├── Battery.h │ ├── Keyword.cpp │ ├── Keyword.h │ ├── Makefile.am │ ├── Or.cpp │ ├── Or.h │ ├── STError.h │ ├── STLog.cpp │ ├── STLog.h │ ├── Splash.cpp │ ├── Splash.h │ ├── Star.cpp │ ├── Star.h │ ├── StatikBattery.h │ ├── Test.cpp │ ├── Test.h │ └── main.cpp ├── test.sh ├── util ├── Graphviz.cpp ├── Graphviz.h ├── Log.cpp ├── Log.h ├── Makefile.am ├── Proc.cpp ├── Proc.h ├── Util.cpp └── Util.h └── vm ├── Call.cpp ├── Call.h ├── Cmd.cpp ├── Cmd.h ├── Context.cpp ├── Context.h ├── Del.cpp ├── Del.h ├── Executor.cpp ├── Executor.h ├── ExpParser.h ├── Expression.cpp ├── Expression.h ├── Identifier.h ├── Instruction.cpp ├── Instruction.h ├── InstructionParser.h ├── Instructions.h ├── Makefile.am ├── New.cpp ├── New.h ├── Object.cpp ├── Object.h ├── StdLib.cpp ├── StdLib.h ├── Symbol.h ├── VMError.h ├── ex.txt └── vm.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # shok 4 | build-aux 5 | config.h.in~ 6 | lexer/shok_lexer 7 | parser/shok_parser 8 | c2/shok_c2 9 | vm/shok_vm 10 | shell/shok_shell 11 | lexer.log 12 | parser.log 13 | compiler.log 14 | vm.log 15 | graphs 16 | log.log 17 | slog.log 18 | slog.log_sanity 19 | g/*.dot 20 | g/*.png 21 | istatik/istatik 22 | exstatik/exstatik 23 | statik/test/statik_test 24 | 25 | # C extensions 26 | *.so 27 | *.o 28 | *.a 29 | 30 | # Packages 31 | *.egg 32 | *.egg-info 33 | dist 34 | build 35 | eggs 36 | parts 37 | bin 38 | var 39 | sdist 40 | develop-eggs 41 | .installed.cfg 42 | lib 43 | lib64 44 | 45 | # Installer logs 46 | pip-log.txt 47 | 48 | # Unit test / coverage reports 49 | .coverage 50 | .tox 51 | nosetests.xml 52 | 53 | # Translations 54 | *.mo 55 | 56 | # Mr Developer 57 | .mr.developer.cfg 58 | .project 59 | .pydevproject 60 | 61 | # lexer files generated by quex 62 | lexer/tiny_lexer_st* 63 | 64 | # vim swp files 65 | .*.swp 66 | 67 | # autotools build files 68 | configure 69 | Makefile 70 | *.in 71 | config.h 72 | config.log 73 | config.status 74 | libtool 75 | aclocal.m4 76 | .deps 77 | m4/libtool.m4 78 | m4/ltoptions.m4 79 | m4/ltsugar.m4 80 | m4/ltversion.m4 81 | m4/lt~obsolete.m4 82 | stamp-h1 83 | autom4te.cache 84 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | The shok interpreter-system is built using the GNU autotools: 2 | 3 | - GNU Autoconf 2.69 4 | https://www.gnu.org/software/autoconf 5 | GNU GPL v3+ 6 | 7 | - GNU Automake 1.13.3+ 8 | https://www.gnu.org/software/automake 9 | GNU GPL v2+ 10 | 11 | - GNU Libtool 2.4.2 12 | https://www.gnu.org/software/libtool 13 | GNU GPL v2+ 14 | 15 | - GNU Make 3.81 16 | https://www.gnu.org/software/make 17 | GNU GPL v2+ 18 | 19 | To build and install, navigate to the base directory of the package and run: 20 | 21 | autoreconf --install 22 | ./configure 23 | make 24 | make install 25 | 26 | The configure script has many options. In particular I STRONGLY recommend 27 | using the --prefix option to install to a sandbox directory, instead of your 28 | system folders. This is appropriate until shok has matured. For example: 29 | 30 | ./configure --prefix=${HOME}/apps 31 | 32 | will install to a personal "apps" subdirectory of your home dir. Then just add 33 | the bin subdirectory to your shell's PATH environment variable: 34 | export PATH=${PATH}:${HOME}/apps/bin 35 | 36 | 37 | The project has the following build dependencies: 38 | 39 | Shell, Lexer, Compiler, VM: 40 | - The GNU C++ compiler (g++) 4.7.2, part of GCC: the GNU Compiler Collection 41 | http://gcc.gnu.org 42 | GNU GPL v3 43 | (C) Free Software Foundation (FSF) 44 | 45 | - Boost C++ libraries (iostreams, spirit, miscellaneous) 46 | http://www.boost.org 47 | Boost Software License v1.0 48 | 49 | Parser: 50 | - Python 2.7 51 | http://python.org/ 52 | See the license of your favourite compiler/interpreter 53 | Maybe 2.6 or some earlier versions will work 54 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | # SUBDIRS = lexer p2 c2 vm shell 3 | SUBDIRS = util statik statik/test exstatik istatik 4 | dist_doc_DATA = README.md 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | shok 2 | ==== 3 | 4 | http://shok.io 5 | 6 | The shok command shell is a non-POSIX interactive command language interpreter with an expressive scripting language. It intends to be a modern, discoverable shell intended for every-day command invocation, process management, and filesystem manipulation. 7 | 8 | status 9 | ====== 10 | 11 | shok is in its early stages of initial development. It has the framework for a shell, a lexer, a parser, and an "evaluator" (type-checking, AST execution, program invocation). If it compiles, it may let you change directories and run commands but not write programs, or much else really. Most core features have yet to be implemented. All language attributes are suitable for discussion and replacement. Nevertheless, it is progressing quickly and steadily. 12 | 13 | Get involved! See http://shok.io for details. Description of the code layout and steps forward are coming soon. 14 | 15 | todo 16 | ==== 17 | 18 | Immediate hacking priorities: 19 | 20 | 1. functions / methods 21 | 22 | 2. trivial implementations of a few basic objects 23 | 24 | 3. string literals 25 | 26 | 4. basic interactive niceties: left/right/home/end, ^L 27 | 28 | 5. comments 29 | -------------------------------------------------------------------------------- /THANKS: -------------------------------------------------------------------------------- 1 | Adding boost library to the autotools-based build process: 2 | https://github.com/tsuna/boost.m4 3 | 4 | Adding shok_parser (python) to the autotools-based build process: 5 | http://www.micahcarrick.com/tutorials/autotools-tutorial-python-gtk/getting-started.html 6 | -------------------------------------------------------------------------------- /c2/Atom.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Atom.h" 5 | 6 | #include "Function.h" 7 | #include "Object.h" 8 | #include "Variable.h" 9 | 10 | #include 11 | #include 12 | using std::string; 13 | 14 | using namespace compiler; 15 | 16 | std::string Atom_bytecode::operator() (const Variable& var) const { 17 | return " " + var.bytename(); 18 | } 19 | 20 | std::string Atom_bytecode::operator() (const Literal& lit) const { 21 | return " " + boost::apply_visitor(Literal_bytecode(), lit); 22 | } 23 | 24 | std::string Atom_bytecode::operator() (const Object& object) const { 25 | return object.bytecode(); 26 | } 27 | 28 | std::string Atom_bytecode::operator() (const Function& function) const { 29 | return function.bytecode(); 30 | } 31 | 32 | const Type& Atom_type::operator() (const Variable& var) const { 33 | return var.type(); 34 | } 35 | 36 | const Type& Atom_type::operator() (const Literal& lit) const { 37 | return boost::apply_visitor(Literal_type(), lit); 38 | } 39 | 40 | const Type& Atom_type::operator() (const Object& object) const { 41 | return object.type(); 42 | } 43 | 44 | const Type& Atom_type::operator() (const Function& function) const { 45 | return function.type(); 46 | } 47 | -------------------------------------------------------------------------------- /c2/Atom.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Atom_h_ 5 | #define _Atom_h_ 6 | 7 | /* Atom */ 8 | 9 | #include "Literal.h" 10 | #include "Type.h" 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace compiler { 19 | 20 | class Function; 21 | class Object; 22 | class Variable; 23 | 24 | typedef boost::variant< 25 | Variable, 26 | Literal, 27 | boost::recursive_wrapper, 28 | boost::recursive_wrapper 29 | > Atom; 30 | 31 | class Atom_bytecode : public boost::static_visitor { 32 | public: 33 | std::string operator() (const Variable& var) const; 34 | std::string operator() (const Literal& var) const; 35 | std::string operator() (const Object& object) const; 36 | std::string operator() (const Function& function) const; 37 | }; 38 | 39 | class Atom_type : public boost::static_visitor { 40 | public: 41 | const Type& operator() (const Variable& var) const; 42 | const Type& operator() (const Literal& var) const; 43 | const Type& operator() (const Object& object) const; 44 | const Type& operator() (const Function& function) const; 45 | }; 46 | 47 | } 48 | 49 | #endif // _Atom_h_ 50 | -------------------------------------------------------------------------------- /c2/Cmd.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Cmd.h" 5 | 6 | #include "CompileError.h" 7 | #include "Expression.h" 8 | 9 | #include 10 | #include 11 | #include 12 | using std::pair; 13 | using std::string; 14 | using std::vector; 15 | 16 | using namespace compiler; 17 | 18 | void Cmd::attach_text(const std::string& text) { 19 | m_cmdtext += text; 20 | } 21 | 22 | void Cmd::attach_exp(const Expression& exp) { 23 | m_expcode += " (exp" + exp.bytecode() + ")"; 24 | m_cmdtext += "{}"; 25 | } 26 | 27 | std::string Cmd::bytecode() const { 28 | return " (cmd" + m_expcode + " [" + m_cmdtext + "])"; 29 | } 30 | -------------------------------------------------------------------------------- /c2/Code.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Code.h" 5 | 6 | #include 7 | #include 8 | using std::string; 9 | 10 | using namespace compiler; 11 | 12 | void Call::init(const Scope& scope) { 13 | m_scope = &scope; 14 | m_bytecode = " (call "; 15 | } 16 | 17 | void Call::attach_source(const Variable& var) { 18 | // TODO validate that var is callable 19 | m_bytecode += var.bytename(); 20 | } 21 | 22 | void Call::attach_arg(const Expression& arg) { 23 | // TODO validate that var's next arg accepts this arg's type 24 | m_bytecode += arg.bytecode(); 25 | } 26 | 27 | string Call::bytecode() const { 28 | return m_bytecode + ")"; 29 | } 30 | -------------------------------------------------------------------------------- /c2/Common.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Common_h_ 5 | #define _Common_h_ 6 | 7 | /* Common typedefs and forward-declares */ 8 | 9 | namespace compiler { 10 | 11 | template struct ExpParser; 12 | 13 | } 14 | 15 | #endif // _Common_h_ 16 | -------------------------------------------------------------------------------- /c2/CompileError.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _CompileError_h_ 5 | #define _CompileError_h_ 6 | 7 | /* Compilation errors */ 8 | 9 | #include "util/Log.h" 10 | 11 | #include 12 | 13 | namespace compiler { 14 | 15 | class CompileError : public std::runtime_error { 16 | public: 17 | CompileError(const std::string& what) : std::runtime_error(what) {} 18 | CompileError(Log& log, const std::string& what) : std::runtime_error(what) { 19 | log.error(what); 20 | } 21 | }; 22 | 23 | } 24 | 25 | #endif // _CompileError_h_ 26 | -------------------------------------------------------------------------------- /c2/Compiler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Compiler_h_ 5 | #define _Compiler_h_ 6 | 7 | /* shok compiler */ 8 | 9 | #include 10 | #include 11 | 12 | namespace compiler { 13 | 14 | class Compiler { 15 | public: 16 | Compiler(std::istream& input, std::ostream& output); 17 | 18 | // returns true on full successful compile 19 | bool execute(); 20 | 21 | private: 22 | std::istream& m_input; 23 | std::ostream& m_output; 24 | }; 25 | 26 | } 27 | 28 | #endif // _Compiler_h_ 29 | -------------------------------------------------------------------------------- /c2/Expression.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Expression_h_ 5 | #define _Expression_h_ 6 | 7 | /* Expression */ 8 | 9 | #include "Atom.h" 10 | #include "Operator.h" 11 | #include "Scope.h" 12 | #include "Type.h" 13 | 14 | #include 15 | 16 | namespace compiler { 17 | 18 | class Expression { 19 | public: 20 | Expression(); 21 | void init(const Scope& scope); 22 | void attach_atom(const Atom& atom); 23 | void attach_preop(const std::string& preop); 24 | void attach_binop(const std::string& binop); 25 | void finalize(); 26 | std::string bytecode() const; 27 | const Type& type() const; 28 | 29 | private: 30 | typedef boost::ptr_vector stack_vec; 31 | typedef stack_vec::const_iterator stack_iter; 32 | 33 | const Scope* m_scope; 34 | stack_vec m_stack; 35 | boost::shared_ptr m_type; 36 | std::string m_bytecode; 37 | }; 38 | 39 | } 40 | 41 | #endif // _Expression_h_ 42 | -------------------------------------------------------------------------------- /c2/Function.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Function.h" 5 | 6 | #include "Expression.h" 7 | 8 | #include 9 | #include 10 | #include 11 | using std::auto_ptr; 12 | using std::string; 13 | 14 | using namespace compiler; 15 | 16 | void Function::init(const Scope& scope) { 17 | m_scope.reset(new FunctionScope(scope, *this)); 18 | m_froot = m_scope->findRoot("@"); 19 | if (!m_froot) { 20 | throw CompileError("Cannot initialize Function; @ is missing"); 21 | } 22 | } 23 | 24 | void Function::init_args() { 25 | if (m_type) { 26 | throw CompileError("Cannot init args of Function that already has a type"); 27 | } 28 | m_type.reset(new ArgsType(*m_froot)); 29 | } 30 | 31 | void Function::attach_arg(const std::string& name, const Expression& exp) { 32 | ArgsType* argsType = dynamic_cast(m_type.get()); 33 | if (!argsType) { 34 | throw CompileError("Cannot attach arg " + name + " to Function with uninitialized args"); 35 | } 36 | argsType->addArg(name, exp.type().duplicate()); 37 | } 38 | 39 | void Function::attach_returns(const Expression& returns) { 40 | if (m_type.get()) { 41 | m_type.reset(new AndType(m_type->duplicate(), 42 | auto_ptr(new ReturnsType(*m_froot, returns.type().duplicate())))); 43 | } else { 44 | m_type.reset(new ReturnsType(*m_froot, returns.type().duplicate())); 45 | } 46 | } 47 | 48 | void Function::attach_body(const string& code) { 49 | m_bytecode += code; 50 | } 51 | 52 | FunctionScope& Function::scope() const { 53 | return *m_scope; 54 | } 55 | 56 | const Type& Function::type() const { 57 | if (!m_type.get()) { 58 | throw CompileError("Function " + bytecode() + " does not have a type"); 59 | } 60 | return *m_type; 61 | } 62 | 63 | string Function::bytecode() const { 64 | return " (function" + m_bytecode + m_scope->bytecode() + ")"; 65 | } 66 | -------------------------------------------------------------------------------- /c2/IntLiteral.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "IntLiteral.h" 5 | 6 | #include "StdLib.h" 7 | 8 | #include 9 | using boost::lexical_cast; 10 | 11 | #include 12 | using std::string; 13 | 14 | using namespace compiler; 15 | 16 | IntLiteral::IntLiteral() 17 | : m_scope(NULL) { 18 | } 19 | 20 | void IntLiteral::init(const Scope& scope) { 21 | m_scope = &scope; 22 | const Type* type = m_scope->find(StdLib::INTEGER); 23 | if (!type) { 24 | throw CompileError("Object for literal int does not exist in scope at depth " + lexical_cast(m_scope->depth())); 25 | } 26 | m_type.reset(type->duplicate().release()); 27 | } 28 | 29 | void IntLiteral::attach_text(const std::string& text) { 30 | m_text = text; 31 | } 32 | 33 | const Type& IntLiteral::type() const { 34 | if (!m_type) { 35 | throw CompileError("IntLiteral has no type"); 36 | } 37 | return *m_type; 38 | } 39 | 40 | std::string IntLiteral::bytecode() const { 41 | return "(int " + m_text + ")"; 42 | } 43 | -------------------------------------------------------------------------------- /c2/IntLiteral.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _IntLiteral_h_ 5 | #define _IntLiteral_h_ 6 | 7 | /* Integer literals */ 8 | 9 | #include "Scope.h" 10 | #include "Type.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | namespace phoenix = boost::phoenix; 21 | namespace spirit = boost::spirit; 22 | namespace ascii = spirit::ascii; 23 | namespace qi = spirit::qi; 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace compiler { 30 | 31 | class IntLiteral { 32 | public: 33 | IntLiteral(); 34 | void init(const Scope& scope); 35 | void attach_text(const std::string& text); 36 | 37 | const Type& type() const; 38 | std::string bytecode() const; 39 | 40 | private: 41 | const Scope* m_scope; 42 | std::string m_text; 43 | boost::shared_ptr m_type; 44 | }; 45 | 46 | template 47 | struct IntLiteralParser 48 | : qi::grammar { 49 | public: 50 | IntLiteralParser() 51 | : IntLiteralParser::base_type(int_, "IntLiteral") { 52 | using phoenix::ref; 53 | using qi::_1; 54 | using qi::_r1; 55 | using qi::_val; 56 | using qi::char_; 57 | using qi::lit; 58 | 59 | nums_ %= +char_("0-9"); 60 | int_ = 61 | lit("INT:'")[phoenix::bind(&IntLiteral::init, _val, _r1)] 62 | > nums_[phoenix::bind(&IntLiteral::attach_text, _val, _1)] 63 | > lit('\''); 64 | 65 | //BOOST_SPIRIT_DEBUG_NODE(int_); 66 | } 67 | 68 | private: 69 | qi::rule nums_; 70 | qi::rule int_; 71 | }; 72 | 73 | } 74 | 75 | #endif // _IntLiteral_h_ 76 | -------------------------------------------------------------------------------- /c2/Literal.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Literal_h_ 5 | #define _Literal_h_ 6 | 7 | /* Atomic literals */ 8 | 9 | #include "IntLiteral.h" 10 | #include "StringLiteral.h" 11 | #include "Scope.h" 12 | #include "Type.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | namespace phoenix = boost::phoenix; 23 | namespace spirit = boost::spirit; 24 | namespace ascii = spirit::ascii; 25 | namespace qi = spirit::qi; 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace compiler { 32 | 33 | typedef boost::variant< 34 | IntLiteral, 35 | StringLiteral 36 | > Literal; 37 | 38 | class Literal_bytecode : public boost::static_visitor { 39 | public: 40 | std::string operator() (const IntLiteral& lit) const { return lit.bytecode(); } 41 | std::string operator() (const StringLiteral& lit) const { return lit.bytecode(); } 42 | }; 43 | 44 | class Literal_type : public boost::static_visitor { 45 | public: 46 | const Type& operator() (const IntLiteral& lit) const { return lit.type(); } 47 | const Type& operator() (const StringLiteral& lit) const { return lit.type(); } 48 | }; 49 | 50 | template 51 | struct LiteralParser 52 | : qi::grammar { 53 | public: 54 | LiteralParser() 55 | : LiteralParser::base_type(literal_, "Literal") { 56 | using phoenix::ref; 57 | using qi::_1; 58 | using qi::_r1; 59 | using qi::_val; 60 | using qi::char_; 61 | using qi::lit; 62 | 63 | literal_ %= ( 64 | int_(_r1) 65 | | str_(_r1) 66 | ); 67 | 68 | //BOOST_SPIRIT_DEBUG_NODE(literal_); 69 | } 70 | 71 | private: 72 | IntLiteralParser int_; 73 | StringLiteralParser str_; 74 | qi::rule literal_; 75 | }; 76 | 77 | } 78 | 79 | #endif // _Literal_h_ 80 | -------------------------------------------------------------------------------- /c2/Makefile.am: -------------------------------------------------------------------------------- 1 | UTIL_DIR = ../util 2 | UTIL_SRCS = \ 3 | $(UTIL_DIR)/Log.cpp \ 4 | $(UTIL_DIR)/Log.h 5 | 6 | COMMON_SRCS = $(UTIL_SRCS) 7 | 8 | bin_PROGRAMS = shok_c2 9 | shok_c2_SOURCES = $(COMMON_SRCS) \ 10 | Atom.cpp \ 11 | Atom.h \ 12 | Cmd.cpp \ 13 | Cmd.h \ 14 | Code.cpp \ 15 | Code.h \ 16 | Common.h \ 17 | CompileError.h \ 18 | Compiler.cpp \ 19 | Compiler.h \ 20 | ExpParser.h \ 21 | Expression.cpp \ 22 | Expression.h \ 23 | Function.cpp \ 24 | Function.h \ 25 | IntLiteral.cpp \ 26 | IntLiteral.h \ 27 | Literal.h \ 28 | NewInit.cpp \ 29 | NewInit.h \ 30 | Object.cpp \ 31 | Object.h \ 32 | Operator.cpp \ 33 | Operator.h \ 34 | Scope.cpp \ 35 | Scope.h \ 36 | StdLib.cpp \ 37 | StdLib.h \ 38 | StringLiteral.cpp \ 39 | StringLiteral.h \ 40 | SymbolTable.h \ 41 | Type.cpp \ 42 | Type.h \ 43 | Variable.cpp \ 44 | Variable.h \ 45 | compiler.cpp 46 | #shok_c2_CPPFLAGS = $(BOOST_CPPFLAGS) -DBOOST_SPIRIT_DEBUG 47 | shok_c2_CPPFLAGS = $(BOOST_CPPFLAGS) 48 | shok_c2_LDFLAGS = $(BOOST_IOSTREAMS_LDFLAGS) 49 | LIBS = $(BOOST_IOSTREAMS_LIBS) 50 | -------------------------------------------------------------------------------- /c2/NewInit.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "NewInit.h" 5 | 6 | #include "Expression.h" 7 | 8 | #include 9 | using boost::lexical_cast; 10 | 11 | #include 12 | #include 13 | using std::string; 14 | 15 | using namespace compiler; 16 | 17 | NewInit::NewInit() 18 | : m_scope(NULL) { 19 | } 20 | 21 | void NewInit::init(Scope& scope) { 22 | m_scope = &scope; 23 | } 24 | 25 | void NewInit::attach_name(const string& name) { 26 | m_name = name; 27 | if (m_scope->findLocal(name)) { 28 | throw CompileError("Variable " + name + " already exists in scope at depth " + lexical_cast(m_scope->depth())); 29 | } 30 | } 31 | 32 | void NewInit::attach_type(const Expression& exp) { 33 | m_type.reset(exp.type().duplicate().release()); 34 | } 35 | 36 | void NewInit::attach_exp(const Expression& exp) { 37 | m_exp.reset(new Expression(exp)); 38 | if (!m_type.get()) { 39 | m_type.reset(exp.type().duplicate().release()); 40 | } 41 | m_bytecode = m_exp->bytecode(); 42 | } 43 | 44 | void NewInit::finalize() { 45 | if (m_type.get()) { 46 | if (!m_exp.get()) { 47 | m_bytecode = m_type->defaultValueBytecode(); 48 | } 49 | } else { 50 | if (!m_exp.get()) { 51 | m_bytecode = Scope::LocalityPrefix(Scope::GLOBAL) + "object"; 52 | } 53 | const Type* object = m_scope->findRoot("object"); 54 | if (!object) { 55 | throw CompileError("NewInit finalize failed to find the root object type"); 56 | } 57 | m_type.reset(new BasicType(object->duplicate(), "object")); 58 | } 59 | m_scope->insert(m_name, m_type->duplicate()); 60 | } 61 | 62 | string NewInit::bytecode_asNew() const { 63 | return " (new " + m_scope->bytename(m_name) + " " + m_bytecode + ")"; 64 | } 65 | 66 | string NewInit::bytecode_asMember() const { 67 | return " (member " + m_scope->bytename(m_name) + " " + m_bytecode + ")"; 68 | } 69 | -------------------------------------------------------------------------------- /c2/Object.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Object.h" 5 | 6 | #include "NewInit.h" 7 | 8 | #include 9 | #include 10 | using std::string; 11 | 12 | using namespace compiler; 13 | 14 | void Object::init(const Scope& scope) { 15 | m_scope.reset(new ObjectScope(scope, *this)); 16 | m_type.reset(new BasicType(m_scope->findRoot("object")->duplicate(), "object")); 17 | } 18 | 19 | void Object::attach_new(const NewInit& newInit) { 20 | m_bytecode += newInit.bytecode_asMember(); 21 | m_type->addMember(newInit.name(), newInit.type().duplicate()); 22 | } 23 | 24 | ObjectScope& Object::scope() const { 25 | return *m_scope; 26 | } 27 | 28 | const Type& Object::type() const { 29 | if (!m_type.get()) { 30 | throw CompileError("Object " + bytecode() + " does not have a type"); 31 | } 32 | return *m_type; 33 | } 34 | 35 | string Object::bytecode() const { 36 | return " (object" + m_bytecode + ")"; 37 | } 38 | -------------------------------------------------------------------------------- /c2/StdLib.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "StdLib.h" 5 | 6 | #include 7 | #include 8 | using std::auto_ptr; 9 | using std::string; 10 | 11 | using namespace compiler; 12 | 13 | void StdLib::Init(Scope& scope) { 14 | scope.insert(StdLib::OBJECT, auto_ptr(new RootType())); 15 | scope.insert(StdLib::FUNCTION, auto_ptr(new BasicType( 16 | scope.find(StdLib::OBJECT)->duplicate(), StdLib::OBJECT))); 17 | scope.insert(StdLib::INTEGER, auto_ptr(new BasicType( 18 | scope.find(StdLib::OBJECT)->duplicate(), StdLib::OBJECT))); 19 | scope.insert(StdLib::STRING, auto_ptr(new BasicType( 20 | scope.find(StdLib::OBJECT)->duplicate(), StdLib::OBJECT))); 21 | scope.insert("print", auto_ptr(new BasicType( 22 | scope.find(StdLib::FUNCTION)->duplicate(), StdLib::FUNCTION))); 23 | } 24 | -------------------------------------------------------------------------------- /c2/StdLib.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _StdLib_h_ 5 | #define _StdLib_h_ 6 | 7 | /* shok standard library */ 8 | 9 | #include "Scope.h" 10 | #include "Type.h" 11 | 12 | #include 13 | #include 14 | 15 | namespace compiler { 16 | 17 | namespace StdLib { 18 | 19 | const std::string OBJECT = "object"; 20 | const std::string FUNCTION = "@"; 21 | const std::string INTEGER = "int"; 22 | const std::string STRING = "str"; 23 | 24 | void Init(Scope& scope); 25 | 26 | } 27 | 28 | } 29 | 30 | #endif // _StdLib_h_ 31 | -------------------------------------------------------------------------------- /c2/StringLiteral.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "StringLiteral.h" 5 | 6 | #include "StdLib.h" 7 | 8 | #include 9 | using boost::lexical_cast; 10 | 11 | #include 12 | using std::string; 13 | 14 | using namespace compiler; 15 | 16 | StringLiteral::StringLiteral() 17 | : m_scope(NULL) { 18 | } 19 | 20 | void StringLiteral::init(const Scope& scope) { 21 | m_scope = &scope; 22 | const Type* type = m_scope->find(StdLib::STRING); 23 | if (!type) { 24 | throw CompileError("Object for literal string does not exist in scope at depth " + lexical_cast(m_scope->depth())); 25 | } 26 | m_type.reset(type->duplicate().release()); 27 | } 28 | 29 | void StringLiteral::attach_text(const std::string& text) { 30 | m_text = text; 31 | } 32 | 33 | const Type& StringLiteral::type() const { 34 | if (!m_type) { 35 | throw CompileError("StringLiteral has no type"); 36 | } 37 | return *m_type; 38 | } 39 | 40 | std::string StringLiteral::bytecode() const { 41 | return "(str " + m_text + ")"; 42 | } 43 | -------------------------------------------------------------------------------- /c2/SymbolTable.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _SymbolTable_h_ 5 | #define _SymbolTable_h_ 6 | 7 | /* A SymbolTable is a table of named Types. The table owns the Types. 8 | * Name-lookups need to be fast but we also need to keep an ordering by 9 | * lifetime. */ 10 | 11 | #include "CompileError.h" 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace compiler { 21 | 22 | class Type; 23 | 24 | // TODO We need to be able to lookup symbols by name, but we also need to keep 25 | // track of the ordering of their lifetimes, so that they can be deleted in the 26 | // correct order in Scope::bytecode(). 27 | 28 | typedef boost::ptr_map symbol_map; 29 | typedef symbol_map::const_iterator symbol_iter; 30 | typedef symbol_map::const_reverse_iterator symbol_rev_iter; 31 | 32 | class SymbolTable { 33 | public: 34 | typedef std::vector > lifetime_vec; 35 | typedef lifetime_vec::const_iterator lifetime_iter; 36 | typedef lifetime_vec::const_reverse_iterator lifetime_rev_iter; 37 | 38 | private: 39 | symbol_map m_symbols; 40 | lifetime_vec m_lifetimes; 41 | }; 42 | 43 | } 44 | 45 | #endif // _SymbolTable_h_ 46 | -------------------------------------------------------------------------------- /c2/Variable.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Variable.h" 5 | 6 | #include 7 | using boost::lexical_cast; 8 | 9 | #include 10 | #include 11 | using std::string; 12 | 13 | using namespace compiler; 14 | 15 | Variable::Variable() 16 | : m_scope(NULL), 17 | m_varScope(NULL) { 18 | } 19 | 20 | void Variable::init(const Scope& scope) { 21 | m_scope = &scope; 22 | } 23 | 24 | void Variable::attach_name(const std::string& name) { 25 | m_name = name; 26 | m_varScope = m_scope->findScope(name); 27 | if (!m_varScope) { 28 | throw CompileError("Variable " + name + " does not exist in scope at depth " + lexical_cast(m_scope->depth())); 29 | } 30 | const Type* type = m_varScope->findLocal(name); 31 | if (!type) { 32 | throw CompileError("Lookup failure for variable " + name + " in scope at depth " + lexical_cast(m_varScope->depth())); 33 | } 34 | m_type.reset(type->duplicate().release()); 35 | } 36 | 37 | void Variable::attach_member(const std::string& member) { 38 | if (!m_type) { 39 | throw CompileError("Cannot attach member " + member + " to variable " + m_name + " that is missing a type"); 40 | } 41 | const Type* type = m_type->findMember(member); 42 | if (!type) { 43 | throw CompileError("Variable member " + fullname() + " does not exist"); 44 | } 45 | m_type = type->duplicate(); 46 | m_members.push_back(member); 47 | } 48 | 49 | const Type& Variable::type() const { 50 | if (!m_type) { 51 | throw CompileError("Variable " + fullname() + " has no type"); 52 | } 53 | return *m_type; 54 | } 55 | 56 | std::string Variable::fullname() const { 57 | std::string name = m_name; 58 | for (member_iter i = m_members.begin(); i != m_members.end(); ++i) { 59 | name += "." + *i; 60 | } 61 | return name; 62 | } 63 | 64 | std::string Variable::bytename() const { 65 | std::string name = m_varScope->bytename(m_name); 66 | for (member_iter i = m_members.begin(); i != m_members.end(); ++i) { 67 | name += "." + *i; 68 | } 69 | return name; 70 | } 71 | -------------------------------------------------------------------------------- /c2/compiler.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | /* shok static analyzer, type checker, and code generator. 5 | * 6 | * Reads lines of AST (except with unordered expressions) from the parser, 7 | * performs many checks including type checks, and emits bytecode appropriate 8 | * for the shok vm. 9 | */ 10 | 11 | #include "CompileError.h" 12 | #include "Compiler.h" 13 | 14 | #include "util/Log.h" 15 | 16 | #include 17 | #include 18 | using std::cin; 19 | using std::cout; 20 | using std::endl; 21 | using std::string; 22 | 23 | using namespace compiler; 24 | 25 | namespace { 26 | const string PROGRAM_NAME = "shok_compiler"; 27 | const string LOGFILE = "compiler.log"; 28 | } 29 | 30 | int main(int argc, char *argv[]) { 31 | if (argc < 1 || argc > 2) { 32 | cout << "usage: " << PROGRAM_NAME << " [log level]" << endl; 33 | return 1; 34 | } 35 | 36 | Log log(LOGFILE); 37 | try { 38 | if (2 == argc) { 39 | log.setLevel(argv[1]); 40 | } 41 | Compiler compiler(cin, cout); 42 | if (!compiler.execute()) { 43 | cout << "failed to compile" << endl; 44 | } 45 | } catch (const CompileError& e) { 46 | log.error(string("Compilation error: ") + e.what()); 47 | cout << endl; 48 | } catch (const std::exception& e) { 49 | log.error(string("Unknown error: ") + e.what()); 50 | } catch (...) { 51 | log.error("Unknown error"); 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /compiler/AST.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "AST.h" 5 | 6 | #include "Brace.h" 7 | #include "CompileError.h" 8 | #include "Token.h" 9 | #include "RootNode.h" 10 | #include "Operator.h" 11 | 12 | #include "util/Log.h" 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | using std::string; 19 | 20 | using namespace compiler; 21 | 22 | /* public */ 23 | 24 | AST::AST(Log& log) 25 | : m_log(log), 26 | m_root(log), 27 | m_current(&m_root) { 28 | } 29 | 30 | AST::~AST() { 31 | } 32 | 33 | void AST::reset() { 34 | m_log.info("Resetting AST. " + print()); 35 | m_current = &m_root; 36 | m_root.reset(); 37 | } 38 | 39 | void AST::insert(const Token& token) { 40 | Node* n = Node::MakeNode(m_log, &m_root, token); 41 | if (!n) { 42 | throw CompileError("Failed to make node for token " + token.name + ":" + token.value); 43 | } 44 | try { 45 | m_current = Node::InsertNode(m_log, m_current, n); 46 | } catch (RecoveredError& e) { 47 | m_current = e.getRecoveredPosition(); 48 | if (!m_current) { 49 | throw CompileError(string("Attempting to recover from error '") + e.what() + "' returned a deficient current node"); 50 | } 51 | throw; 52 | } 53 | if (!m_current) { 54 | throw CompileError("Inserting node " + n->print() + " returned a deficient current node"); 55 | } 56 | m_log.debug("AST: " + print()); 57 | } 58 | 59 | void AST::compile() { 60 | // We only actually compile code if m_current has arrived back at the root 61 | // node, m_root. This signifies a return to the outer-most (command-line) 62 | // scope. 63 | if (m_current != &m_root) { 64 | m_log.debug(" - not at root -- not ready to run"); 65 | return; 66 | } 67 | m_root.prepare(); 68 | m_root.compileNode(); 69 | } 70 | 71 | string AST::print() const { 72 | return "<" + m_root.print() + ">"; 73 | } 74 | -------------------------------------------------------------------------------- /compiler/AST.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _AST_h_ 5 | #define _AST_h_ 6 | 7 | /* Abstract Syntax Tree */ 8 | 9 | #include "Node.h" 10 | #include "RootNode.h" 11 | #include "Token.h" 12 | 13 | #include "util/Log.h" 14 | 15 | #include 16 | 17 | namespace compiler { 18 | 19 | class AST { 20 | public: 21 | AST(Log& log); 22 | ~AST(); 23 | 24 | // Reset the AST to a correct state; may destroy some uncompiled code. 25 | void reset(); 26 | // Performs the ugly work of inserting an input "AST Token" into the AST. 27 | void insert(const Token& token); 28 | // Analyze the AST and compile any appropriate, complete fragments of code 29 | void compile(); 30 | // Pretty-print the contents of the AST to a string 31 | std::string print() const; 32 | 33 | private: 34 | Log& m_log; 35 | RootNode m_root; 36 | Node* m_current; 37 | }; 38 | 39 | } 40 | 41 | #endif // _AST_h_ 42 | -------------------------------------------------------------------------------- /compiler/Arg.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Arg.h" 5 | 6 | #include "CompileError.h" 7 | #include "Identifier.h" 8 | #include "TypeSpec.h" 9 | 10 | #include 11 | #include 12 | #include 13 | using std::auto_ptr; 14 | using std::string; 15 | using std::vector; 16 | 17 | using namespace compiler; 18 | 19 | void Arg::setup() { 20 | // If two children, the first is the name. Otherwise, name is "". 21 | if (1 == children.size()) { 22 | m_typeSpec = dynamic_cast(children.at(0)); 23 | } else if (2 == children.size()) { 24 | m_typeSpec = dynamic_cast(children.at(1)); 25 | Identifier* ident = dynamic_cast(children.at(0)); 26 | if (!ident) { 27 | throw CompileError("First child of 2-child Arg " + print() + " must be an Identifier"); 28 | } 29 | m_argname = ident->getName(); 30 | } else { 31 | throw CompileError("Arg node must have 1 or 2 children"); 32 | } 33 | if (!m_typeSpec) { 34 | throw CompileError("Arg " + print() + " must have a TypeSpec child"); 35 | } 36 | } 37 | 38 | string Arg::getName() const { 39 | if (!isSetup) { 40 | throw CompileError("Cannot get name of Arg " + print() + " before it is setup"); 41 | } 42 | return m_argname; 43 | } 44 | 45 | auto_ptr Arg::getType() const { 46 | return m_typeSpec->getType(); 47 | } 48 | 49 | const Type& Arg::type() const { 50 | return m_typeSpec->type(); 51 | } 52 | 53 | auto_ptr Arg::getSpec() const { 54 | return auto_ptr(new ArgSpec(getName(), *getType().release())); 55 | } 56 | -------------------------------------------------------------------------------- /compiler/Arg.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Arg_h_ 5 | #define _Arg_h_ 6 | 7 | /* Arg 8 | * 9 | * A Node representing a function argument as specified in the function's 10 | * declaration. For example: 11 | * new x = @(a:b, c) {} 12 | * There are two Args: one is named a and has type b. c is declared as a type 13 | * but with no name. 14 | */ 15 | 16 | #include "ArgSpec.h" 17 | #include "RootNode.h" 18 | #include "Token.h" 19 | #include "TypeSpec.h" 20 | 21 | #include "util/Log.h" 22 | 23 | #include 24 | #include 25 | 26 | namespace compiler { 27 | 28 | class Arg : public Node { 29 | public: 30 | Arg(Log& log, RootNode*const root, const Token& token) 31 | : Node(log, root, token), 32 | m_typeSpec(NULL) {} 33 | virtual void setup(); 34 | 35 | // If the arg is unnamed, returns the empty string 36 | std::string getName() const; 37 | std::auto_ptr getType() const; 38 | const Type& type() const; 39 | std::auto_ptr getSpec() const; 40 | 41 | private: 42 | std::string m_argname; // provided by first child, if two children 43 | TypeSpec* m_typeSpec; // last child 44 | }; 45 | 46 | } 47 | 48 | #endif // _Arg_h_ 49 | -------------------------------------------------------------------------------- /compiler/ArgSpec.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _ArgSpec_h_ 5 | #define _ArgSpec_h_ 6 | 7 | /* The specification of a function argument */ 8 | 9 | #include "Type.h" 10 | 11 | #include "util/Log.h" 12 | 13 | #include 14 | #include 15 | 16 | namespace compiler { 17 | 18 | class ArgSpec { 19 | public: 20 | ArgSpec(const std::string& name, 21 | Type& type) 22 | //Object* defaultValue, 23 | //bool optional = false) 24 | : m_name(name), 25 | m_type(type) {} 26 | 27 | std::auto_ptr duplicate() const { 28 | return std::auto_ptr(new ArgSpec(m_name, *m_type.duplicate().release())); 29 | } 30 | 31 | const Type& type() const { 32 | return m_type; 33 | } 34 | 35 | std::string print() const { 36 | return "(argspec:" + m_name + ":" + m_type.print() + ")"; 37 | } 38 | 39 | private: 40 | std::string m_name; 41 | Type& m_type; 42 | }; 43 | 44 | } 45 | 46 | #endif // _ArgSpec_h_ 47 | -------------------------------------------------------------------------------- /compiler/Args.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Args.h" 5 | 6 | #include "Arg.h" 7 | #include "Common.h" 8 | #include "CompileError.h" 9 | 10 | #include 11 | #include 12 | using std::string; 13 | using std::vector; 14 | 15 | using namespace compiler; 16 | 17 | void Args::setup() { 18 | for (child_iter i = children.begin(); i != children.end(); ++i) { 19 | Arg* arg = dynamic_cast(*i); 20 | if (!arg) { 21 | throw CompileError("Args " + print() + " found non-Arg child " + (*i)->print()); 22 | } 23 | m_args.push_back(arg); 24 | } 25 | } 26 | 27 | const arg_vec& Args::getArgs() const { 28 | if (!isSetup) { 29 | throw CompileError("Cannot get args from Args " + print() + " before it is setup"); 30 | } 31 | return m_args; 32 | } 33 | -------------------------------------------------------------------------------- /compiler/Args.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Args_h_ 5 | #define _Args_h_ 6 | 7 | /* Args 8 | * 9 | * A list of Arg, as seen in a function definition. 10 | */ 11 | 12 | #include "Arg.h" 13 | #include "Common.h" 14 | #include "RootNode.h" 15 | #include "Token.h" 16 | 17 | #include "util/Log.h" 18 | 19 | #include 20 | 21 | namespace compiler { 22 | 23 | class Args : public Node { 24 | public: 25 | Args(Log& log, RootNode*const root, const Token& token) 26 | : Node(log, root, token) {} 27 | virtual void setup(); 28 | 29 | const arg_vec& getArgs() const; 30 | 31 | private: 32 | arg_vec m_args; 33 | }; 34 | 35 | } 36 | 37 | #endif // _Args_h_ 38 | -------------------------------------------------------------------------------- /compiler/Brace.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Brace.h" 5 | 6 | #include "CompileError.h" 7 | 8 | #include 9 | using std::string; 10 | 11 | using namespace compiler; 12 | 13 | bool Brace::isOpen() const { 14 | return m_isOpen; 15 | } 16 | 17 | bool Brace::isIrrelevant() const { 18 | return "(" == name || ")" == name; 19 | } 20 | 21 | bool Brace::matchesCloseBrace(Brace* closeBrace) const { 22 | if (!m_isOpen) { 23 | throw CompileError("A closing brace will never match with another closing brace... :P"); 24 | } 25 | if (("[" == name && "]" == closeBrace->name) || 26 | ("(" == name && ")" == closeBrace->name) || 27 | ("{" == name && "}" == closeBrace->name)) { 28 | return true; 29 | } 30 | return false; 31 | } 32 | 33 | void Brace::setup() { 34 | if (("(" == name || ")" == name) && children.size() < 1) { 35 | throw CompileError("Empty parens in the AST are not allowed"); 36 | } 37 | } 38 | 39 | void Brace::compile() { 40 | if (0 == children.size()) { 41 | return; 42 | } 43 | throw CompileError("Brace::compile is not setup"); 44 | } 45 | -------------------------------------------------------------------------------- /compiler/Brace.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Brace_h_ 5 | #define _Brace_h_ 6 | 7 | /* Brace -- actually, just an AST token that requires a match */ 8 | 9 | #include "Node.h" 10 | #include "RootNode.h" 11 | #include "Token.h" 12 | 13 | #include "util/Log.h" 14 | 15 | namespace compiler { 16 | 17 | class Brace : public Node { 18 | public: 19 | Brace(Log& log, RootNode*const root, const Token& token, bool isOpen) 20 | : Node(log, root, token), 21 | m_isOpen(isOpen) {} 22 | ~Brace() {} 23 | 24 | bool isOpen() const; 25 | bool isIrrelevant() const; 26 | bool matchesCloseBrace(Brace* closeBrace) const; 27 | 28 | virtual void setup(); 29 | virtual void compile(); 30 | 31 | private: 32 | bool m_isOpen; 33 | }; 34 | 35 | } 36 | 37 | #endif // _Brace_h_ 38 | -------------------------------------------------------------------------------- /compiler/Command.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Command.h" 5 | 6 | #include "Block.h" 7 | #include "CommandFragment.h" 8 | #include "CompileError.h" 9 | #include "Node.h" 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | using std::string; 17 | using std::vector; 18 | 19 | using namespace compiler; 20 | 21 | void Command::setup() { 22 | } 23 | 24 | void Command::compile() { 25 | // Codegen all the child blocks. If it's a single code block, run it. 26 | // Otherwise, run all the expression blocks, take their cmdtext, and tell 27 | // the shell what command it should run on our behalf. 28 | if (1 == children.size()) { 29 | Block* block = dynamic_cast(children.front()); 30 | if (block && block->isCodeBlock()) { 31 | block->compileNode(); 32 | return; 33 | } 34 | } 35 | string cmd; 36 | for (Node::child_iter i = children.begin(); i != children.end(); ++i) { 37 | Block* block = dynamic_cast(*i); 38 | // Code blocks should have already been dealt with 39 | if (block && block->isCodeBlock()) { 40 | throw CompileError("Command " + print() + " found inappropriately-positioned code block"); 41 | } 42 | CommandFragment* frag = dynamic_cast(*i); 43 | if (frag) { 44 | frag->compileNode(); 45 | cmd += frag->cmdText(); 46 | } else if (block) { 47 | block->compileNode(); 48 | cmd += block->cmdText(); 49 | } else { 50 | throw CompileError("Command has an unsupported child: " + string(**i)); 51 | } 52 | } 53 | log.info("RUNNING CMD: <" + cmd + ">"); 54 | std::cout << "CMD:" << cmd << std::endl; 55 | string line; 56 | std::getline(std::cin, line); 57 | int returnCode = boost::lexical_cast(line); 58 | log.info("RETURN CODE: " + boost::lexical_cast(returnCode)); 59 | } 60 | -------------------------------------------------------------------------------- /compiler/Command.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Command_h_ 5 | #define _Command_h_ 6 | 7 | /* Command-line program invocation 8 | * 9 | * This is a Brace because of the way it happens to be represented in the 10 | * string AST we receive from the parser. 11 | */ 12 | 13 | #include "Brace.h" 14 | #include "RootNode.h" 15 | #include "Token.h" 16 | 17 | #include "util/Log.h" 18 | 19 | namespace compiler { 20 | 21 | class Command : public Brace { 22 | public: 23 | Command(Log& log, RootNode*const root, const Token& token) 24 | : Brace(log, root, token, true) {} 25 | virtual void setup(); 26 | virtual void compile(); 27 | }; 28 | 29 | } 30 | 31 | #endif // _Command_h_ 32 | -------------------------------------------------------------------------------- /compiler/CommandFragment.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "CommandFragment.h" 5 | 6 | #include "CompileError.h" 7 | 8 | #include 9 | using std::string; 10 | 11 | using namespace compiler; 12 | 13 | void CommandFragment::setup() { 14 | } 15 | 16 | void CommandFragment::compile() { 17 | } 18 | 19 | string CommandFragment::cmdText() const { 20 | return value; 21 | } 22 | -------------------------------------------------------------------------------- /compiler/CommandFragment.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _CommandFragment_h_ 5 | #define _CommandFragment_h_ 6 | 7 | /* CommandFragment: a piece of a command-line */ 8 | 9 | #include "Node.h" 10 | #include "RootNode.h" 11 | #include "Token.h" 12 | 13 | #include "util/Log.h" 14 | 15 | #include 16 | 17 | namespace compiler { 18 | 19 | class CommandFragment : public Node { 20 | public: 21 | CommandFragment(Log& log, RootNode*const root, const Token& token) 22 | : Node(log, root, token) {} 23 | virtual void setup(); 24 | virtual void compile(); 25 | virtual std::string cmdText() const; 26 | }; 27 | 28 | } 29 | 30 | #endif // _CommandFragment_h_ 31 | -------------------------------------------------------------------------------- /compiler/Common.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Common_h_ 5 | #define _Common_h_ 6 | 7 | /* Some common types used throughout the program. Here to avoid circular 8 | * dependencies (no typedef forward-declarations in C++) 9 | */ 10 | 11 | #include 12 | 13 | namespace compiler { 14 | 15 | class Arg; 16 | class ArgSpec; 17 | class Object; 18 | class Type; 19 | 20 | // An ObjectStore changeset commit ID 21 | typedef int change_id; 22 | 23 | // List of types that a function caller will provide 24 | typedef std::vector paramtype_vec; 25 | typedef paramtype_vec::const_iterator paramtype_iter; 26 | 27 | // List of actual Object* arguments provided by a function caller 28 | typedef std::vector param_vec; 29 | typedef param_vec::const_iterator param_iter; 30 | typedef param_vec::iterator param_mod_iter; 31 | 32 | // The function's specification of the arguments it accepts 33 | typedef std::vector argspec_vec; 34 | typedef argspec_vec::const_iterator argspec_iter; 35 | 36 | // A list of Arg nodes that hold function argument specifications 37 | typedef std::vector arg_vec; 38 | typedef arg_vec::const_iterator arg_iter; 39 | 40 | } 41 | 42 | #endif // _Common_h_ 43 | -------------------------------------------------------------------------------- /compiler/CompileError.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _CompileError_h_ 5 | #define _CompileError_h_ 6 | 7 | /* Compilation errors. Used for both internal compiler-code errors as well as 8 | * errors regarding the input AST, or errors in the generated code. 9 | * 10 | * Anywhere in the code that an error occurs, a CompileError is thrown. 11 | * Node::insertNode() can catch some of them, deem them "recoverable", and 12 | * throws a RecoveredError instead. The RecoveredError contains a good known 13 | * position along the AST which we should use as the new current location. 14 | * AST::insertNode() catches this and uses this known position, and then 15 | * re-throws the RecoveredError again. 16 | * 17 | * The top-level REPL (main) catches both types of errors. If it's not a 18 | * recovered error, then it resets the AST (clears any uncompiled code and 19 | * returns us to the root scope). 20 | */ 21 | 22 | #include "util/Log.h" 23 | 24 | #include 25 | 26 | namespace compiler { 27 | 28 | class Node; 29 | 30 | class CompileError : public std::runtime_error { 31 | public: 32 | CompileError(const std::string& what) : std::runtime_error(what) {} 33 | CompileError(Log& log, const std::string& what) : std::runtime_error(what) { 34 | log.error(what); 35 | } 36 | }; 37 | 38 | class RecoveredError : public std::runtime_error { 39 | public: 40 | RecoveredError(CompileError& originalError, Node* recoveredPosition) 41 | : std::runtime_error(originalError.what()), 42 | m_recoveredPosition(recoveredPosition) {} 43 | 44 | Node* getRecoveredPosition() const { return m_recoveredPosition; } 45 | 46 | private: 47 | Node* m_recoveredPosition; 48 | }; 49 | 50 | } 51 | 52 | #endif // _CompileError_h_ 53 | -------------------------------------------------------------------------------- /compiler/Expression.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Expression_h_ 5 | #define _Expression_h_ 6 | 7 | /* Expression 8 | * 9 | * This wraps an expression. Each child could be an atom (literal, variable 10 | * name, etc.) or the top operator of an expression tree. 11 | * 12 | * The operators are given to us by the AST (parser) in a ridiculous and 13 | * flattened ordering, so at setup() time we must arrange our children into a 14 | * tree and then reorder them for operator precedence. Then we validate the 15 | * operators bottom-up. 16 | * 17 | * This single expression may be owned by an expression block, in which case 18 | * the expression is meant to compile to an object on which we'll call 19 | * ->str.escape() and then provide this text as a command-line fragment. 20 | * 21 | * The expression's Type is determined at setup() time. 22 | */ 23 | 24 | #include "Operator.h" 25 | #include "OperatorParser.h" 26 | #include "RootNode.h" 27 | #include "Token.h" 28 | #include "Type.h" 29 | #include "TypedNode.h" 30 | 31 | #include "util/Log.h" 32 | 33 | #include 34 | #include 35 | 36 | namespace compiler { 37 | 38 | class Expression : public TypedNode, public OperatorParser { 39 | public: 40 | Expression(Log& log, RootNode*const root, const Token& token) 41 | : TypedNode(log, root, token), 42 | OperatorParser(log) {} 43 | virtual void setup(); 44 | virtual void compile(); 45 | virtual std::string cmdText() const; 46 | 47 | // Get the Object resulting from the expression's compiled code (?). 48 | std::auto_ptr getObject(const std::string& newName) const; 49 | 50 | private: 51 | // from TypedNode 52 | virtual void computeType(); 53 | }; 54 | 55 | } 56 | 57 | #endif // _Expression_h_ 58 | -------------------------------------------------------------------------------- /compiler/Identifier.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Identifier.h" 5 | 6 | #include "CompileError.h" 7 | 8 | #include 9 | using std::string; 10 | 11 | using namespace compiler; 12 | 13 | void Identifier::setup() { 14 | if (children.size() != 0) { 15 | throw CompileError("Identifier node cannot have children"); 16 | } 17 | if ("" == value) { 18 | throw CompileError("Identifier cannot have blank value"); 19 | } 20 | } 21 | 22 | void Identifier::compile() { 23 | } 24 | -------------------------------------------------------------------------------- /compiler/Identifier.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Identifier_h_ 5 | #define _Identifier_h_ 6 | 7 | /* Identifier 8 | * 9 | * A minimal label that refers to an object or object-member that may or may 10 | * not yet exist. Held by nodes such as Variable and NewInit. 11 | */ 12 | 13 | #include "Node.h" 14 | #include "RootNode.h" 15 | #include "Token.h" 16 | 17 | #include "util/Log.h" 18 | 19 | #include 20 | 21 | namespace compiler { 22 | 23 | class Identifier : public Node { 24 | public: 25 | Identifier(Log& log, RootNode*const root, const Token& token) 26 | : Node(log, root, token) {} 27 | virtual void setup(); 28 | virtual void compile(); 29 | 30 | std::string getName() const { return value; } 31 | 32 | private: 33 | }; 34 | 35 | } 36 | 37 | #endif // _Identifier_h_ 38 | -------------------------------------------------------------------------------- /compiler/IsVar.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "IsVar.h" 5 | 6 | #include "CompileError.h" 7 | #include "Identifier.h" 8 | 9 | #include 10 | #include 11 | #include 12 | using std::auto_ptr; 13 | using std::cout; 14 | using std::endl; 15 | using std::string; 16 | 17 | using namespace compiler; 18 | 19 | void IsVar::setup() { 20 | if (children.size() < 1) { 21 | throw CompileError("IsVar must have >= 1 children"); 22 | } 23 | auto_ptr current(NULL); 24 | bool found = true; 25 | string missingName; 26 | size_t i = 0; 27 | for (; i < children.size(); ++i) { 28 | Identifier* ident = dynamic_cast(children.at(i)); 29 | if (!ident) { 30 | throw CompileError("Children of IsVar " + print() + " must be Identifiers"); 31 | } 32 | if (!current.get()) { 33 | missingName = ident->getName(); 34 | Symbol* s = parentScope->getSymbol(ident->getName()); 35 | if (!s) { 36 | found = false; 37 | break; 38 | } 39 | current = s->type->duplicate(); 40 | } else { 41 | missingName += "." + ident->getName(); 42 | current = current->getMemberType(ident->getName()); 43 | if (!current.get()) { 44 | found = false; 45 | break; 46 | } 47 | } 48 | } 49 | 50 | string msg; 51 | if (found) { 52 | msg = "true"; 53 | } else if (i < children.size()-1) { 54 | msg = "Object " + missingName + " does not exist"; 55 | } else { 56 | msg = "false"; 57 | } 58 | cout << "PRINT:" << msg << endl; 59 | } 60 | 61 | // As an "instant" Statement, we should never even get to this stage 62 | void IsVar::compile() { 63 | throw CompileError("Cannot compile instant statement " + print()); 64 | } 65 | -------------------------------------------------------------------------------- /compiler/IsVar.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _IsVar_h_ 5 | #define _IsVar_h_ 6 | 7 | /* IsVar statement 8 | * 9 | * This is an ugly interpreter built-in being temporarily implemented as a 10 | * statement, that somehow magically displays a true/false value to the user 11 | * via hacks. 12 | */ 13 | 14 | #include "RootNode.h" 15 | #include "Statement.h" 16 | #include "Token.h" 17 | 18 | #include "util/Log.h" 19 | 20 | #include 21 | 22 | namespace compiler { 23 | 24 | class IsVar : public Statement { 25 | public: 26 | IsVar(Log& log, RootNode*const root, const Token& token) 27 | : Statement(log, root, token) {} 28 | virtual void setup(); 29 | virtual void compile(); 30 | virtual bool isInstant() const { return true; } 31 | 32 | private: 33 | }; 34 | 35 | } 36 | 37 | #endif // _IsVar_h_ 38 | -------------------------------------------------------------------------------- /compiler/Makefile.am: -------------------------------------------------------------------------------- 1 | UTIL_DIR = ../util 2 | UTIL_SRCS = \ 3 | $(UTIL_DIR)/Log.cpp \ 4 | $(UTIL_DIR)/Log.h 5 | 6 | COMMON_SRCS = $(UTIL_SRCS) 7 | 8 | bin_PROGRAMS = shok_compiler 9 | shok_compiler_SOURCES = $(COMMON_SRCS) \ 10 | Arg.cpp \ 11 | Arg.h \ 12 | Args.cpp \ 13 | Args.h \ 14 | ArgSpec.h \ 15 | AST.cpp \ 16 | AST.h \ 17 | Block.cpp \ 18 | Block.h \ 19 | Brace.cpp \ 20 | Brace.h \ 21 | Command.cpp \ 22 | Command.h \ 23 | CommandFragment.cpp \ 24 | CommandFragment.h \ 25 | Common.h \ 26 | CompileError.h \ 27 | Expression.cpp \ 28 | Expression.h \ 29 | Function.cpp \ 30 | Function.h \ 31 | Identifier.cpp \ 32 | Identifier.h \ 33 | IsVar.cpp \ 34 | IsVar.h \ 35 | Method.cpp \ 36 | Method.h \ 37 | New.cpp \ 38 | New.h \ 39 | NewInit.cpp \ 40 | NewInit.h \ 41 | Node.cpp \ 42 | Node.h \ 43 | Object.cpp \ 44 | Object.h \ 45 | ObjectLiteral.cpp \ 46 | ObjectLiteral.h \ 47 | Operator.cpp \ 48 | Operator.h \ 49 | OperatorParser.cpp \ 50 | OperatorParser.h \ 51 | ProcCall.cpp \ 52 | ProcCall.h \ 53 | Returns.cpp \ 54 | Returns.h \ 55 | RootNode.cpp \ 56 | RootNode.h \ 57 | Scope.cpp \ 58 | Scope.h \ 59 | Statement.h \ 60 | StdLib.cpp \ 61 | StdLib.h \ 62 | Symbol.h \ 63 | SymbolTable.cpp \ 64 | SymbolTable.h \ 65 | Token.cpp \ 66 | Token.h \ 67 | Type.cpp \ 68 | Type.h \ 69 | TypedNode.cpp \ 70 | TypedNode.h \ 71 | TypeSpec.cpp \ 72 | TypeSpec.h \ 73 | Variable.cpp \ 74 | Variable.h \ 75 | compile.cpp 76 | -------------------------------------------------------------------------------- /compiler/Method.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Method.h" 5 | 6 | #include "Arg.h" 7 | 8 | #include 9 | using std::auto_ptr; 10 | 11 | using namespace compiler; 12 | 13 | Method::Method(const arg_vec* args, 14 | auto_ptr returnType, 15 | auto_ptr body) 16 | : m_returnType(returnType), m_body(body) { 17 | if (args) { 18 | for (arg_iter i = args->begin(); i != args->end(); ++i) { 19 | m_args.push_back((*i)->getSpec().release()); 20 | } 21 | } 22 | } 23 | 24 | Method::Method(const argspec_vec* args, 25 | auto_ptr returnType, 26 | auto_ptr body) 27 | : m_returnType(returnType), m_body(body) { 28 | if (args) { 29 | for (argspec_iter i = args->begin(); i != args->end(); ++i) { 30 | m_args.push_back((*i)->duplicate().release()); 31 | } 32 | } 33 | } 34 | 35 | Method::~Method() { 36 | for (argspec_iter i = m_args.begin(); i != m_args.end(); ++i) { 37 | delete *i; 38 | } 39 | } 40 | 41 | /* 42 | bool Method::isEquivalentTo(const Method& rhs) const { 43 | // TODO fix this to support named or optional arguments 44 | // TODO eventually we'll want smarter dispatch, where this will do something 45 | // like areArgsEquivalent() (not Identical, that's not correct). 46 | return m_args.size() == rhs.m_args.size(); 47 | } 48 | 49 | // Check if the caller's list of argument types is compatible with this method. 50 | // Note that m_args is an argspec_vec while rhs_args is a type_list. 51 | bool Method::areArgsCompatible(const type_list& rhs_args) const { 52 | return m_args.size() == rhs_args.size(); 53 | } 54 | */ 55 | -------------------------------------------------------------------------------- /compiler/Method.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Method_h_ 5 | #define _Method_h_ 6 | 7 | /* Method: arguments, return type, and code body. Owned by Object. */ 8 | 9 | #include "Common.h" 10 | #include "Type.h" 11 | 12 | #include "util/Log.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace compiler { 19 | 20 | class Block; 21 | 22 | class Method { 23 | public: 24 | Method(const arg_vec* args, 25 | std::auto_ptr returnType, 26 | std::auto_ptr body); 27 | Method(const argspec_vec* args, 28 | std::auto_ptr returnType, 29 | std::auto_ptr body); 30 | ~Method(); 31 | 32 | /* 33 | std::auto_ptr duplicate() const { 34 | return std::auto_ptr(new Method(&m_args, m_returnType->duplicate(), m_body->duplicate())); 35 | } 36 | */ 37 | 38 | const argspec_vec& args() const { 39 | return m_args; 40 | } 41 | 42 | const Type* returnType() const { 43 | return m_returnType.get(); 44 | } 45 | 46 | //bool isEquivalentTo(const Method& rhs) const; 47 | //bool areArgsCompatible(const type_list& rhs_args) const; 48 | 49 | private: 50 | argspec_vec m_args; 51 | std::auto_ptr m_returnType; 52 | std::auto_ptr m_body; 53 | }; 54 | 55 | } 56 | 57 | #endif // _Method_h_ 58 | -------------------------------------------------------------------------------- /compiler/New.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "New.h" 5 | 6 | #include "CompileError.h" 7 | #include "NewInit.h" 8 | 9 | #include 10 | using std::string; 11 | 12 | using namespace compiler; 13 | 14 | void New::setup() { 15 | // Children are inits 16 | for (child_iter i = children.begin(); i != children.end(); ++i) { 17 | NewInit* init = dynamic_cast(*i); 18 | if (!init) { 19 | throw CompileError("New statement's children must all be NewInit nodes"); 20 | } 21 | } 22 | } 23 | 24 | void New::analyze() { 25 | for (child_iter i = children.begin(); i != children.end(); ++i) { 26 | NewInit* init = dynamic_cast(*i); 27 | init->prepare(); 28 | } 29 | } 30 | 31 | // Children will have already been compiled (commit their changesets) 32 | void New::compile() { 33 | for (child_iter i = children.begin(); i != children.end(); ++i) { 34 | NewInit* init = dynamic_cast(*i); 35 | init->codegen(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /compiler/New.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _New_h_ 5 | #define _New_h_ 6 | 7 | /* New statement */ 8 | 9 | #include "RootNode.h" 10 | #include "Statement.h" 11 | #include "Token.h" 12 | 13 | #include "util/Log.h" 14 | 15 | #include 16 | 17 | namespace compiler { 18 | 19 | class New : public Statement { 20 | public: 21 | New(Log& log, RootNode*const root, const Token& token) 22 | : Statement(log, root, token) {} 23 | 24 | virtual void setup(); 25 | virtual void analyze(); 26 | virtual void compile(); 27 | 28 | private: 29 | }; 30 | 31 | } 32 | 33 | #endif // _New_h_ 34 | -------------------------------------------------------------------------------- /compiler/ObjectLiteral.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _ObjectLiteral_h_ 5 | #define _ObjectLiteral_h_ 6 | 7 | /* Object Literals */ 8 | 9 | #include "Block.h" 10 | #include "NewInit.h" 11 | #include "Token.h" 12 | #include "TypedNode.h" 13 | 14 | #include "util/Log.h" 15 | 16 | #include 17 | #include 18 | 19 | namespace compiler { 20 | 21 | class ObjectLiteral : public TypedNode { 22 | public: 23 | ObjectLiteral(Log& log, RootNode*const root, const Token& token) 24 | : TypedNode(log, root, token), 25 | m_body(NULL) {} 26 | 27 | virtual void setup(); 28 | virtual void compile(); 29 | std::auto_ptr makeObject(const std::string& newName) const; 30 | 31 | private: 32 | typedef std::vector init_vec; 33 | typedef init_vec::const_iterator init_iter; 34 | 35 | // from TypedNode 36 | virtual void computeType(); 37 | Block* m_body; 38 | init_vec m_inits; 39 | }; 40 | 41 | } 42 | 43 | #endif // _ObjectLiteral_h_ 44 | -------------------------------------------------------------------------------- /compiler/OperatorParser.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _OperatorParser_h_ 5 | #define _OperatorParser_h_ 6 | 7 | /* Operator Parser 8 | * 9 | * An OperatorParser is a Node that is provided by the input-AST alongside a 10 | * flattened operator tree. For example: 11 | * 12 | * (exp (var ID:'a') PLUS (var ID:'b') STAR MINUS (var ID:'c')) 13 | * 14 | * Expression and TypeSpec are two OperatorParsers. 15 | * 16 | * The OperatorParser is noticed by Node::InsertNode() and handles the logic 17 | * for parsing these special structures; organizing the operators on-the-fly 18 | * as-they-come into a tree that accounts for operator precedence while 19 | * simultaneously allowing us to perform early static analysis on any of the 20 | * elements between operators. 21 | * 22 | * Specifically, we employ Pratt (aka TDOP: Top-Down Operator Precedence 23 | * parsing) to let us setupNode() nodes as quickly as possible. 24 | */ 25 | 26 | #include "Node.h" 27 | #include "Operator.h" 28 | 29 | #include "util/Log.h" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace compiler { 36 | 37 | class OperatorParser { 38 | public: 39 | OperatorParser(Log& log) 40 | : m_log(log), 41 | m_infixing(false) {} 42 | void insertNode(Node* node); 43 | Node* finalizeParse(); 44 | 45 | private: 46 | Log& m_log; 47 | bool m_infixing; 48 | typedef std::pair stack_pair; 49 | typedef std::vector stack_vec; 50 | stack_vec m_stack; 51 | }; 52 | 53 | } 54 | 55 | #endif // _OperatorParser_h_ 56 | -------------------------------------------------------------------------------- /compiler/ProcCall.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "ProcCall.h" 5 | 6 | #include "Expression.h" 7 | #include "CompileError.h" 8 | #include "Function.h" 9 | 10 | #include 11 | #include 12 | #include 13 | using std::auto_ptr; 14 | using std::string; 15 | using std::vector; 16 | 17 | using namespace compiler; 18 | 19 | void ProcCall::setup() { 20 | if (children.size() < 1) { 21 | throw CompileError("ProcCall must have >= 1 children"); 22 | } 23 | Variable* var = dynamic_cast(children.at(0)); 24 | if (!var) { 25 | throw CompileError("ProcCall first child must be a Variable"); 26 | } 27 | m_object = &var->getObject(); 28 | /* 29 | if (!m_object->isFunction()) { 30 | throw CompileError("ProcCall cannot call a non-function"); 31 | } 32 | */ 33 | for (child_iter i = children.begin()+1; i != children.end(); ++i) { 34 | Expression* exp = dynamic_cast(*i); 35 | if (!exp) { 36 | throw CompileError("ProcCall params must be Expressions"); 37 | } 38 | m_paramexps.push_back(exp); 39 | m_paramtypes.push_back(&exp->type()); 40 | } 41 | // Verify that the function has a signature for these param types 42 | /* 43 | if (!m_object->takesArgs(m_paramtypes)) { 44 | throw CompileError("Function " + m_object->print() + " does not accept the provided parameters"); 45 | } 46 | */ 47 | } 48 | 49 | void ProcCall::compile() { 50 | // The expressions of m_paramexps have all been compiled. Call the function 51 | // on their resulting objects. The object being called gets ownership of the 52 | // params. 53 | param_vec params; 54 | for (exp_iter i = m_paramexps.begin(); i != m_paramexps.end(); ++i) { 55 | // TODO: ask the object for the argument names it wants to use (on the 56 | // specific signature we're calling) 57 | params.push_back((*i)->getObject("(some arg)").release()); 58 | } 59 | //auto_ptr ret = m_object->call(params); 60 | } 61 | 62 | void ProcCall::computeType() { 63 | // ProcCall type is the return type of the function 64 | //m_type = m_object->getPossibleReturnTypes(m_paramtypes); 65 | } 66 | -------------------------------------------------------------------------------- /compiler/ProcCall.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _ProcCall_h_ 5 | #define _ProcCall_h_ 6 | 7 | /* ProcCall (the calling of a function/procedure/method) */ 8 | 9 | #include "Common.h" 10 | #include "Function.h" 11 | #include "Object.h" 12 | #include "Type.h" 13 | #include "Variable.h" 14 | 15 | #include "util/Log.h" 16 | 17 | #include 18 | #include 19 | 20 | namespace compiler { 21 | 22 | class ProcCall : public TypedNode { 23 | public: 24 | ProcCall(Log& log, RootNode*const root, const Token& token) 25 | : TypedNode(log, root, token), 26 | m_object(NULL) {} 27 | virtual void setup(); 28 | virtual void compile(); 29 | 30 | private: 31 | // from TypedNode 32 | virtual void computeType(); 33 | Object* m_object; 34 | typedef std::vector exp_vec; 35 | typedef exp_vec::const_iterator exp_iter; 36 | exp_vec m_paramexps; 37 | paramtype_vec m_paramtypes; 38 | }; 39 | 40 | } 41 | 42 | #endif // _ProcCall_h_ 43 | -------------------------------------------------------------------------------- /compiler/Returns.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Returns.h" 5 | 6 | #include "CompileError.h" 7 | #include "TypeSpec.h" 8 | 9 | #include 10 | #include 11 | #include 12 | using std::auto_ptr; 13 | using std::string; 14 | using std::vector; 15 | 16 | using namespace compiler; 17 | 18 | void Returns::setup() { 19 | if (children.size() != 1) { 20 | throw CompileError("TypeSpec" + print() + " must have 1 child"); 21 | } 22 | m_typeSpec = dynamic_cast(children.at(0)); 23 | if (!m_typeSpec) { 24 | throw CompileError("Arg " + print() + " child must be a TypeSpec"); 25 | } 26 | } 27 | 28 | string Returns::getName() const { 29 | if (!isSetup || !m_typeSpec) { 30 | throw CompileError("Cannot get name of Function-Returns " + print() + " that has not been setup or is missing typespec"); 31 | } 32 | return m_typeSpec->getTypeName(); 33 | } 34 | 35 | auto_ptr Returns::getType() const { 36 | if (!isSetup || !m_typeSpec) { 37 | throw CompileError("Cannot get type of Function-Returns " + print() + " that has not been setup or is missing typespec"); 38 | } 39 | return m_typeSpec->getType(); 40 | } 41 | -------------------------------------------------------------------------------- /compiler/Returns.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Returns_h_ 5 | #define _Returns_h_ 6 | 7 | /* Returns 8 | * 9 | * Function return type, which (eventually) might have a name. 10 | */ 11 | 12 | #include "RootNode.h" 13 | #include "Token.h" 14 | #include "TypeSpec.h" 15 | 16 | #include "util/Log.h" 17 | 18 | namespace compiler { 19 | 20 | class Returns : public Node { 21 | public: 22 | Returns(Log& log, RootNode*const root, const Token& token) 23 | : Node(log, root, token), 24 | m_typeSpec(NULL) {} 25 | virtual void setup(); 26 | 27 | std::string getName() const; 28 | std::auto_ptr getType() const; 29 | 30 | private: 31 | TypeSpec* m_typeSpec; 32 | }; 33 | 34 | } 35 | 36 | #endif // _Returns_h_ 37 | -------------------------------------------------------------------------------- /compiler/RootNode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "RootNode.h" 5 | 6 | #include "CompileError.h" 7 | #include "Token.h" 8 | 9 | #include "util/Log.h" 10 | 11 | using namespace compiler; 12 | 13 | /* public */ 14 | 15 | RootNode::RootNode(Log& log) 16 | : Node(log, NULL, Token(":ROOT:")), 17 | m_scope(log), 18 | m_stdlib(log, m_scope) { 19 | isInit = true; 20 | isSetup = true; 21 | isAnalyzed = true; 22 | } 23 | 24 | // Reset any pending-compilation children, and undo any pending changes to the 25 | // scope. Note that this does not clear out variables that are already commit 26 | // in the global scope; we only let that happen on destruction. 27 | void RootNode::reset() { 28 | log.debug("Resetting root node"); 29 | clearChildren(); 30 | m_scope.revertAll(); 31 | } 32 | 33 | void RootNode::prepare() { 34 | isCompiled = false; 35 | } 36 | 37 | /* protected */ 38 | 39 | void RootNode::setup() { 40 | throw CompileError("Cannot setup the root node"); 41 | } 42 | 43 | void RootNode::compile() { 44 | for (child_iter i = children.begin(); i != children.end(); ++i) { 45 | (*i)->compileNode(); 46 | // TODO we could delete the child here, but that's messy to deal with 47 | } 48 | clearChildren(); 49 | } 50 | 51 | void RootNode::clearChildren() { 52 | while (!children.empty()) { 53 | delete children.front(); 54 | children.pop_front(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /compiler/RootNode.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _RootNode_h_ 5 | #define _RootNode_h_ 6 | 7 | /* Root node of the AST 8 | * 9 | * Its children are all Commands, although this is not enforced. 10 | */ 11 | 12 | #include "Node.h" 13 | #include "Scope.h" 14 | #include "StdLib.h" 15 | 16 | #include "util/Log.h" 17 | 18 | namespace compiler { 19 | 20 | class RootNode : public Node { 21 | public: 22 | RootNode(Log&); 23 | 24 | // Reset the whole AST; destroys all children 25 | void reset(); 26 | // Prepare the RootNode for another compilation 27 | void prepare(); 28 | 29 | virtual Scope* getScope() { return &m_scope; } 30 | 31 | protected: 32 | virtual void setup(); 33 | virtual void compile(); 34 | 35 | private: 36 | void clearChildren(); 37 | Scope m_scope; 38 | StdLib m_stdlib; 39 | }; 40 | 41 | } 42 | 43 | #endif // _RootNode_h_ 44 | -------------------------------------------------------------------------------- /compiler/Statement.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Statement_h_ 5 | #define _Statement_h_ 6 | 7 | /* Statement 8 | * 9 | * Abstract base class for statements. A statement has an analyze() method, 10 | * called by Node::analyzeNode(), that performs whatever static analysis is 11 | * appropriate for that statement. 12 | */ 13 | 14 | #include "Node.h" 15 | #include "RootNode.h" 16 | #include "Token.h" 17 | 18 | #include "util/Log.h" 19 | 20 | namespace compiler { 21 | 22 | class Statement : public Node { 23 | public: 24 | Statement(Log& log, RootNode*const root, const Token& token) 25 | : Node(log, root, token) {} 26 | 27 | virtual void analyze() {} 28 | virtual bool isInstant() const { return false; } 29 | }; 30 | 31 | } 32 | 33 | #endif // _Statement_h_ 34 | -------------------------------------------------------------------------------- /compiler/StdLib.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "StdLib.h" 5 | 6 | #include "util/Log.h" 7 | 8 | #include 9 | #include 10 | using std::auto_ptr; 11 | using std::vector; 12 | 13 | using namespace compiler; 14 | 15 | /* public */ 16 | 17 | StdLib::StdLib(Log& log, Scope& rootScope) 18 | : m_log(log), m_scope(rootScope) { 19 | 20 | // object: the root of the object tree 21 | auto_ptr objectObject(new Object(m_log, "object")); 22 | auto_ptr objectType(new RootType(m_log)); 23 | Symbol& object = m_scope.newSymbol("object", objectType); 24 | //objectType->addMemberType("foo", auto_ptr(new BasicType(m_log, objectSymbol))); 25 | //object.newMember("foo", auto_ptr(new Object(m_log, "foo"))); 26 | m_scope.initSymbol("object", objectObject); 27 | 28 | auto_ptr functionObject(new Object(m_log, "@")); 29 | auto_ptr functionType(new BasicType(m_log, object)); 30 | //Symbol& function = m_scope.newSymbol("@", functionType); 31 | m_scope.newSymbol("@", functionType); 32 | m_scope.initSymbol("@", functionObject); 33 | 34 | m_scope.commitAll(); 35 | } 36 | 37 | // Nothing to do. m_objects objects are owned by m_scope. 38 | StdLib::~StdLib() { 39 | } 40 | -------------------------------------------------------------------------------- /compiler/StdLib.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _StdLib_h_ 5 | #define _StdLib_h_ 6 | 7 | /* shok standard library */ 8 | 9 | #include "Object.h" 10 | #include "Scope.h" 11 | 12 | #include "util/Log.h" 13 | 14 | #include 15 | 16 | namespace compiler { 17 | 18 | class StdLib { 19 | public: 20 | StdLib(Log&, Scope& rootScope); 21 | ~StdLib(); 22 | 23 | private: 24 | typedef std::vector stdlib_vec; 25 | typedef stdlib_vec::const_iterator stdlib_iter; 26 | 27 | Log& m_log; 28 | Scope& m_scope; 29 | stdlib_vec m_objects; 30 | }; 31 | 32 | } 33 | 34 | #endif // _StdLib_h_ 35 | -------------------------------------------------------------------------------- /compiler/Symbol.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Symbol_h_ 5 | #define _Symbol_h_ 6 | 7 | /* Symbol 8 | * 9 | * A Symbol is a typed entry in a symbol table. The "Type" just refers to the 10 | * set of parent Symbol(s). The Symbol itself has a SymbolTable of members. 11 | * At compile()-time it will be given an actual Object instance. 12 | */ 13 | 14 | #include "Common.h" 15 | #include "SymbolTable.h" 16 | 17 | #include "util/Log.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace compiler { 24 | 25 | class Object; 26 | class Type; 27 | 28 | class Symbol { 29 | public: 30 | Symbol(Log& log, std::auto_ptr type) 31 | : log(log), type(type), object(NULL) {} 32 | Log& log; 33 | std::auto_ptr type; 34 | std::auto_ptr object; 35 | }; 36 | 37 | } 38 | 39 | #endif // _Symbol_h_ 40 | -------------------------------------------------------------------------------- /compiler/Token.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Token_h_ 5 | #define _Token_h_ 6 | 7 | /* Token of AST input read from the parser */ 8 | 9 | #include "util/Log.h" 10 | 11 | #include 12 | #include 13 | 14 | namespace compiler { 15 | 16 | struct Token { 17 | Token() {} 18 | Token(const std::string& name, const std::string& value = "") 19 | : name(name), value(value) {} 20 | std::string print() const; 21 | std::string name; 22 | std::string value; 23 | }; 24 | 25 | class Tokenizer { 26 | public: 27 | Tokenizer() 28 | : mode(MODE_NONE), 29 | codeDepth(0) {} 30 | typedef std::vector token_vec; 31 | typedef token_vec::const_iterator token_iter; 32 | 33 | token_vec tokenize(Log& log, const std::string& ast); 34 | 35 | private: 36 | enum MODE { 37 | MODE_NONE, 38 | MODE_CMD, 39 | MODE_CODE 40 | }; 41 | 42 | MODE mode; 43 | int codeDepth; 44 | }; 45 | 46 | } 47 | 48 | #endif // _Token_h_ 49 | -------------------------------------------------------------------------------- /compiler/TypeSpec.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "TypeSpec.h" 5 | 6 | #include "CompileError.h" 7 | #include "Operator.h" 8 | 9 | #include 10 | using std::string; 11 | 12 | using namespace compiler; 13 | 14 | void TypeSpec::setup() { 15 | if (children.size() != 1) { 16 | throw CompileError("TypeSpec must wrap a single expression fragment"); 17 | } 18 | computeType(); 19 | } 20 | 21 | string TypeSpec::getTypeName() const { 22 | return m_type->getName(); 23 | } 24 | 25 | void TypeSpec::computeType() { 26 | // Extract the type of our expression tree, then delete all its nodes; they 27 | // are irrelevant, we don't want to actually compile them as if they were 28 | // code. 29 | TypedNode* child = dynamic_cast(children.at(0)); 30 | if (!child) { 31 | throw CompileError("Child of TypeSpec must be a TypedNode"); 32 | } 33 | m_type = child->getType(); 34 | if (!m_type.get()) { 35 | throw CompileError("Child of TypeSpec must have a Type"); 36 | } 37 | delete children.at(0); 38 | children.clear(); 39 | } 40 | -------------------------------------------------------------------------------- /compiler/TypeSpec.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _TypeSpec_h_ 5 | #define _TypeSpec_h_ 6 | 7 | /* Type specifier 8 | * 9 | * This is like Expression except instead of wrapping any general expression, 10 | * it wraps an expression that we intend to use only for its Type. At setup() 11 | * time we reorder and validate the operator tree just like an Expression. 12 | * Then we extract the Type of the expression and delete all the Nodes to block 13 | * them from ever being compiled. 14 | * 15 | * A TypeSpec will be more readily permitted to use | and maybe & than some 16 | * uses of Expression. Additionally, a TypeSpec may be forbidden from 17 | * including object literals, by the parser. 18 | */ 19 | 20 | #include "OperatorParser.h" 21 | #include "RootNode.h" 22 | #include "Token.h" 23 | #include "TypedNode.h" 24 | 25 | #include "util/Log.h" 26 | 27 | #include 28 | 29 | namespace compiler { 30 | 31 | class TypeSpec : public TypedNode, public OperatorParser { 32 | public: 33 | TypeSpec(Log& log, RootNode*const root, const Token& token) 34 | : TypedNode(log, root, token), 35 | OperatorParser(log) {} 36 | virtual void setup(); 37 | 38 | std::string getTypeName() const; 39 | 40 | private: 41 | // from TypedNode 42 | virtual void computeType(); 43 | }; 44 | 45 | } 46 | 47 | #endif // _TypeSpec_h_ 48 | -------------------------------------------------------------------------------- /compiler/TypedNode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "TypedNode.h" 5 | 6 | #include "CompileError.h" 7 | 8 | #include 9 | using std::auto_ptr; 10 | 11 | using namespace compiler; 12 | 13 | // Returns a duplicate of m_type; caller must take ownership 14 | auto_ptr TypedNode::getType() const { 15 | if (!m_type.get()) { 16 | throw CompileError("Cannot get Type of TypedNode " + print() + " before it has been computed"); 17 | } 18 | return m_type->duplicate(); 19 | } 20 | 21 | const Type& TypedNode::type() const { 22 | if (!m_type.get()) { 23 | throw CompileError("Cannot refer to Type of TypedNode " + print() + " before it has been computed"); 24 | } 25 | return *m_type.get(); 26 | } 27 | -------------------------------------------------------------------------------- /compiler/TypedNode.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _TypedNode_h_ 5 | #define _TypedNode_h_ 6 | 7 | /* TypedNode 8 | * 9 | * Any AST Node that has a Type and thus may appear in an Expression. 10 | */ 11 | 12 | #include "Node.h" 13 | #include "RootNode.h" 14 | #include "Token.h" 15 | #include "Type.h" 16 | 17 | #include "util/Log.h" 18 | 19 | #include 20 | 21 | namespace compiler { 22 | 23 | class TypedNode : public Node { 24 | public: 25 | TypedNode(Log& log, RootNode*const root, const Token& token) 26 | : Node(log, root, token), 27 | m_type(NULL) {} 28 | virtual ~TypedNode() {} 29 | 30 | // Returns a duplicate of m_type; caller must take ownership 31 | std::auto_ptr getType() const; 32 | 33 | // Use this for quick const lookups on the Type without duplicating it 34 | const Type& type() const; 35 | 36 | protected: 37 | virtual void computeType() = 0; 38 | std::auto_ptr m_type; 39 | }; 40 | 41 | } 42 | 43 | #endif // _TypedNode_h_ 44 | -------------------------------------------------------------------------------- /compiler/Variable.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Variable.h" 5 | 6 | #include "CompileError.h" 7 | #include "Identifier.h" 8 | #include "Type.h" 9 | 10 | #include 11 | #include 12 | #include 13 | using std::auto_ptr; 14 | using std::string; 15 | using std::vector; 16 | 17 | using namespace compiler; 18 | 19 | void Variable::setup() { 20 | if (children.size() < 1) { 21 | throw CompileError("Variable node must have >= 1 children"); 22 | } 23 | auto_ptr memberType; 24 | for (child_iter i = children.begin(); i != children.end(); ++i) { 25 | Identifier* ident = dynamic_cast(*i); 26 | if (!ident) { 27 | throw CompileError("Variable children must all be Identifiers"); 28 | } 29 | if (!m_symbol) { 30 | m_varname = ident->getName(); 31 | m_fullname = m_varname; 32 | m_symbol = parentScope->getSymbol(m_varname); 33 | if (!m_symbol) { 34 | throw CompileError("Object " + m_varname + " does not exist"); 35 | } 36 | memberType = m_symbol->type->duplicate(); 37 | } else { 38 | string member = ident->getName(); 39 | m_fullname += "." + member; 40 | memberType = memberType->getMemberType(member); 41 | if (!memberType.get()) { 42 | throw CompileError("Object member " + m_fullname + " does not exist"); 43 | } 44 | m_select.push_back(member); 45 | } 46 | } 47 | computeType(); 48 | } 49 | 50 | Object& Variable::getObject() const { 51 | if (!m_symbol) { 52 | throw CompileError("Cannot retrieve Symbol of deficient Variable " + print()); 53 | } else if (!m_symbol->object.get()) { 54 | throw CompileError("Cannot retrieve Object of deficient Variable " + print()); 55 | } 56 | return *m_symbol->object.get(); 57 | } 58 | 59 | void Variable::computeType() { 60 | if (!m_symbol) { 61 | throw CompileError("Failed to find Symbol behind Variable " + print()); 62 | } 63 | //m_type.reset(new BasicType(log, *m_symbol, m_select)); // TODO 64 | m_type.reset(new BasicType(log, *m_symbol)); 65 | } 66 | -------------------------------------------------------------------------------- /compiler/Variable.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Variable_h_ 5 | #define _Variable_h_ 6 | 7 | /* Variable 8 | * 9 | * A Variable simply refers to an object, or nested object-members, by name. 10 | * Its children are Identifiers, and there must be at least one. The first 11 | * must refer to an object that exists. The second and subsequent are the 12 | * names of a member, a member on that member, etc. These must all exist in 13 | * the parent scope at setup()-time, so the Variable can be a TypedNode. 14 | */ 15 | 16 | #include "Object.h" 17 | #include "RootNode.h" 18 | #include "Token.h" 19 | #include "TypedNode.h" 20 | 21 | #include "util/Log.h" 22 | 23 | #include 24 | 25 | namespace compiler { 26 | 27 | class Variable : public TypedNode { 28 | public: 29 | Variable(Log& log, RootNode*const root, const Token& token) 30 | : TypedNode(log, root, token), 31 | m_symbol(NULL) {} 32 | virtual void setup(); 33 | 34 | Object& getObject() const; 35 | 36 | private: 37 | typedef std::vector select_vec; 38 | typedef select_vec::const_iterator select_iter; 39 | // from TypedNode 40 | virtual void computeType(); 41 | std::string m_varname; 42 | std::string m_fullname; 43 | Symbol* m_symbol; 44 | select_vec m_select; 45 | }; 46 | 47 | } 48 | 49 | #endif // _Variable_h_ 50 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([shok], [0.01], [http://shok.io]) 2 | AC_CONFIG_AUX_DIR([build-aux]) 3 | 4 | AM_INIT_AUTOMAKE([-Wall -Werror foreign]) 5 | AM_PROG_AR 6 | 7 | AC_PROG_CXX 8 | AC_PROG_LIBTOOL 9 | 10 | AM_PATH_PYTHON([2]) 11 | 12 | AC_CONFIG_MACRO_DIR([m4]) 13 | AC_CONFIG_HEADERS([config.h]) 14 | 15 | AX_WITH_CURSES 16 | 17 | AC_CONFIG_FILES([ 18 | Makefile 19 | util/Makefile 20 | statik/Makefile 21 | statik/test/Makefile 22 | exstatik/Makefile 23 | istatik/Makefile 24 | ]) 25 | # lexer/Makefile 26 | # p2/Makefile 27 | # c2/Makefile 28 | # vm/Makefile 29 | # shell/Makefile 30 | 31 | BOOST_REQUIRE 32 | BOOST_PROGRAM_OPTIONS 33 | BOOST_REGEX 34 | # BOOST_IOSTREAMS 35 | 36 | AC_OUTPUT 37 | -------------------------------------------------------------------------------- /exstatik/Codegen.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Codegen.h" 5 | 6 | #include "statik/Meta.h" 7 | #include "statik/Or.h" 8 | #include "statik/Seq.h" 9 | #include "statik/Star.h" 10 | using statik::META; 11 | using statik::OR; 12 | using statik::Rule; 13 | using statik::SEQ; 14 | using statik::STAR; 15 | 16 | #include 17 | using std::auto_ptr; 18 | 19 | using namespace exstatik; 20 | 21 | /* 22 | // compiler = 23 | auto_ptr exstatik::CreateCodegen_Simple() { 24 | auto_ptr compiler(MakeRule_Star("codegen")); 25 | Rule* newstmt_ = compiler_->AddChild(MakeRule_Seq("new stmt")); 26 | Rule* delstmt_ = compiler_->AddChild(MakeRule_Seq("del stmt")); 27 | newstmt_->AddChild(MakeRule_Meta("new")); 28 | delstmt_->AddChild(MakeRule_Meta("del")); 29 | return compiler; 30 | } 31 | 32 | // compiler = 33 | auto_ptr exstatik::CreateCodegen_Moderate() { 34 | auto_ptr compiler(new Rule("codegen")); 35 | return compiler; 36 | } 37 | */ 38 | 39 | // compiler = 40 | /* 41 | auto_ptr exstatik::CreateCodegen_Complex() { 42 | auto_ptr compiler(new StarRule("codegen")); 43 | return compiler; 44 | } 45 | */ 46 | 47 | auto_ptr exstatik::CreateCodegen_Nifty() { 48 | auto_ptr compiler(STAR("codegen")); 49 | Rule* stmt_ = compiler->AddChild(SEQ("stmt")); 50 | stmt_->AddChild(META("(stmt")); 51 | Rule* stmts_ = stmt_->AddChild(OR("stmts")); 52 | stmt_->AddChild(META(")")); 53 | 54 | //Rule* cmdstmt_ = stmts_->AddChild(SEQ("cmd stmt")); 55 | Rule* newstmt_ = stmts_->AddChild(SEQ("new stmt")) 56 | ->CapOutput("PUSH"); 57 | Rule* delstmt_ = stmts_->AddChild(SEQ("del stmt")) 58 | ->CapOutput("POP"); 59 | 60 | //Rule* cmd_ = cmdstmt_->AddChild(STAR("cmd")); 61 | //cmd_->AddChild(META("cmdtext", "cmd")); 62 | 63 | newstmt_->AddChild(META("new")); 64 | newstmt_->AddChild(META("identifier")); 65 | 66 | delstmt_->AddChild(META("del")); 67 | delstmt_->AddChild(META("identifier")); 68 | return compiler; 69 | } 70 | -------------------------------------------------------------------------------- /exstatik/Codegen.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _exstatik_Codegen_h_ 5 | #define _exstatik_Codegen_h_ 6 | 7 | #include "statik/Rule.h" 8 | 9 | #include 10 | 11 | namespace exstatik { 12 | 13 | /* 14 | std::auto_ptr CreateCodegen_Simple(); 15 | std::auto_ptr CreateCodegen_Moderate(); 16 | std::auto_ptr CreateCodegen_Complex(); 17 | */ 18 | std::auto_ptr CreateCodegen_Nifty(); 19 | 20 | } 21 | 22 | #endif // _exstatik_Codegen_h_ 23 | -------------------------------------------------------------------------------- /exstatik/Compiler.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Compiler.h" 5 | 6 | #include "Codegen.h" 7 | #include "Lexer.h" 8 | #include "Parser.h" 9 | 10 | #include "statik/SError.h" 11 | 12 | #include 13 | #include 14 | using std::auto_ptr; 15 | using std::string; 16 | 17 | using namespace exstatik; 18 | 19 | auto_ptr exstatik::MakeCompiler(const string& name) { 20 | auto_ptr c(new Compiler()); 21 | if ("Simple" == name) { 22 | c->push_back(CreateLexer_Simple()); 23 | c->push_back(CreateParser_Simple()); 24 | 25 | } else if ("Nick" == name) { 26 | c->push_back(CreateLexer_Nick()); 27 | 28 | } else if ("Seq" == name) { 29 | c->push_back(CreateLexer_Seq()); 30 | 31 | } else if ("Splash" == name) { 32 | c->push_back(CreateLexer_Splash()); 33 | 34 | } else if ("Moderate" == name) { 35 | c->push_back(CreateLexer_Moderate()); 36 | c->push_back(CreateParser_Moderate()); 37 | 38 | } else if ("Complex" == name) { 39 | c->push_back(CreateLexer_Complex()); 40 | c->push_back(CreateParser_Complex()); 41 | 42 | } else if ("Nifty" == name) { 43 | c->push_back(CreateLexer_Nifty()); 44 | c->push_back(CreateParser_Nifty()); 45 | c->push_back(CreateCodegen_Nifty()); 46 | 47 | } else if ("JSON" == name || "Json" == name || "json" == name) { 48 | c->push_back(CreateLexer_JSON()); 49 | c->push_back(CreateParser_JSON()); 50 | 51 | } else if ("C" == name) { 52 | c->push_back(CreateLexer_C()); 53 | c->push_back(CreateParser_C()); 54 | } else { 55 | throw statik::SError("Unknown compiler " + name); 56 | } 57 | return c; 58 | } 59 | -------------------------------------------------------------------------------- /exstatik/Compiler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _exstatik_Compiler_h_ 5 | #define _exstatik_Compiler_h_ 6 | 7 | #include "statik/Rule.h" 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace exstatik { 15 | 16 | typedef boost::ptr_vector Compiler; 17 | typedef Compiler::const_iterator Compiler_iter; 18 | typedef Compiler::iterator Compiler_mod_iter; 19 | std::auto_ptr MakeCompiler(const std::string& name); 20 | 21 | } 22 | 23 | #endif // _exstatik_Compiler_h_ 24 | -------------------------------------------------------------------------------- /exstatik/Lexer.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _exstatik_Lexer_h_ 5 | #define _exstatik_Lexer_h_ 6 | 7 | #include "statik/Rule.h" 8 | 9 | #include 10 | 11 | namespace exstatik { 12 | 13 | std::auto_ptr CreateLexer_Nick(); 14 | std::auto_ptr CreateLexer_Simple(); 15 | std::auto_ptr CreateLexer_Splash(); 16 | std::auto_ptr CreateLexer_Seq(); 17 | std::auto_ptr CreateLexer_KeywordTest(); 18 | std::auto_ptr CreateLexer_Moderate(); 19 | std::auto_ptr CreateLexer_Complex(); 20 | std::auto_ptr CreateLexer_Nifty(); 21 | std::auto_ptr CreateLexer_JSON(); 22 | std::auto_ptr CreateLexer_C(); 23 | 24 | } 25 | 26 | #endif // _exstatik_Lexer_h_ 27 | -------------------------------------------------------------------------------- /exstatik/Makefile.am: -------------------------------------------------------------------------------- 1 | EXSTATIK_SRCS = Codegen.cpp \ 2 | Codegen.h \ 3 | Compiler.cpp \ 4 | Compiler.h \ 5 | Lexer.cpp \ 6 | Lexer.h \ 7 | Parser.cpp \ 8 | Parser.h 9 | 10 | LIB_CXXFLAGS = -I../ 11 | 12 | lib_LIBRARIES = libexstatik.a 13 | libexstatik_a_SOURCES = $(EXSTATIK_SRCS) 14 | libexstatik_a_LIBADD = ../statik/libstatik.a ../util/libutil.a 15 | libexstatik_a_CXXFLAGS = -ggdb -Wall -pedantic $(BOOST_CXXFLAGS) $(LIB_CXXFLAGS) 16 | 17 | bin_PROGRAMS = exstatik 18 | exstatik_SOURCES = main.cpp 19 | exstatik_LDADD = libexstatik.a ../statik/libstatik.a ../util/libutil.a 20 | exstatik_CXXFLAGS = -ggdb -Wall -pedantic $(BOOST_CXXFLAGS) $(LIB_CXXFLAGS) 21 | exstatik_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) $(BOOST_REGEX_LDFLAGS) 22 | LIBS = $(BOOST_PROGRAM_OPTIONS_LIBS) $(BOOST_REGEX_LIBS) 23 | -------------------------------------------------------------------------------- /exstatik/Parser.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _exstatik_Parser_h_ 5 | #define _exstatik_Parser_h_ 6 | 7 | #include "statik/Rule.h" 8 | 9 | #include 10 | 11 | namespace exstatik { 12 | 13 | std::auto_ptr CreateParser_Simple(); 14 | std::auto_ptr CreateParser_Moderate(); 15 | std::auto_ptr CreateParser_Complex(); 16 | std::auto_ptr CreateParser_Nifty(); 17 | std::auto_ptr CreateParser_JSON(); 18 | std::auto_ptr CreateParser_C(); 19 | 20 | } 21 | 22 | #endif // _exstatik_Parser_h_ 23 | -------------------------------------------------------------------------------- /g/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm *.dot *.png 4 | -------------------------------------------------------------------------------- /g/convert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set +x 4 | 5 | for i in *.dot; do 6 | dot -Tpng ${i} > ${i}.png 7 | done 8 | -------------------------------------------------------------------------------- /info/chain.txt: -------------------------------------------------------------------------------- 1 | code 2 | 3 | statements (newinit, ...) 4 | 5 | statements: exp (probably not object or function) 6 | 7 | exp: object, function 8 | 9 | object: newinit 10 | 11 | function: code 12 | 13 | ----- 14 | 15 | cmd 16 | 17 | exp: object, function 18 | 19 | 20 | 21 | ===== 22 | 23 | object(function) 24 | function(object) waaaah! 25 | 26 | code(object,function) 27 | cmd(object,function) 28 | 29 | eeeeveryone forward-declares object and function 30 | eeeeveryone receives object and function, down to exps. 31 | 32 | problem? nope! 33 | - Atom is 34 | - Expression uses Atoms everywhere 35 | - don't want to forward-declare these there, do I? 36 | - Perfectly fine because that's in *Atom*!! 37 | 38 | ----- 39 | 40 | exp, typespec 41 | - object(exp) 42 | - function(exp) 43 | 44 | code(exp) 45 | cmd(exp) 46 | -------------------------------------------------------------------------------- /istatik/ISError.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _istatik_ISError_h_ 5 | #define _istatik_ISError_h_ 6 | 7 | #include "ISLog.h" 8 | 9 | #include 10 | 11 | namespace istatik { 12 | 13 | class ISError : public std::runtime_error { 14 | public: 15 | ISError(const std::string& what) : std::runtime_error(what) { 16 | g_log.error() << what; 17 | } 18 | }; 19 | 20 | } 21 | 22 | #endif // _istatik_ISError_h_ 23 | -------------------------------------------------------------------------------- /istatik/ISLog.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "ISLog.h" 5 | 6 | using namespace istatik; 7 | 8 | Log istatik::g_log; 9 | -------------------------------------------------------------------------------- /istatik/ISLog.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _istatik_ISLog_h_ 5 | #define _istatik_ISLog_h_ 6 | 7 | #include "util/Log.h" 8 | 9 | namespace istatik { 10 | 11 | extern Log g_log; 12 | 13 | } 14 | 15 | #endif // _istatik_ISLog_h_ 16 | -------------------------------------------------------------------------------- /istatik/IStatik.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _istatik_IStatik_h_ 5 | #define _istatik_IStatik_h_ 6 | 7 | #include "ISError.h" 8 | #include "WindowResponse.h" 9 | 10 | #include "exstatik/Compiler.h" 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | namespace istatik { 18 | 19 | class IStatik { 20 | public: 21 | IStatik(const std::string& compiler_name, const std::string& graphdir); 22 | ~IStatik(); 23 | void run(); 24 | 25 | private: 26 | static void finish(int sig); 27 | 28 | void InitScreen(size_t numParsers); 29 | void UpdateWindow(int window_index, 30 | const WindowResponse::action_vec& actions); 31 | 32 | std::string m_compiler_name; 33 | std::string m_graphdir; 34 | std::vector m_windows; 35 | std::vector m_windowSizes; 36 | }; 37 | 38 | } 39 | 40 | #endif // _istatik_IStatik_h_ 41 | -------------------------------------------------------------------------------- /istatik/InputWindow.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _istatik_InputWindow_h_ 5 | #define _istatik_InputWindow_h_ 6 | 7 | #include "ISError.h" 8 | #include "WindowResponse.h" 9 | 10 | #include "statik/List.h" 11 | #include "statik/ObjectPool.h" 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace istatik { 19 | 20 | struct Char { 21 | Char(int ch); 22 | void SetNext(Char* next); 23 | void SetPrevious(Char* prev); 24 | void Unlink(); 25 | operator std::string() const; 26 | 27 | int ch; 28 | statik::List inode; 29 | }; 30 | std::ostream& operator<< (std::ostream& out, const Char& node); 31 | 32 | class Line { 33 | public: 34 | Line(int y); 35 | bool HasChar(int x) const; 36 | int LastIndex() const; 37 | size_t Size() const; 38 | std::string GetString(int startx = 0) const; 39 | Char* GetFirst(); 40 | Char* GetLast(); 41 | Char* GetBefore(int x); 42 | Char* GetAtOrAfter(int x); 43 | Char* Insert(int x, int ch); 44 | Char* Insert(int x, std::auto_ptr c); 45 | Char* Delete(int x); 46 | std::auto_ptr Extract(int x); 47 | int y; 48 | private: 49 | typedef std::vector char_vec; 50 | char_vec m_chars; 51 | statik::ObjectPool m_charpool; 52 | }; 53 | 54 | class LineBuf { 55 | public: 56 | LineBuf(size_t maxcols); 57 | bool HasChar(int y, int x) const; 58 | bool HasLine(int y) const; 59 | size_t Size() const { return m_lines.size(); } 60 | int LastIndexOfLine(int y) const; 61 | WindowResponse Insert(int y, int x, int ch); 62 | WindowResponse Enter(int y, int x, int ch); 63 | WindowResponse Delete(int y, int x); 64 | WindowResponse Backspace(int y, int x); 65 | private: 66 | typedef boost::ptr_vector line_vec; 67 | size_t m_maxcols; 68 | line_vec m_lines; 69 | Char* FindBefore(int y, int x); 70 | Char* FindAtOrAfter(int y, int x); 71 | }; 72 | 73 | class InputWindow { 74 | public: 75 | InputWindow(size_t maxrows, size_t maxcols); 76 | WindowResponse Input(int y, int x, int ch); 77 | private: 78 | size_t m_maxrows; 79 | LineBuf m_linebuf; 80 | }; 81 | 82 | } 83 | 84 | #endif // _istatik_InputWindow_h_ 85 | -------------------------------------------------------------------------------- /istatik/Makefile.am: -------------------------------------------------------------------------------- 1 | ISTATIK_SRCS = \ 2 | ISError.h \ 3 | ISLog.cpp \ 4 | ISLog.h \ 5 | IStatik.cpp \ 6 | IStatik.h \ 7 | InputWindow.cpp \ 8 | InputWindow.h \ 9 | ParserWindow.cpp \ 10 | ParserWindow.h \ 11 | WindowAction.h \ 12 | WindowResponse.h \ 13 | main.cpp 14 | 15 | LIB_CXXFLAGS = -I../ 16 | 17 | bin_PROGRAMS = istatik 18 | istatik_SOURCES = $(ISTATIK_SRCS) 19 | istatik_LDADD = ../exstatik/libexstatik.a ../statik/libstatik.a ../util/libutil.a 20 | istatik_CXXFLAGS = -ggdb -Wall -pedantic $(BOOST_CXXFLAGS) $(LIB_CXXFLAGS) 21 | istatik_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) $(BOOST_REGEX_LDFLAGS) -lcurses 22 | LIBS = $(BOOST_PROGRAM_OPTIONS_LIBS) $(BOOST_REGEX_LIBS) $(CURSES_LIB) 23 | -------------------------------------------------------------------------------- /istatik/ParserWindow.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _istatik_ParserWindow_h_ 5 | #define _istatik_ParserWindow_h_ 6 | 7 | #include "ISError.h" 8 | #include "WindowResponse.h" 9 | 10 | #include "statik/Batch.h" 11 | #include "statik/IncParser.h" 12 | #include "statik/List.h" 13 | #include "statik/Rule.h" 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | namespace istatik { 21 | 22 | class ParserWindow : private boost::noncopyable { 23 | public: 24 | ParserWindow(std::auto_ptr rule, 25 | const std::string& name, 26 | const std::string& graphdir); 27 | ~ParserWindow(); 28 | WindowResponse Input(const statik::Batch& batch); 29 | private: 30 | statik::IncParser m_incParser; 31 | std::string m_str; 32 | statik::List* m_nodes; // our own copies of the IncParser's ONodes 33 | // maps IncParser's ONode -> our m_nodes 34 | typedef std::map node_map; 35 | typedef node_map::const_iterator node_iter; 36 | typedef node_map::iterator node_mod_iter; 37 | node_map m_nodeMap; 38 | }; 39 | 40 | } 41 | 42 | #endif // _istatik_ParserWindow_h_ 43 | -------------------------------------------------------------------------------- /istatik/WindowAction.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _istatik_WindowAction_h_ 5 | #define _istatik_WindowAction_h_ 6 | 7 | namespace istatik { 8 | 9 | struct WindowAction { 10 | enum ACTION { 11 | MOVE, 12 | INSERT, 13 | DELETE 14 | }; 15 | 16 | WindowAction(ACTION action, int y = 0, int x = 0, int ch = '\0') 17 | : action(action), y(y), x(x), ch(ch) {} 18 | ACTION action; 19 | int y; 20 | int x; 21 | int ch; 22 | }; 23 | 24 | } 25 | 26 | #endif // _istatik_WindowAction_h_ 27 | -------------------------------------------------------------------------------- /istatik/WindowResponse.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _istatik_WindowResponse_h_ 5 | #define _istatik_WindowResponse_h_ 6 | 7 | #include "WindowAction.h" 8 | 9 | #include "statik/Batch.h" 10 | 11 | #include 12 | 13 | namespace istatik { 14 | 15 | struct WindowResponse { 16 | typedef std::vector action_vec; 17 | typedef action_vec::const_iterator action_iter; 18 | action_vec actions; 19 | statik::Batch batch; 20 | }; 21 | 22 | } 23 | 24 | #endif // _istatik_WindowResponse_h_ 25 | -------------------------------------------------------------------------------- /lexer/Common.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Common_h_ 5 | #define _Common_h_ 6 | 7 | /* Lexical analyzer */ 8 | 9 | namespace lexer { 10 | 11 | typedef unsigned long linenum_t; 12 | typedef unsigned int charnum_t; 13 | 14 | } 15 | 16 | #endif // _Common_h_ 17 | -------------------------------------------------------------------------------- /lexer/Emitter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Emitter.h" 5 | 6 | #include "LexError.h" 7 | 8 | #include 9 | #include 10 | #include 11 | using std::endl; 12 | using std::ostream; 13 | using std::string; 14 | 15 | using namespace lexer; 16 | 17 | Emitter::Emitter(ostream& out, linenum_t& linenum, charnum_t& charnum) 18 | : m_out(out), 19 | m_linenum(linenum), 20 | m_charnum(charnum) { 21 | } 22 | 23 | void Emitter::p(const string& s) { 24 | if (1 == m_charnum) { 25 | m_out << m_linenum << " "; 26 | } else { 27 | m_out << " "; 28 | } 29 | m_out << m_charnum << ":" << s; 30 | } 31 | -------------------------------------------------------------------------------- /lexer/LexError.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _LexError_h_ 5 | #define _LexError_h_ 6 | 7 | /* Lexer errors */ 8 | 9 | #include "util/Log.h" 10 | 11 | #include 12 | 13 | namespace lexer { 14 | 15 | class LexError : public std::runtime_error { 16 | public: 17 | LexError(const std::string& what) : std::runtime_error(what) {} 18 | LexError(Log& log, const std::string& what) : std::runtime_error(what) { 19 | log.error(what); 20 | } 21 | }; 22 | 23 | } 24 | 25 | #endif // _LexError_h_ 26 | -------------------------------------------------------------------------------- /lexer/Lexer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Lexer.h" 5 | 6 | #include "Tokenizer.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace spirit = boost::spirit; 19 | namespace lex = spirit::lex; 20 | 21 | using std::istream; 22 | using std::ostream; 23 | using std::string; 24 | using std::endl; 25 | 26 | using namespace lexer; 27 | 28 | Lexer::Lexer(Log& log, istream& input, ostream& output) 29 | : m_log(log), 30 | m_input(input), 31 | m_output(output), 32 | m_linenum(1), 33 | m_charnum(1), 34 | m_emitter(output, m_linenum, m_charnum) { 35 | } 36 | 37 | bool Lexer::lex() { 38 | m_input >> std::noskipws; 39 | string sbuf; 40 | 41 | typedef lex::lexertl::token token_type; 42 | typedef lex::lexertl::lexer lexer_type; 43 | Tokenizer tokenizer; 44 | 45 | while (m_input) { 46 | string line; 47 | getline(m_input, line); 48 | sbuf += line + "\n"; 49 | 50 | const char* sbuf_first = sbuf.c_str(); 51 | const char* sbuf_last = &sbuf_first[sbuf.size()]; 52 | 53 | (void) lex::tokenize(sbuf_first, sbuf_last, tokenizer, boost::bind(m_emitter, _1)); 54 | if (sbuf_first == sbuf_last) { 55 | sbuf.clear(); 56 | } else { 57 | std::string rest(sbuf_first, sbuf_last); 58 | std::copy(rest.begin(), rest.end(), sbuf.begin()); 59 | } 60 | } 61 | 62 | return sbuf.empty(); 63 | } 64 | -------------------------------------------------------------------------------- /lexer/Lexer.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Lexer_h_ 5 | #define _Lexer_h_ 6 | 7 | /* Lexical analyzer */ 8 | 9 | #include "Common.h" 10 | #include "Emitter.h" 11 | 12 | #include "util/Log.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace lexer { 18 | 19 | class Lexer { 20 | public: 21 | Lexer(Log& log, std::istream& input, std::ostream& output); 22 | 23 | // returns true on full successful lex 24 | bool lex(); 25 | 26 | private: 27 | Log& m_log; 28 | std::istream& m_input; 29 | std::ostream& m_output; 30 | linenum_t m_linenum; 31 | charnum_t m_charnum; 32 | Emitter m_emitter; 33 | }; 34 | 35 | } 36 | 37 | #endif // _Lexer_h_ 38 | -------------------------------------------------------------------------------- /lexer/Makefile.am: -------------------------------------------------------------------------------- 1 | UTIL_DIR = ../util 2 | UTIL_SRCS = \ 3 | $(UTIL_DIR)/Log.cpp \ 4 | $(UTIL_DIR)/Log.h 5 | 6 | COMMON_SRCS = $(UTIL_SRCS) 7 | 8 | bin_PROGRAMS = shok_lexer 9 | shok_lexer_SOURCES = $(COMMON_SRCS) \ 10 | Common.h \ 11 | Emitter.h \ 12 | Emitter.cpp \ 13 | Lexer.cpp \ 14 | Lexer.h \ 15 | LexError.h \ 16 | Tokenizer.h \ 17 | lexer.cpp 18 | shok_lexer_CPPFLAGS = $(BOOST_CPPFLAGS) 19 | -------------------------------------------------------------------------------- /lexer/lexer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | /* shok lexer */ 5 | 6 | #include "Lexer.h" 7 | #include "LexError.h" 8 | 9 | #include "util/Log.h" 10 | 11 | #include 12 | #include 13 | using std::cin; 14 | using std::cout; 15 | using std::endl; 16 | using std::string; 17 | 18 | namespace { 19 | const string PROGRAM_NAME = "shok_lexer"; 20 | const string LOGFILE = "lexer.log"; 21 | } 22 | 23 | using namespace lexer; 24 | 25 | int main(int argc, char *argv[]) { 26 | if (argc < 1 || argc > 2) { 27 | cout << "usage: " << PROGRAM_NAME << " [log level]" << endl; 28 | return 1; 29 | } 30 | 31 | Log log(LOGFILE); 32 | try { 33 | if (2 == argc) { 34 | log.setLevel(argv[1]); 35 | } 36 | Lexer lexer(log, cin, cout); 37 | if (!lexer.lex()) { 38 | cout << "failed to lex program!" << endl; 39 | } 40 | } catch (const LexError& e) { 41 | log.error(string("Error lexing program: ") + e.what()); 42 | cout << endl; 43 | } catch (const std::exception& e) { 44 | log.error(string("Unknown error: ") + e.what()); 45 | } catch (...) { 46 | log.error("Unknown error"); 47 | } 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /p2/Makefile.am: -------------------------------------------------------------------------------- 1 | UTIL_DIR = ../util 2 | UTIL_SRCS = \ 3 | $(UTIL_DIR)/Log.cpp \ 4 | $(UTIL_DIR)/Log.h 5 | 6 | COMMON_SRCS = $(UTIL_SRCS) 7 | 8 | bin_PROGRAMS = shok_p2 9 | shok_p2_SOURCES = $(COMMON_SRCS) \ 10 | Cmd.h \ 11 | ParseError.h \ 12 | Parser.cpp \ 13 | Parser.h \ 14 | Token.cpp \ 15 | Token.h \ 16 | parser.cpp 17 | shok_p2_CPPFLAGS = $(BOOST_CPPFLAGS) -DBOOST_SPIRIT_DEBUG 18 | #shok_p2_CPPFLAGS = $(BOOST_CPPFLAGS) 19 | shok_p2_LDFLAGS = $(BOOST_IOSTREAMS_LDFLAGS) 20 | LIBS = $(BOOST_IOSTREAMS_LIBS) 21 | -------------------------------------------------------------------------------- /p2/ParseError.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _ParseError_h_ 5 | #define _ParseError_h_ 6 | 7 | /* Parse errors */ 8 | 9 | #include "util/Log.h" 10 | 11 | #include 12 | 13 | namespace parser { 14 | 15 | class ParseError : public std::runtime_error { 16 | public: 17 | ParseError(const std::string& what) : std::runtime_error(what) {} 18 | ParseError(Log& log, const std::string& what) : std::runtime_error(what) { 19 | log.error(what); 20 | } 21 | }; 22 | 23 | } 24 | 25 | #endif // _ParseError_h_ 26 | -------------------------------------------------------------------------------- /p2/Parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Parser.h" 5 | 6 | #include "Shok.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | namespace phoenix = boost::phoenix; 14 | namespace spirit = boost::spirit; 15 | namespace ascii = spirit::ascii; 16 | namespace qi = spirit::qi; 17 | 18 | #include 19 | #include 20 | #include 21 | using std::endl; 22 | using std::istream; 23 | using std::ostream; 24 | using std::string; 25 | 26 | using namespace parser; 27 | 28 | Parser::Parser(istream& input, ostream& output) 29 | : m_input(input), 30 | m_output(output) { 31 | } 32 | 33 | bool Parser::parse() { 34 | // iterate over stream input 35 | typedef std::istreambuf_iterator base_iterator_type; 36 | base_iterator_type in_begin(m_input); 37 | 38 | // convert input iterator to forward iterator, usable by spirit parser 39 | typedef spirit::multi_pass forward_iterator_type; 40 | forward_iterator_type fwd_begin = spirit::make_default_multi_pass(in_begin); 41 | forward_iterator_type fwd_end; 42 | 43 | ShokParser shok_(m_output); 44 | 45 | //BOOST_SPIRIT_DEBUG_NODE(shok_); 46 | 47 | bool r = qi::phrase_parse( 48 | fwd_begin, fwd_end, 49 | shok_, 50 | ascii::space 51 | ); 52 | 53 | if (!r || fwd_begin != fwd_end) { 54 | return false; 55 | } 56 | 57 | return r; 58 | } 59 | -------------------------------------------------------------------------------- /p2/Parser.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Parser_h_ 5 | #define _Parser_h_ 6 | 7 | /* shok parser */ 8 | 9 | #include 10 | #include 11 | 12 | namespace parser { 13 | 14 | class Parser { 15 | public: 16 | Parser(std::istream& input, std::ostream& output); 17 | 18 | // returns true on full successful parse 19 | bool parse(); 20 | 21 | private: 22 | std::istream& m_input; 23 | std::ostream& m_output; 24 | unsigned long m_linenum; 25 | }; 26 | 27 | } 28 | 29 | #endif // _Parser_h_ 30 | -------------------------------------------------------------------------------- /p2/Token.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Token.h" 5 | 6 | using namespace parser; 7 | -------------------------------------------------------------------------------- /p2/parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | /* shok parser runner */ 5 | 6 | #include "ParseError.h" 7 | #include "Parser.h" 8 | 9 | #include "util/Log.h" 10 | 11 | #include 12 | #include 13 | using std::cin; 14 | using std::cout; 15 | using std::endl; 16 | using std::string; 17 | 18 | using namespace parser; 19 | 20 | namespace { 21 | const string PROGRAM_NAME = "shok_parser"; 22 | const string LOGFILE = "parser.log"; 23 | } 24 | 25 | int main(int argc, char *argv[]) { 26 | if (argc < 1 || argc > 2) { 27 | cout << "usage: " << PROGRAM_NAME << " [log level]" << endl; 28 | return 1; 29 | } 30 | 31 | Log log(LOGFILE); 32 | try { 33 | if (2 == argc) { 34 | log.setLevel(argv[1]); 35 | } 36 | Parser parser(cin, cout); 37 | if (!parser.parse()) { 38 | cout << "failed to parse" << endl; 39 | } 40 | } catch (const ParseError& e) { 41 | log.error(string("Parse error: ") + e.what()); 42 | cout << endl; 43 | } catch (const std::exception& e) { 44 | log.error(string("Unknown error: ") + e.what()); 45 | } catch (...) { 46 | log.error("Unknown error"); 47 | } 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /parser/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = shokparser 2 | 3 | bin_SCRIPTS = shok_parser 4 | CLEANFILES = $(bin_SCRIPTS) 5 | EXTRA_DIST = shok_parser.in 6 | 7 | do_substitution = sed -e 's,[@]pythondir[@],$(pythondir),g' \ 8 | -e 's,[@]PACKAGE[@],$(PACKAGE),g' \ 9 | -e 's,[@]VERSION[@],$(VERSION),g' 10 | 11 | shok_parser: shok_parser.in Makefile 12 | $(do_substitution) < $(srcdir)/shok_parser.in > shok_parser 13 | chmod +x shok_parser 14 | -------------------------------------------------------------------------------- /parser/shok_parser.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import sys 4 | sys.path.insert(1, '@pythondir@') 5 | 6 | from shokparser.ParserRunner import ParserRunner 7 | 8 | if __name__ == "__main__": 9 | runner = ParserRunner(package="@PACKAGE@", version="@VERSION@") 10 | runner.run() 11 | -------------------------------------------------------------------------------- /parser/shokparser/ActionParser.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | # directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | from Parser import Parser, MakeParser 5 | from Rule import Rule 6 | import logging 7 | 8 | # ActionParser performs its Action-rule's associated function the first time 9 | # its sub-parser is done. 10 | # 11 | # Why not do it every time? Well, probably because of the way SeqParser works 12 | # now (tries to repeat any rule until it fails).... Not sure about that tho. 13 | # We were getting many many repeats of the action... 14 | # 15 | # You should be careful about where you place Actions in your grammar :) 16 | class ActionParser(Parser): 17 | def __init__(self,rule,parent): 18 | if not isinstance(rule, Action): 19 | raise Exception("Cannot use an ActionParser on a non-Action rule") 20 | Parser.__init__(self, rule, parent) 21 | self.actioned = False 22 | self.active = MakeParser(rule.items, self) 23 | 24 | def parse(self,token): 25 | disp = self.active.parse(token) 26 | self.bad = self.active.bad 27 | self.done = self.active.done 28 | if not self.actioned and not self.bad and self.done: 29 | self.rule.func(self) 30 | self.actioned = True 31 | return disp 32 | return '' 33 | 34 | # The Action's msg should contain at most a single %s, which will be filled 35 | # by the display of its sub-parser. It may have other text in its msg which 36 | # we'll want to display too. So we let the Rule do the work. 37 | def display(self): 38 | d = self.active.display() 39 | return self.rule.display([d]) 40 | 41 | class Action(Rule): 42 | def __init__(self,items,func,msg='%s'): 43 | Rule.__init__(self, "action(%s,%s)" % (items, func), items, msg) 44 | self.func = func 45 | 46 | def MakeParser(self,parent): 47 | return ActionParser(self,parent) 48 | 49 | -------------------------------------------------------------------------------- /parser/shokparser/LexToken.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | # directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | # Tokens that come from the Lexer are either pairs or tuples: 5 | # colno:type 6 | # colno:type:value 7 | class LexToken: 8 | colno = 0 9 | ttype = '' 10 | tvalue = '' 11 | def __init__(self, tokenstr): 12 | t = tokenstr.split(':') 13 | if len(t) < 2 or len(t) > 3: 14 | raise Exception("invalid token: %s" % t) 15 | self.colno = t[0] 16 | self.ttype = t[1] 17 | if len(t) == 3: 18 | self.tvalue = t[2] 19 | 20 | def __repr__(self): 21 | if '' == self.tvalue: 22 | return "<%s:%s>" % (self.colno, self.ttype) 23 | else: 24 | return "<%s:%s:%s>" % (self.colno, self.ttype, self.tvalue) 25 | 26 | def NewlineToken(): 27 | return LexToken('0:NEWL') 28 | -------------------------------------------------------------------------------- /parser/shokparser/MakeRule.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | # directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | import DispParser 5 | import SeqParser 6 | import TerminalParser 7 | 8 | def MakeRule(x): 9 | if isinstance(x, str): 10 | return TerminalParser.Terminal(x) 11 | if isinstance(x, tuple): 12 | return DispParser.Disp(x[0], x[1]) 13 | if isinstance(x, list): 14 | return SeqParser.Seq(str(x), x) 15 | raise Exception("Cannot make rule from unknown type of '%s'" % x) 16 | 17 | -------------------------------------------------------------------------------- /parser/shokparser/Makefile.am: -------------------------------------------------------------------------------- 1 | shok_parser_PYTHON = \ 2 | __init__.py \ 3 | ActionParser.py \ 4 | DispParser.py \ 5 | LexToken.py \ 6 | MakeRule.py \ 7 | OrParser.py \ 8 | Parser.py \ 9 | ParserRunner.py \ 10 | PlusParser.py \ 11 | Rule.py \ 12 | SeqParser.py \ 13 | ShokParser.py \ 14 | StarParser.py \ 15 | TerminalParser.py 16 | 17 | shok_parserdir = $(pythondir)/shokparser 18 | -------------------------------------------------------------------------------- /parser/shokparser/Parser.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | # directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | import MakeRule 5 | import Rule 6 | import logging 7 | 8 | class Parser(object): 9 | def __init__(self,rule,parent=None): 10 | self.rule = rule 11 | self.name = rule.name 12 | self.bad = self.rule.bad 13 | self.done = self.rule.done 14 | self.evil = self.rule.evil 15 | if parent: 16 | self.parent = parent 17 | self.top = parent.top 18 | else: 19 | self.parent = None 20 | self.top = self 21 | 22 | def __repr__(self): 23 | return '%s (%s)' % (self.name, self.rule.name) 24 | 25 | def MakeParser(x, parent=None): 26 | if isinstance(x, Parser): 27 | return x 28 | elif isinstance(x, Rule.Rule): 29 | return x.MakeParser(parent) 30 | return MakeParser(MakeRule.MakeRule(x), parent) 31 | -------------------------------------------------------------------------------- /parser/shokparser/Rule.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | # directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | import Parser 5 | 6 | class Rule: 7 | def __init__(self,name,items): 8 | self.name = name 9 | self.items = items 10 | self.bad = False 11 | self.done = False 12 | self.evil = False 13 | 14 | def MakeParser(self,parent): 15 | return Parser.Parser(self, parent) 16 | 17 | def __repr__(self): 18 | return "{rule %s}" % self.name 19 | 20 | def Opt(rule): 21 | rule.done = True 22 | return rule 23 | 24 | def IsRuleDone(x): 25 | if hasattr(x, 'done'): 26 | return x.done 27 | if isinstance(x, str): 28 | return False 29 | if isinstance(x, tuple): 30 | return IsRuleDone(x[0]) 31 | if isinstance(x, list): 32 | return all([IsRuleDone(i) for i in x]) 33 | raise Exception("Cannot check IsRuleDone from unknown rule type of '%s'" % x) 34 | 35 | -------------------------------------------------------------------------------- /parser/shokparser/StarParser.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | # directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | from PlusParser import Plus 5 | import logging 6 | 7 | class Star(Plus): 8 | def __init__(self,name,items): 9 | Plus.__init__(self, name, items) 10 | self.done = True 11 | 12 | -------------------------------------------------------------------------------- /parser/shokparser/TerminalParser.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | # directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | from Parser import Parser 5 | from Rule import Rule 6 | import logging 7 | 8 | class TerminalParser(Parser): 9 | def __init__(self,rule,parent): 10 | Parser.__init__(self, rule, parent) 11 | if isinstance(self.rule.items, str): 12 | self.rule.items = [self.rule.items] 13 | if len(self.rule.items) != 1: 14 | raise Exception("TerminalParser's Terminal must have one rule.item; instead got '%s'" % self.rule.items) 15 | self.tname = self.rule.items[0] 16 | self.value = None 17 | self.parsedtodone = False # Have we already parsed the token? 18 | # Separate from done because we might be optional 19 | self.displayValue = False 20 | if hasattr(self.rule, 'displayValue') and self.rule.displayValue: 21 | self.displayValue = self.rule.displayValue 22 | 23 | def parse(self,token): 24 | logging.debug("%s TerminalParser parsing '%s'" % (self.name, token)) 25 | if self.bad: 26 | raise Exception("%s TerminalParser already bad" % self.name) 27 | if self.parsedtodone: 28 | self.done = False 29 | self.bad = True 30 | return '' 31 | if token.ttype == self.tname: 32 | self.done = True 33 | self.parsedtodone = True 34 | if token.tvalue != None and token.tvalue != '': 35 | self.value = token.tvalue 36 | else: 37 | self.done = False 38 | self.bad = True 39 | return '' 40 | 41 | return self.display() 42 | 43 | def display(self): 44 | if self.value == None: 45 | return self.tname 46 | if self.displayValue: 47 | return '%s' % self.value[1:-1] 48 | return "%s:%s" % (self.tname, self.value) 49 | 50 | def fakeEnd(self): 51 | return '' 52 | 53 | class Terminal(Rule): 54 | def __init__(self,name): 55 | Rule.__init__(self, name, [name]) 56 | 57 | def MakeParser(self,parent): 58 | return TerminalParser(self, parent) 59 | 60 | # A Terminal that displays the original text (value) verbatim, and not the 61 | # terminal name. 62 | class ValueTerminal(Terminal): 63 | def __init__(self,name): 64 | Terminal.__init__(self, name) 65 | self.displayValue = True 66 | 67 | -------------------------------------------------------------------------------- /parser/shokparser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nfomon/shok/a6728c7ddc0b87fb9945b746c456111e1e068823/parser/shokparser/__init__.py -------------------------------------------------------------------------------- /parser/shokparsertest/ShokParserTest.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | # directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | import unittest 5 | from ShokParser import ShokParser 6 | from LexToken import LexToken 7 | 8 | class ShokTester(unittest.TestCase): 9 | def shokTestAll(self,tests): 10 | for test in tests: 11 | self.shokTest(test[0], test[1]) 12 | 13 | def shokTest(self,inp,out,bad=False,incomplete=False): 14 | parser = ShokParser() 15 | for word in inp.split(): 16 | tok = '1:%s' % word 17 | parser.parse(LexToken(tok)) 18 | if parser.bad: 19 | self.assertTrue(bad) 20 | break 21 | if not parser.done: 22 | self.assertTrue(incomplete) 23 | return 24 | self.assertEqual(parser.ast, out) 25 | 26 | class TestCmdLine(ShokTester): 27 | def test_Cmd(self): 28 | self.shokTestAll([ 29 | ("ID:'ls' NEWL", 30 | "[ls]"), 31 | ("WS ID:'ls' WS MINUS ID:'al' WS ID:'foo.txt' WS NEWL", 32 | "[ls -al foo.txt]"), 33 | ]) 34 | 35 | def test_ExpBlock(self): 36 | self.shokTestAll([ 37 | ("LBRACE ID:'foo' RBRACE WS ID:'lolz' NEWL", 38 | "[{(exp ID:'foo')} lolz]"), 39 | ("LBRACE ID:'foo' WS RBRACE WS ID:'one' WS LBRACE ID:'two' RBRACE NEWL", 40 | "[{(exp ID:'foo')} one {(exp ID:'two')}]"), 41 | ("WS LBRACE WS ID:'foo' WS RBRACE WS ID:'one' WS LBRACE WS ID:'two' WS RBRACE WS NEWL", 42 | "[{(exp ID:'foo')} one {(exp ID:'two')}]"), 43 | ]) 44 | 45 | def test_CodeBlock(self): 46 | self.shokTestAll([ 47 | ("WS LBRACE WS NEWL WS NEWL NEWL WS NEWL WS RBRACE WS NEWL", 48 | "[{}]"), 49 | ]) 50 | 51 | 52 | def suite(): 53 | suite = unittest.TestSuite() 54 | testcases = [TestCmdLine] 55 | suite.addTests([unittest.TestLoader().loadTestsFromTestCase(x) for x in testcases]) 56 | return suite 57 | 58 | if __name__ == '__main__': 59 | unittest.TextTestRunner(verbosity=2).run(suite()) 60 | -------------------------------------------------------------------------------- /shell/Makefile.am: -------------------------------------------------------------------------------- 1 | UTIL_DIR = ../util 2 | UTIL_SRCS = \ 3 | $(UTIL_DIR)/Log.cpp \ 4 | $(UTIL_DIR)/Log.h \ 5 | $(UTIL_DIR)/Proc.cpp \ 6 | $(UTIL_DIR)/Proc.h \ 7 | $(UTIL_DIR)/Util.cpp \ 8 | $(UTIL_DIR)/Util.h 9 | 10 | COMMON_SRCS = $(UTIL_SRCS) 11 | 12 | bin_PROGRAMS = shok_shell 13 | shok_shell_SOURCES = $(COMMON_SRCS) \ 14 | shell.cpp 15 | shok_shell_CPPFLAGS = $(BOOST_CPPFLAGS) 16 | shok_shell_LDFLAGS = $(BOOST_IOSTREAMS_LDFLAGS) 17 | LIBS = $(BOOST_IOSTREAMS_LIBS) 18 | -------------------------------------------------------------------------------- /statik/Batch.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Batch.h" 5 | 6 | #include "List.h" 7 | #include "SLog.h" 8 | 9 | #include 10 | using boost::lexical_cast; 11 | 12 | #include 13 | #include 14 | using std::ostream; 15 | using std::string; 16 | 17 | using namespace statik; 18 | 19 | /* BatchItem public */ 20 | 21 | std::string Batch::BatchItem::Print() const { 22 | if (!node) { 23 | throw SError("Cannot print defective BatchItem"); 24 | } 25 | string s(UnMapBatchOp(op) + " "); 26 | if (OP_DELETE == op) { 27 | s += lexical_cast(node); 28 | } else { 29 | s += lexical_cast(node) + " " + node->Print(); 30 | } 31 | if (pos) { 32 | s += " @ " + lexical_cast(pos) + " " + pos->Print(); 33 | } 34 | return s; 35 | } 36 | 37 | /* Batch public */ 38 | 39 | std::string Batch::UnMapBatchOp(const BATCH_OP& op) { 40 | switch (op) { 41 | case OP_INSERT: return "OP_INSERT"; 42 | case OP_UPDATE: return "OP_UPDATE"; 43 | case OP_DELETE: return "OP_DELETE"; 44 | default: throw SError("Cannot unmap unknown BATCH_OP"); 45 | } 46 | } 47 | 48 | void Batch::Insert(const List& inode, const List* pos = NULL) { 49 | m_batch.push_back(BatchItem(inode, OP_INSERT, pos)); 50 | } 51 | 52 | void Batch::Delete(const List& inode) { 53 | m_batch.push_back(BatchItem(inode, OP_DELETE)); 54 | } 55 | 56 | void Batch::Update(const List& inode) { 57 | m_batch.push_back(BatchItem(inode, OP_UPDATE)); 58 | } 59 | 60 | void Batch::Accept(const Batch& batch) { 61 | for (batch_iter i = batch.begin(); i != batch.end(); ++i) { 62 | m_batch.push_back(*i); 63 | } 64 | } 65 | 66 | void Batch::Clear() { 67 | g_log.debug() << "Batch: Clearing " << m_batch.size() << " items out of batch"; 68 | m_batch.clear(); 69 | } 70 | 71 | string Batch::Print() const { 72 | string s; 73 | for (batch_iter i = m_batch.begin(); i != m_batch.end(); ++i) { 74 | s += "\n" + i->Print(); 75 | } 76 | return s; 77 | } 78 | 79 | /* non-member */ 80 | 81 | ostream& statik::operator<< (ostream& out, const Batch::BatchItem& item) { 82 | out << item.Print(); 83 | return out; 84 | } 85 | 86 | ostream& statik::operator<< (ostream& out, const Batch& batch) { 87 | out << batch.Print(); 88 | return out; 89 | } 90 | -------------------------------------------------------------------------------- /statik/Batch.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Batch_h_ 5 | #define _statik_Batch_h_ 6 | 7 | /* A batch of List node changes (insertions/updates/deletions). This is the 8 | * output emit by an IncParser, describing the changes to the output list. You 9 | * can also provide a batch of input changes to an IncParser; e.g. to drive one 10 | * IncParser from the ChangeBatch emit by another. 11 | * 12 | * The batch is ordered; the first item (change) should be applied before the 13 | * subsequent. The nodes are wired (left/right pointers are set) as if they 14 | * were connected as a part of the list as it exists when their change would be 15 | * applied. However, of course, their neighbours' left/right pointers will 16 | * reflect the old state of the list. 17 | */ 18 | 19 | #include "List.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace statik { 28 | 29 | class Batch { 30 | public: 31 | enum BATCH_OP { 32 | OP_INSERT, 33 | OP_UPDATE, 34 | OP_DELETE 35 | }; 36 | 37 | static std::string UnMapBatchOp(const BATCH_OP& op); 38 | 39 | struct BatchItem { 40 | BatchItem(const List& node, BATCH_OP op, const List* pos = NULL) 41 | : node(&node), op(op), pos(pos) {} 42 | const List* node; 43 | BATCH_OP op; 44 | const List* pos; 45 | 46 | std::string Print() const; 47 | }; 48 | 49 | typedef std::vector batch_vec; 50 | typedef batch_vec::const_iterator batch_iter; 51 | 52 | batch_iter begin() const { return m_batch.begin(); } 53 | batch_iter end() const { return m_batch.end(); } 54 | size_t Size() const { return m_batch.size(); } 55 | bool IsEmpty() const { return m_batch.empty(); } 56 | 57 | void Insert(const List& inode, const List* pos); 58 | void Update(const List& inode); 59 | void Delete(const List& inode); 60 | void Accept(const Batch& batch); 61 | void Clear(); 62 | 63 | std::string Print() const; 64 | 65 | private: 66 | batch_vec m_batch; 67 | }; 68 | 69 | std::ostream& operator<< (std::ostream& out, const Batch::BatchItem& item); 70 | std::ostream& operator<< (std::ostream& out, const Batch& batch); 71 | 72 | } 73 | 74 | #endif // _statik_Batch_h_ 75 | -------------------------------------------------------------------------------- /statik/Grapher.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Grapher_h_ 5 | #define _statik_Grapher_h_ 6 | 7 | #include "IncParser.h" 8 | #include "List.h" 9 | #include "Rule.h" 10 | #include "STree.h" 11 | 12 | #include 13 | 14 | namespace statik { 15 | 16 | class Grapher { 17 | public: 18 | Grapher(const std::string& out_dir, const std::string& base_filename); 19 | 20 | void AddMachine(const std::string& context, const Rule& machineRoot); 21 | void AddOrderList(const std::string& context, const OrderList& orderList, const List& start); 22 | void AddIList(const std::string& context, const List& start, const std::string& label = ""); 23 | void AddSTree(const std::string& context, const STree& root, const std::string& label = "", const STree* initiator = NULL); 24 | void AddIListeners(const std::string& context, const IncParser& incParser, const List& start); 25 | void AddOBatch(const std::string& context, const Batch& batch, const std::string& label = ""); 26 | void Signal(const std::string& context, const void*, bool isUpdate = false); 27 | 28 | bool IsDirty() const { return m_isDirty; } 29 | 30 | void SaveAndClear() { 31 | Save(); 32 | Clear(); 33 | } 34 | 35 | private: 36 | void Save(); 37 | void Clear(); 38 | 39 | std::string m_out_dir; 40 | std::string m_base_filename; 41 | std::string m_graph; 42 | int m_img_count; 43 | bool m_isDirty; 44 | }; 45 | 46 | } 47 | 48 | #endif // _statik_Grapher_h_ 49 | -------------------------------------------------------------------------------- /statik/IConnection.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "IConnection.h" 5 | 6 | #include "SError.h" 7 | 8 | using namespace statik; 9 | 10 | IConnection::IConnection() 11 | : m_istart(NULL), 12 | m_iend(NULL) { 13 | } 14 | 15 | void IConnection::Clear() { 16 | m_istart = NULL; 17 | m_iend = NULL; 18 | } 19 | 20 | bool IConnection::IsClear() const { 21 | return !m_istart; 22 | } 23 | 24 | const List& IConnection::Start() const { 25 | if (!m_istart) { 26 | throw SError("Cannot get start of uninitialized IConnection"); 27 | } 28 | return *m_istart; 29 | } 30 | 31 | const List& IConnection::End() const { 32 | if (!m_iend) { 33 | throw SError("Cannot get end of uninitialized IConnection"); 34 | } 35 | return *m_iend; 36 | } 37 | 38 | void IConnection::Restart(const List& istart, bool total) { 39 | g_log.debug() << "Restarting node to " << istart; 40 | m_istart = &istart; 41 | if (total) { 42 | m_iend = &istart; 43 | } 44 | } 45 | 46 | void IConnection::SetEnd(const List& iend) { 47 | if (!m_istart) { 48 | throw SError("Cannot set end of IConnection that has not been started"); 49 | } 50 | m_iend = &iend; 51 | } 52 | -------------------------------------------------------------------------------- /statik/IConnection.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_IConnection_h_ 5 | #define _statik_IConnection_h_ 6 | 7 | #include "List.h" 8 | 9 | namespace statik { 10 | 11 | class IConnection { 12 | public: 13 | IConnection(); 14 | 15 | void Clear(); 16 | bool IsClear() const; 17 | 18 | const List& Start() const; 19 | const List& End() const; 20 | 21 | void Restart(const List& istart, bool total = true); 22 | void SetEnd(const List& iend); 23 | 24 | private: 25 | const List* m_istart; // starting inode 26 | const List* m_iend; // inode that makes us bad after we're done, or last 27 | }; 28 | 29 | } 30 | 31 | #endif // _statik_IConnection_h_ 32 | -------------------------------------------------------------------------------- /statik/Keyword.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Keyword.h" 5 | 6 | #include "IncParser.h" 7 | #include "OutputFunc.h" 8 | #include "SError.h" 9 | #include "SLog.h" 10 | #include "STree.h" 11 | 12 | #include 13 | #include 14 | using std::auto_ptr; 15 | using std::string; 16 | 17 | using namespace statik; 18 | 19 | auto_ptr statik::KEYWORD(const string& str) { 20 | return statik::KEYWORD(str, str); 21 | } 22 | 23 | auto_ptr statik::KEYWORD(const string& name, const string& str) { 24 | return auto_ptr(new Rule(name, 25 | MakeParseFunc_Keyword(str), 26 | MakeOutputFunc_Basic(name))); 27 | } 28 | 29 | auto_ptr statik::MakeParseFunc_Keyword(const string& str) { 30 | return auto_ptr(new ParseFunc_Keyword(str)); 31 | } 32 | 33 | ParseFunc_Keyword::ParseFunc_Keyword(const string& str) 34 | : m_str(str) { 35 | if (m_str.empty()) { 36 | throw SError("Cannot create empty Keyword"); 37 | } 38 | } 39 | 40 | void ParseFunc_Keyword::operator() (ParseAction::Action action, const List& inode, const STree* initiator) { 41 | g_log.info() << "Computing Keyword at " << *m_node << " with inode " << inode; 42 | State& state = m_node->GetState(); 43 | state.Clear(); 44 | string matched; 45 | bool done = false; 46 | const List* i = &m_node->IStart(); 47 | for (; i != NULL; i = i->right) { 48 | m_node->GetIncParser().Listen(*m_node, *i); 49 | m_node->GetIConnection().SetEnd(*i); 50 | if (done) { 51 | state.GoComplete(); 52 | break; 53 | } 54 | matched += i->value; 55 | if (m_str == matched) { 56 | state.GoDone(); 57 | done = true; 58 | } else if (m_str.substr(0, matched.size()) != matched) { 59 | state.GoBad(); 60 | break; 61 | } else { 62 | // Just ok; keep going (if possible) 63 | state.GoOK(); 64 | } 65 | } 66 | if (state.IsEmitting()) { 67 | state.Lock(); 68 | } else { 69 | state.Unlock(); 70 | } 71 | if (state.IsPending()) { 72 | throw SError("Keyword failed to determine state"); 73 | } 74 | g_log.debug() << "Keyword now at: " << *m_node << " with IStart: " << m_node->IStart() << " and IEnd: " << m_node->IEnd(); 75 | } 76 | -------------------------------------------------------------------------------- /statik/Keyword.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Keyword_h_ 5 | #define _statik_Keyword_h_ 6 | 7 | /* Keyword rule */ 8 | 9 | #include "List.h" 10 | #include "ParseAction.h" 11 | #include "ParseFunc.h" 12 | #include "Rule.h" 13 | #include "STree.h" 14 | 15 | #include 16 | #include 17 | 18 | namespace statik { 19 | 20 | std::auto_ptr KEYWORD(const std::string& str); 21 | std::auto_ptr KEYWORD(const std::string& name, 22 | const std::string& str); 23 | 24 | class ParseFunc_Keyword : public ParseFunc { 25 | public: 26 | ParseFunc_Keyword(const std::string& str); 27 | virtual ~ParseFunc_Keyword() {} 28 | virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator); 29 | virtual std::auto_ptr Clone() { 30 | return std::auto_ptr(new ParseFunc_Keyword(m_str)); 31 | } 32 | 33 | private: 34 | const std::string m_str; 35 | }; 36 | 37 | std::auto_ptr MakeParseFunc_Keyword(const std::string& str); 38 | 39 | } 40 | 41 | #endif // _statik_Keyword_h_ 42 | -------------------------------------------------------------------------------- /statik/List.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "List.h" 5 | 6 | #include "SLog.h" 7 | #include "STree.h" 8 | 9 | #include "util/Graphviz.h" 10 | using Util::dotVar; 11 | using Util::safeLabelStr; 12 | 13 | #include 14 | #include 15 | #include 16 | using std::auto_ptr; 17 | using std::ostream; 18 | using std::string; 19 | 20 | using namespace statik; 21 | 22 | /* public */ 23 | 24 | List::List(const string& name, const string& value) 25 | : name(name), 26 | value(value), 27 | left(NULL), 28 | right(NULL) { 29 | } 30 | 31 | string List::DrawNode(const string& context) const { 32 | string s = dotVar(this, context) + " [label=\"" + safeLabelStr(name + (value.empty() ? "" : (name.empty() ? "" : ":") + value)) + "\", style=\"filled\", fillcolor=\"#dddddd\", fontsize=12.0];\n"; 33 | if (right) { 34 | s += dotVar(this, context) + " -> " + dotVar(right, context) + ";\n"; 35 | s += right->DrawNode(context); 36 | } 37 | return s; 38 | } 39 | 40 | /* non-member */ 41 | 42 | ostream& statik::operator<< (ostream& out, const List& node) { 43 | out << node.Print(); 44 | return out; 45 | } 46 | -------------------------------------------------------------------------------- /statik/List.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_List_h_ 5 | #define _statik_List_h_ 6 | 7 | #include "SError.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace statik { 13 | 14 | struct List { 15 | List(const std::string& name, const std::string& value = ""); 16 | 17 | std::string Print() const { return "(List " + name + ":" + value + ")"; } 18 | std::string DrawNode(const std::string& context) const; 19 | 20 | const std::string name; 21 | std::string value; 22 | List* left; 23 | List* right; 24 | }; 25 | 26 | std::ostream& operator<< (std::ostream& out, const List& node); 27 | 28 | } 29 | 30 | #endif // _statik_List_h_ 31 | -------------------------------------------------------------------------------- /statik/Makefile.am: -------------------------------------------------------------------------------- 1 | STATIK_SRCS = \ 2 | Batch.cpp \ 3 | Batch.h \ 4 | Grapher.cpp \ 5 | Grapher.h \ 6 | IConnection.cpp \ 7 | IConnection.h \ 8 | IncParser.cpp \ 9 | IncParser.h \ 10 | Keyword.cpp \ 11 | Keyword.h \ 12 | List.cpp \ 13 | List.h \ 14 | ListenerTable.h \ 15 | Meta.cpp \ 16 | Meta.h \ 17 | ObjectPool.h \ 18 | OData.h \ 19 | Opt.cpp \ 20 | Opt.h \ 21 | Or.cpp \ 22 | Or.h \ 23 | OrderList.cpp \ 24 | OrderList.h \ 25 | OutputFunc.cpp \ 26 | OutputFunc.h \ 27 | ParseAction.h \ 28 | ParseFunc.h \ 29 | Regexp.cpp \ 30 | Regexp.h \ 31 | Root.cpp \ 32 | Root.h \ 33 | Rule.cpp \ 34 | Rule.h \ 35 | SError.h \ 36 | SLog.cpp \ 37 | SLog.h \ 38 | STree.cpp \ 39 | STree.h \ 40 | Seq.cpp \ 41 | Seq.h \ 42 | Star.cpp \ 43 | Star.h \ 44 | State.cpp \ 45 | State.h 46 | 47 | LIB_CXXFLAGS = -I../ 48 | 49 | lib_LIBRARIES = libstatik.a 50 | libstatik_a_LIBADD = ../util/libutil.a 51 | libstatik_a_SOURCES = $(STATIK_SRCS) 52 | libstatik_a_CXXFLAGS = -ggdb -Wall -pedantic $(BOOST_CXXFLAGS) $(LIB_CXXFLAGS) 53 | -------------------------------------------------------------------------------- /statik/Meta.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Meta.h" 5 | 6 | #include "IncParser.h" 7 | #include "OutputFunc.h" 8 | #include "SError.h" 9 | #include "SLog.h" 10 | #include "STree.h" 11 | 12 | #include 13 | #include 14 | using std::auto_ptr; 15 | using std::string; 16 | 17 | using namespace statik; 18 | 19 | auto_ptr statik::META(const string& searchName) { 20 | return statik::META(searchName, searchName); 21 | } 22 | 23 | auto_ptr statik::META(const string& name, const string& searchName) { 24 | return auto_ptr(new Rule(name, 25 | MakeParseFunc_Meta(searchName), 26 | MakeOutputFunc_IValues(name))); 27 | } 28 | 29 | auto_ptr statik::MakeParseFunc_Meta(const string& searchName) { 30 | return auto_ptr(new ParseFunc_Meta(searchName)); 31 | } 32 | 33 | ParseFunc_Meta::ParseFunc_Meta(const string& searchName) 34 | : m_searchName(searchName) { 35 | if (m_searchName.empty()) { 36 | throw SError("Cannot create empty Meta"); 37 | } 38 | } 39 | 40 | void ParseFunc_Meta::operator() (ParseAction::Action action, const List& inode, const STree* initiator) { 41 | g_log.info() << "Computing Meta at " << *m_node << " with inode "<< inode; 42 | State& state = m_node->GetState(); 43 | state.Clear(); 44 | const List& first = m_node->IStart(); 45 | g_log.debug() << " - Meta wants '" << m_searchName << "', we are provided first '" << first.name << "'"; 46 | m_node->GetIncParser().Listen(*m_node, first); 47 | m_node->GetIConnection().SetEnd(first); 48 | if (first.name == m_searchName) { 49 | state.GoDone(); 50 | const List* second = first.right; 51 | if (second) { 52 | state.GoComplete(); 53 | m_node->GetIConnection().SetEnd(*second); 54 | } 55 | } else { 56 | state.GoBad(); 57 | } 58 | if (state.IsPending()) { 59 | throw SError("Meta failed to determine state"); 60 | } 61 | g_log.debug() << "Meta now at: " << *m_node << " with IStart: " << m_node->IStart() << " and IEnd: " << m_node->IEnd(); 62 | } 63 | -------------------------------------------------------------------------------- /statik/Meta.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Meta_h_ 5 | #define _statik_Meta_h_ 6 | 7 | /* Meta rule 8 | * 9 | * Recognizes a node output by another rule, by its name. 10 | */ 11 | 12 | #include "List.h" 13 | #include "ParseAction.h" 14 | #include "ParseFunc.h" 15 | #include "Rule.h" 16 | #include "STree.h" 17 | 18 | #include 19 | #include 20 | 21 | namespace statik { 22 | 23 | std::auto_ptr META(const std::string& searchName); 24 | std::auto_ptr META(const std::string& name, 25 | const std::string& searchName); 26 | 27 | class ParseFunc_Meta : public ParseFunc { 28 | public: 29 | ParseFunc_Meta(const std::string& searchName); 30 | virtual ~ParseFunc_Meta() {} 31 | virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator); 32 | virtual std::auto_ptr Clone() { 33 | return std::auto_ptr(new ParseFunc_Meta(m_searchName)); 34 | } 35 | 36 | private: 37 | std::string m_searchName; 38 | }; 39 | 40 | std::auto_ptr MakeParseFunc_Meta(const std::string& searchName); 41 | 42 | } 43 | 44 | #endif // _statik_Meta_h_ 45 | -------------------------------------------------------------------------------- /statik/Opt.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Opt_h_ 5 | #define _statik_Opt_h_ 6 | 7 | /* Optional rule */ 8 | 9 | #include "List.h" 10 | #include "ParseAction.h" 11 | #include "ParseFunc.h" 12 | #include "Rule.h" 13 | #include "STree.h" 14 | 15 | #include 16 | #include 17 | 18 | namespace statik { 19 | 20 | std::auto_ptr OPT(const std::string& name); 21 | 22 | struct ParseFunc_Opt : public ParseFunc { 23 | virtual ~ParseFunc_Opt() {} 24 | virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator); 25 | virtual std::auto_ptr Clone() { 26 | return std::auto_ptr(new ParseFunc_Opt()); 27 | } 28 | }; 29 | 30 | std::auto_ptr MakeParseFunc_Opt(); 31 | 32 | } 33 | 34 | #endif // _statik_Opt_h_ 35 | -------------------------------------------------------------------------------- /statik/Or.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Or_h_ 5 | #define _statik_Or_h_ 6 | 7 | #include "List.h" 8 | #include "ParseAction.h" 9 | #include "ParseFunc.h" 10 | #include "Rule.h" 11 | #include "STree.h" 12 | 13 | #include 14 | #include 15 | 16 | namespace statik { 17 | 18 | std::auto_ptr OR(const std::string& name); 19 | 20 | struct ParseFunc_Or : public ParseFunc { 21 | virtual ~ParseFunc_Or() {} 22 | virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator); 23 | virtual std::auto_ptr Clone() { 24 | return std::auto_ptr(new ParseFunc_Or()); 25 | } 26 | }; 27 | 28 | std::auto_ptr MakeParseFunc_Or(); 29 | 30 | } 31 | 32 | #endif // _statik_Or_h_ 33 | -------------------------------------------------------------------------------- /statik/OrderList.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_OrderList_h_ 5 | #define _statik_OrderList_h_ 6 | 7 | #include "List.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace statik { 14 | 15 | class OrderNode { 16 | public: 17 | typedef std::map node_map; 18 | typedef node_map::const_iterator node_iter; 19 | typedef node_map::iterator node_mod_iter; 20 | 21 | OrderNode(OrderNode* parent); 22 | ~OrderNode(); 23 | 24 | void RemoveLeaf(const List& leaf); 25 | void InsertLeaf(const List& leaf, node_map& out_changes); 26 | void InsertLeafBefore(const List& leaf, const List& next, node_map& out_changes); 27 | void InsertLeafAfter(const List& leaf, const List& prev, node_map& out_changes); 28 | void InsertChildAfter(OrderNode* child, const OrderNode& prev, node_map& out_changes); 29 | 30 | int CompareLeaves(const List& a, const List& b) const; 31 | int CompareChildren(const OrderNode& a, const OrderNode& b) const; 32 | 33 | bool HasLeaves() const; 34 | const OrderNode* Parent() const; 35 | 36 | std::string DrawNode(const std::string& context) const; 37 | 38 | private: 39 | OrderNode* m_parent; 40 | const unsigned int MAX_CHILDREN; 41 | const unsigned int MAX_LEAVES; 42 | 43 | typedef std::vector child_vec; 44 | typedef child_vec::const_iterator child_iter; 45 | typedef child_vec::iterator child_mod_iter; 46 | child_vec m_children; 47 | typedef std::vector leaf_vec; 48 | typedef leaf_vec::const_iterator leaf_iter; 49 | typedef leaf_vec::iterator leaf_mod_iter; 50 | leaf_vec m_leaves; 51 | 52 | bool HasChild(const OrderNode& child) const; 53 | void RemoveChild(const OrderNode& child); 54 | void Grow(node_map& out_changes); 55 | }; 56 | 57 | class OrderList { 58 | public: 59 | ~OrderList(); 60 | void Insert(const List& inode); 61 | void Delete(const List& inode); 62 | int Compare(const List& a, const List& b) const; 63 | 64 | std::string Draw(const std::string& context, const List& start) const; 65 | 66 | private: 67 | OrderNode::node_map m_nodes; 68 | }; 69 | 70 | } 71 | 72 | #endif // _statik_OrderList_h_ 73 | -------------------------------------------------------------------------------- /statik/ParseAction.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_ParseAction_h_ 5 | #define _statik_ParseAction_h_ 6 | 7 | #include "List.h" 8 | 9 | namespace statik { 10 | 11 | class STree; 12 | 13 | struct ParseAction { 14 | public: 15 | enum Action { 16 | Start, 17 | Restart, 18 | INodeInsert, 19 | INodeDelete, 20 | INodeUpdate, 21 | ChildUpdate 22 | }; 23 | 24 | static std::string UnMapAction(Action action) { 25 | switch (action) { 26 | case Start: return "Start"; 27 | case Restart: return "Restart"; 28 | case INodeInsert: return "INodeInsert"; 29 | case INodeDelete: return "INodeDelete"; 30 | case INodeUpdate: return "INodeUpdate"; 31 | case ChildUpdate: return "ChildUpdate"; 32 | default: throw SError("Cannot unmap unknown action"); 33 | } 34 | } 35 | 36 | ParseAction(Action action, STree& node, const List& inode, const STree* initiator = NULL) 37 | : action(action), 38 | node(&node), 39 | inode(&inode), 40 | initiator(initiator) {} 41 | virtual ~ParseAction() {} 42 | 43 | Action action; 44 | STree* node; 45 | const List* inode; 46 | const STree* initiator; 47 | }; 48 | 49 | } 50 | 51 | #endif // _statik_ParseAction_h_ 52 | -------------------------------------------------------------------------------- /statik/ParseFunc.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_ParseFunc_h_ 5 | #define _statik_ParseFunc_h_ 6 | 7 | #include "List.h" 8 | #include "ParseAction.h" 9 | 10 | #include 11 | 12 | namespace statik { 13 | 14 | struct ParseFunc { 15 | public: 16 | virtual ~ParseFunc() {} 17 | void Init(STree& x) { m_node = &x; } 18 | virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator) = 0; 19 | virtual std::auto_ptr Clone() = 0; 20 | protected: 21 | STree* m_node; 22 | }; 23 | 24 | } 25 | 26 | #endif // _statik_ParseFunc_h_ 27 | -------------------------------------------------------------------------------- /statik/README.md: -------------------------------------------------------------------------------- 1 | statik 2 | ====== 3 | 4 | http://statik.rocks 5 | 6 | `statik` is a C++ library for incremental compilation. You give it a grammar, and it gives you an incremental parser. "Incremental" means that the input are changes to the characters of the input source code, and the output are changes to the resulting compiled bytecode. 7 | 8 | Statik allows you to write a compiler as a sequence of "phases" of parsing. Each phase incrementally translates an input list to an output list. For example, your compiler might be constructed as the pipeline: lexer -> parser -> code-generator. The lexer incrementally translates source-code characters to tokens. The parser translates incremental changes to the token list, to an incrementally-updating parse tree. The code-generator responds to the changing parse tree by generating the bytecode for those changes, and emits the bytecode changes incrementally. 9 | 10 | The parser author can provide as many phases as they want; for example, you could toss in an incremental pre-processor, or other phases of compilation. 11 | 12 | status 13 | ====== 14 | 15 | Statik still has some major bugs in some of its rules, especially when grammars are more than a few layers deep. So it's not yet practical for usage, but it's getting pretty close. It can also output graphs (in GraphViz format) to help understand how it runs an incremental parse. 16 | 17 | code 18 | ==== 19 | 20 | Statik is embedded within the codebase for [shok](http://shok.io); they will be separated soon. 21 | 22 | There are three pieces: 23 | - statik/ The library itself, compile it down to libstatik.a 24 | - statik/test/ Test suite 25 | - exstatik/ Example parsers 26 | - istatik/ An interactive ncurses GUI for running/visualizing statik 27 | 28 | Publications 29 | =========== 30 | 31 | - [Poster at SPLASH 2015](http://2015.splashcon.org/event/splash2015-posters-statik-an-incremental-compiler-generator) 32 | -------------------------------------------------------------------------------- /statik/Regexp.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Regexp.h" 5 | 6 | #include "IncParser.h" 7 | #include "OutputFunc.h" 8 | #include "SError.h" 9 | #include "SLog.h" 10 | #include "STree.h" 11 | 12 | #include 13 | #include 14 | using std::auto_ptr; 15 | using std::string; 16 | 17 | using namespace statik; 18 | 19 | auto_ptr statik::REGEXP(const string& name, const boost::regex& regex) { 20 | return auto_ptr(new Rule(name, 21 | MakeParseFunc_Regexp(regex), 22 | MakeOutputFunc_IValues(name))); 23 | } 24 | 25 | auto_ptr statik::MakeParseFunc_Regexp(const boost::regex& regex) { 26 | return auto_ptr(new ParseFunc_Regexp(regex)); 27 | } 28 | 29 | ParseFunc_Regexp::ParseFunc_Regexp(const boost::regex& regex) 30 | : m_regex(regex) { 31 | if (m_regex.empty()) { 32 | throw SError("Cannot create Regexp with empty regex"); 33 | } 34 | } 35 | 36 | void ParseFunc_Regexp::operator() (ParseAction::Action action, const List& inode, const STree* initiator) { 37 | g_log.info() << "Computing Regexp at " << *m_node << " with inode " << inode; 38 | State& state = m_node->GetState(); 39 | state.Clear(); 40 | string str; 41 | const List* i = &m_node->IStart(); 42 | state.GoOK(); 43 | for (; i != NULL; i = i->right) { 44 | m_node->GetIncParser().Listen(*m_node, *i); 45 | m_node->GetIConnection().SetEnd(*i); 46 | str += i->value; 47 | if (boost::regex_match(str, m_regex)) { 48 | state.GoDone(); 49 | // keep going if possible, in case we can get complete 50 | } else if (str.size() > 1 && boost::regex_match(str.begin(), str.end()-1, m_regex)) { 51 | state.GoComplete(); 52 | break; 53 | } else if (boost::regex_match(str, m_regex, boost::match_partial)) { 54 | state.GoDone(); 55 | // keep going if possible, in case we can get done or complete 56 | } else { 57 | state.GoBad(); 58 | break; 59 | } 60 | } 61 | if (state.IsPending()) { 62 | throw SError("Regexp failed to determine state"); 63 | } 64 | g_log.debug() << "Regexp now at: " << *m_node << " with IStart: " << m_node->IStart() << " and IEnd: " << m_node->IEnd(); 65 | } 66 | -------------------------------------------------------------------------------- /statik/Regexp.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Regexp_h_ 5 | #define _statik_Regexp_h_ 6 | 7 | /* Regexp rule */ 8 | 9 | #include "List.h" 10 | #include "ParseAction.h" 11 | #include "ParseFunc.h" 12 | #include "Rule.h" 13 | #include "STree.h" 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | namespace statik { 21 | 22 | std::auto_ptr REGEXP(const std::string& name, 23 | const boost::regex& regex); 24 | 25 | class ParseFunc_Regexp : public ParseFunc { 26 | public: 27 | ParseFunc_Regexp(const boost::regex& regex); 28 | virtual ~ParseFunc_Regexp() {} 29 | virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator); 30 | virtual std::auto_ptr Clone() { 31 | return std::auto_ptr(new ParseFunc_Regexp(m_regex)); 32 | } 33 | 34 | private: 35 | const boost::regex m_regex; 36 | }; 37 | 38 | std::auto_ptr MakeParseFunc_Regexp(const boost::regex& regex); 39 | 40 | } 41 | 42 | #endif // _statik_Regexp_h_ 43 | -------------------------------------------------------------------------------- /statik/Root.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Root_h_ 5 | #define _statik_Root_h_ 6 | 7 | /* Special Rule for the Root node */ 8 | 9 | #include "List.h" 10 | #include "ParseAction.h" 11 | #include "ParseFunc.h" 12 | #include "Rule.h" 13 | #include "STree.h" 14 | 15 | #include 16 | #include 17 | 18 | namespace statik { 19 | 20 | class ParseFunc_Root : public ParseFunc { 21 | public: 22 | ParseFunc_Root(const std::string& name); 23 | virtual ~ParseFunc_Root() {} 24 | virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator); 25 | virtual std::auto_ptr Clone() { 26 | return std::auto_ptr(new ParseFunc_Root(m_name)); 27 | } 28 | 29 | private: 30 | const std::string m_name; 31 | }; 32 | 33 | std::auto_ptr MakeParseFunc_Root(const std::string& name); 34 | 35 | } 36 | 37 | #endif // _statik_Root_h_ 38 | -------------------------------------------------------------------------------- /statik/SError.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_SError_h_ 5 | #define _statik_SError_h_ 6 | 7 | /* Compiler framework errors */ 8 | 9 | #include "SLog.h" 10 | 11 | #include 12 | 13 | namespace statik { 14 | 15 | class SError : public std::runtime_error { 16 | public: 17 | SError(const std::string& what) : std::runtime_error(what) { 18 | g_log.error() << what; 19 | } 20 | }; 21 | 22 | } 23 | 24 | #endif // _statik_SError_h_ 25 | -------------------------------------------------------------------------------- /statik/SLog.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "SLog.h" 5 | 6 | using namespace statik; 7 | 8 | Log statik::g_log; 9 | Log statik::g_san; 10 | -------------------------------------------------------------------------------- /statik/SLog.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_SLog_h_ 5 | #define _statik_SLog_h_ 6 | 7 | #include "util/Log.h" 8 | 9 | namespace statik { 10 | 11 | extern Log g_log; 12 | extern Log g_san; 13 | 14 | } 15 | 16 | #endif // _statik_SLog_h_ 17 | -------------------------------------------------------------------------------- /statik/Seq.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Seq_h_ 5 | #define _statik_Seq_h_ 6 | 7 | #include "List.h" 8 | #include "ParseAction.h" 9 | #include "ParseFunc.h" 10 | #include "Rule.h" 11 | #include "STree.h" 12 | 13 | #include 14 | #include 15 | 16 | namespace statik { 17 | 18 | std::auto_ptr SEQ(const std::string& name); 19 | 20 | struct ParseFunc_Seq : public ParseFunc { 21 | virtual ~ParseFunc_Seq() {} 22 | virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator); 23 | virtual std::auto_ptr Clone() { 24 | return std::auto_ptr(new ParseFunc_Seq()); 25 | } 26 | }; 27 | 28 | std::auto_ptr MakeParseFunc_Seq(); 29 | 30 | } 31 | 32 | #endif // _statik_Seq_h_ 33 | -------------------------------------------------------------------------------- /statik/Star.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_Star_h_ 5 | #define _statik_Star_h_ 6 | 7 | #include "List.h" 8 | #include "ParseAction.h" 9 | #include "ParseFunc.h" 10 | #include "Rule.h" 11 | #include "STree.h" 12 | 13 | #include 14 | #include 15 | 16 | namespace statik { 17 | 18 | std::auto_ptr STAR(const std::string& name); 19 | std::auto_ptr PLUS(const std::string& name); 20 | 21 | struct ParseFunc_Star : public ParseFunc { 22 | public: 23 | ParseFunc_Star(bool plus = false) 24 | : m_plus(plus) {} 25 | virtual ~ParseFunc_Star() {} 26 | virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator); 27 | virtual std::auto_ptr Clone() { 28 | return std::auto_ptr(new ParseFunc_Star()); 29 | } 30 | 31 | private: 32 | bool m_plus; 33 | }; 34 | 35 | std::auto_ptr MakeParseFunc_Star(bool plus = false); 36 | 37 | } 38 | 39 | #endif // _statik_Star_h_ 40 | -------------------------------------------------------------------------------- /statik/State.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "State.h" 5 | 6 | #include 7 | using boost::lexical_cast; 8 | 9 | #include 10 | #include 11 | using std::ostream; 12 | using std::string; 13 | 14 | using namespace statik; 15 | 16 | /* public */ 17 | 18 | string State::UnMapStation(Station st) { 19 | switch (st) { 20 | case ST_PENDING: return "pending"; 21 | case ST_OK: return "ok"; 22 | case ST_BAD: return "bad"; 23 | case ST_DONE: return "done"; 24 | case ST_COMPLETE: return "complete"; 25 | default: throw SError("Failed to unmap Station " + lexical_cast(st)); 26 | } 27 | } 28 | 29 | State::State() 30 | : m_isLocked(false), 31 | m_station(ST_PENDING) { 32 | } 33 | 34 | State::State(Station station) 35 | : m_isLocked(false), 36 | m_station(station) { 37 | } 38 | 39 | void State::Clear() { 40 | m_station = ST_PENDING; 41 | Unlock(); 42 | } 43 | 44 | bool State::operator==(const State& rhs) const { 45 | return m_station == rhs.m_station && m_isLocked == rhs.m_isLocked; 46 | } 47 | 48 | bool State::operator!=(const State& rhs) const { 49 | return !(*this == rhs); 50 | } 51 | 52 | /* non-member */ 53 | 54 | ostream& statik::operator<< (ostream& out, const State& state) { 55 | out << state.Print(); 56 | return out; 57 | } 58 | -------------------------------------------------------------------------------- /statik/State.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_State_h_ 5 | #define _statik_State_h_ 6 | 7 | #include "SError.h" 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace statik { 15 | 16 | class State { 17 | public: 18 | // Ordering: worst to best 19 | enum Station { 20 | ST_PENDING, 21 | ST_BAD, 22 | ST_OK, 23 | ST_DONE, 24 | ST_COMPLETE 25 | }; 26 | static std::string UnMapStation(Station st); 27 | 28 | State(); 29 | State(Station station); 30 | 31 | void Clear(); 32 | 33 | Station GetStation() const { return m_station; } 34 | void SetStation(Station station) { m_station = station; } 35 | 36 | bool IsPending() const { return ST_PENDING == m_station; } 37 | bool IsOK() const { return ST_OK == m_station; } 38 | bool IsBad() const { return ST_BAD == m_station; } 39 | bool IsDone() const { return ST_DONE == m_station; } 40 | bool IsComplete() const { return ST_COMPLETE == m_station; } 41 | bool IsAccepting() const { return ST_OK == m_station || ST_DONE == m_station; } 42 | bool IsEmitting() const { return ST_DONE == m_station || ST_COMPLETE == m_station; } 43 | bool IsLocked() const { return m_isLocked; } 44 | 45 | void GoPending() { m_station = ST_PENDING; } 46 | void GoOK() { m_station = ST_OK; } 47 | void GoBad() { m_station = ST_BAD; } 48 | void GoDone() { m_station = ST_DONE; } 49 | void GoComplete() { m_station = ST_COMPLETE; } 50 | void Lock() { m_isLocked = true; } 51 | void Unlock() { m_isLocked = false; } 52 | 53 | bool operator==(const State& rhs) const; 54 | bool operator!=(const State& rhs) const; 55 | std::string Print() const { return UnMapStation(m_station); } 56 | 57 | private: 58 | bool m_isLocked; 59 | Station m_station; 60 | }; 61 | 62 | std::ostream& operator<< (std::ostream& out, const State& state); 63 | 64 | } 65 | 66 | #endif // _statik_State_h_ 67 | -------------------------------------------------------------------------------- /statik/reorg.txt: -------------------------------------------------------------------------------- 1 | Rule is just a factory for STree nodes. 2 | - Give it auto_ptr, auto_ptr 3 | - it doesn't use these, just clones them for STree nodes 4 | - AddChild(auto_ptr), AddChildRecursive(Rule*), ownership vec (vector eeps) 5 | - SilenceOutput, CapOutput are kinda funny 6 | 7 | ComputeFunc, OutputFunc are Init(STree&) to their STree node on STree constructor 8 | - except for the Rule funcs which are just prototypes 9 | 10 | STree: 11 | - Connector& 12 | - Rule& 13 | - State 14 | - parent* 15 | - isClear 16 | - vector children, depth 17 | - IConnection 18 | - auto_ptr, auto_ptr 19 | 20 | -------------------------------------------------------------------------------- /statik/test/Battery.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_test_Battery_h_ 5 | #define _statik_test_Battery_h_ 6 | 7 | #include "Test.h" 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace statik_test { 17 | 18 | class Battery { 19 | public: 20 | Battery(const std::string& name = "", 21 | std::istream& input = std::cin, 22 | std::ostream& output = std::cout); 23 | void Run(); 24 | 25 | protected: 26 | std::string m_name; 27 | std::istream& m_input; 28 | std::ostream& m_output; 29 | 30 | typedef boost::ptr_vector test_vec; 31 | typedef test_vec::const_iterator test_iter; 32 | typedef test_vec::iterator test_mod_iter; 33 | test_vec m_tests; 34 | }; 35 | 36 | } 37 | 38 | #endif // _statik_test_Battery_h_ 39 | -------------------------------------------------------------------------------- /statik/test/Keyword.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_test_Keyword_h_ 5 | #define _statik_test_Keyword_h_ 6 | 7 | #include "Test.h" 8 | 9 | #include 10 | 11 | namespace statik_test { 12 | 13 | class Keyword : public Test { 14 | public: 15 | Keyword() 16 | : Test("Keyword") {} 17 | virtual ~Keyword() {} 18 | 19 | protected: 20 | virtual void run(); 21 | }; 22 | 23 | } 24 | 25 | #endif // _statik_test_Keyword_h_ 26 | -------------------------------------------------------------------------------- /statik/test/Makefile.am: -------------------------------------------------------------------------------- 1 | STATIK_TEST_SRCS = \ 2 | Battery.cpp \ 3 | Battery.h \ 4 | Keyword.cpp \ 5 | Keyword.h \ 6 | Or.cpp \ 7 | Or.h \ 8 | STError.h \ 9 | STLog.cpp \ 10 | STLog.h \ 11 | Splash.cpp \ 12 | Splash.h \ 13 | Star.cpp \ 14 | Star.h \ 15 | StatikBattery.h \ 16 | Test.cpp \ 17 | Test.h \ 18 | main.cpp 19 | 20 | LIB_CXXFLAGS = -I../ -I../../ 21 | 22 | bin_PROGRAMS = statik_test 23 | statik_test_SOURCES = $(STATIK_TEST_SRCS) 24 | statik_test_LDADD = ../libstatik.a ../../util/libutil.a 25 | statik_test_CXXFLAGS = -ggdb -Wall -pedantic $(BOOST_CXXFLAGS) $(LIB_CXXFLAGS) 26 | statik_test_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) $(BOOST_REGEX_LDFLAGS) 27 | LIBS = $(BOOST_PROGRAM_OPTIONS_LIBS) $(BOOST_REGEX_LIBS) 28 | -------------------------------------------------------------------------------- /statik/test/Or.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_test_Or_h_ 5 | #define _statik_test_Or_h_ 6 | 7 | #include "Test.h" 8 | 9 | #include 10 | 11 | namespace statik_test { 12 | 13 | class Or : public Test { 14 | public: 15 | Or() 16 | : Test("Or") {} 17 | virtual ~Or() {} 18 | 19 | protected: 20 | virtual void run(); 21 | }; 22 | 23 | } 24 | 25 | #endif // _statik_test_Or_h_ 26 | -------------------------------------------------------------------------------- /statik/test/STError.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_test_STError_h_ 5 | #define _statik_test_STError_h_ 6 | 7 | #include "STLog.h" 8 | 9 | #include 10 | 11 | namespace statik_test { 12 | 13 | class STError : public std::runtime_error { 14 | public: 15 | STError(const std::string& what) : std::runtime_error(what) { 16 | g_log.error() << what; 17 | } 18 | }; 19 | 20 | } 21 | 22 | #endif // _statik_test_STError_h_ 23 | -------------------------------------------------------------------------------- /statik/test/STLog.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "STLog.h" 5 | 6 | using namespace statik_test; 7 | 8 | Log statik_test::g_log; 9 | -------------------------------------------------------------------------------- /statik/test/STLog.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_test_STLog_h_ 5 | #define _statik_test_STLog_h_ 6 | 7 | #include "util/Log.h" 8 | 9 | namespace statik_test { 10 | 11 | extern Log g_log; 12 | 13 | } 14 | 15 | #endif // _statik_test_STLog_h_ 16 | -------------------------------------------------------------------------------- /statik/test/Splash.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_test_Splash_h_ 5 | #define _statik_test_Splash_h_ 6 | 7 | #include "Test.h" 8 | 9 | #include 10 | 11 | namespace statik_test { 12 | 13 | class Splash : public Test { 14 | public: 15 | Splash() 16 | : Test("Splash") {} 17 | virtual ~Splash() {} 18 | 19 | protected: 20 | virtual void run(); 21 | }; 22 | 23 | } 24 | 25 | #endif // _statik_test_Splash_h_ 26 | -------------------------------------------------------------------------------- /statik/test/Star.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_test_Star_h_ 5 | #define _statik_test_Star_h_ 6 | 7 | #include "Test.h" 8 | 9 | #include 10 | 11 | namespace statik_test { 12 | 13 | class Star : public Test { 14 | public: 15 | Star() 16 | : Test("Star") {} 17 | virtual ~Star() {} 18 | 19 | protected: 20 | virtual void run(); 21 | }; 22 | 23 | } 24 | 25 | #endif // _statik_test_Star_h_ 26 | -------------------------------------------------------------------------------- /statik/test/StatikBattery.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _statik_test_StatikBattery_h_ 5 | #define _statik_test_StatikBattery_h_ 6 | 7 | #include "Battery.h" 8 | 9 | #include "Keyword.h" 10 | #include "Or.h" 11 | #include "Splash.h" 12 | #include "Star.h" 13 | 14 | namespace statik_test { 15 | 16 | class StatikBattery : public Battery { 17 | public: 18 | StatikBattery(const std::string& name = "statik", 19 | std::istream& input = std::cin, 20 | std::ostream& output = std::cout) { 21 | m_tests.push_back(new Keyword()); 22 | m_tests.push_back(new Or()); 23 | m_tests.push_back(new Star()); 24 | m_tests.push_back(new Splash()); 25 | } 26 | }; 27 | 28 | } 29 | 30 | #endif // _statik_test_StatikBattery_h_ 31 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | ./statik/test/statik_test -f log.log -L debug --slogfile slog.log --sloglevel debug 2 | -------------------------------------------------------------------------------- /util/Graphviz.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Graphviz.h" 5 | 6 | #include 7 | using boost::lexical_cast; 8 | 9 | #include 10 | using std::string; 11 | 12 | using namespace Util; 13 | 14 | string Util::dotVar(const void* x, const std::string& context) { 15 | return context + "_" + lexical_cast(x); 16 | } 17 | 18 | bool Util::isSafeLabelChar(char c) { 19 | return c >= 21 && c <= 126; 20 | } 21 | 22 | char Util::safeLabelChar(char c) { 23 | return isSafeLabelChar(c) ? c : '.'; 24 | } 25 | 26 | string Util::safeLabelStr(const string& str) { 27 | string s = str; 28 | for (size_t i = 0; i < s.length(); ++i) { 29 | if (!isSafeLabelChar(s[i])) { 30 | s[i] = '.'; 31 | } 32 | } 33 | return s; 34 | } 35 | -------------------------------------------------------------------------------- /util/Graphviz.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Graphviz_h_ 5 | #define _Graphviz_h_ 6 | 7 | /* Handy functions for interfacing with graphviz */ 8 | 9 | #include 10 | 11 | namespace Util { 12 | std::string dotVar(const void*, const std::string& context); 13 | bool isSafeLabelChar(char c); 14 | char safeLabelChar(char c); 15 | std::string safeLabelStr(const std::string& str); 16 | } 17 | 18 | #endif // _Graphviz_h_ 19 | -------------------------------------------------------------------------------- /util/Log.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Log.h" 5 | 6 | #include 7 | #include 8 | #include 9 | using std::cerr; 10 | using std::endl; 11 | using std::ostream; 12 | using std::ofstream; 13 | using std::string; 14 | 15 | Log::Log(const LEVEL level, ostream& err) 16 | : m_level(level), 17 | m_err(err) { 18 | } 19 | 20 | Log::Log(const string& logfile, const LEVEL level, ostream& err) 21 | : m_level(level), 22 | m_err(err) { 23 | Init(logfile); 24 | } 25 | 26 | Log::~Log() { 27 | debug() << "Destroying log"; 28 | m_log << endl; 29 | m_log.close(); 30 | } 31 | 32 | void Log::Init(const string& logfile) { 33 | if (m_log) { 34 | debug() << "Closing former log"; 35 | m_log.close(); 36 | } 37 | m_log.open(logfile.c_str()); 38 | if (!m_log) { 39 | throw std::runtime_error("Failed to open logfile " + logfile); 40 | } 41 | m_log << "Initialized log with output file " << logfile; 42 | } 43 | 44 | void Log::setLevel(LEVEL level) { 45 | m_level = level; 46 | } 47 | 48 | void Log::setLevel(const string& level) { 49 | if ("error" == level || "ERROR" == level) { 50 | setLevel(ERROR); 51 | } else if ("warning" == level || "WARNING" == level) { 52 | setLevel(WARNING); 53 | } else if ("info" == level || "INFO" == level) { 54 | setLevel(INFO); 55 | } else if ("debug" == level || "DEBUG" == level) { 56 | setLevel(DEBUG); 57 | } else { 58 | throw std::runtime_error("Cannot set log to unknown level '" + level + "'"); 59 | } 60 | } 61 | 62 | ostream& Log::error() { 63 | if (m_level > ERROR) return m_null; 64 | ostream& log = stream(); 65 | log << endl << "ERROR: "; 66 | return log; 67 | } 68 | 69 | ostream& Log::warning() { 70 | if (m_level > WARNING) return m_null; 71 | ostream& log = stream(); 72 | log << endl << "WARNING: "; 73 | return log; 74 | } 75 | 76 | ostream& Log::info() { 77 | if (!m_log || m_level > INFO) return m_null; 78 | m_log << endl << "INFO: "; 79 | return m_log; 80 | } 81 | 82 | ostream& Log::debug() { 83 | if (!m_log || m_level > DEBUG) return m_null; 84 | m_log << endl << "DEBUG: "; 85 | return m_log; 86 | } 87 | 88 | ostream& Log::stream() { 89 | if (m_log) { 90 | return m_log; 91 | } 92 | return m_err; 93 | } 94 | -------------------------------------------------------------------------------- /util/Log.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Log_h_ 5 | #define _Log_h_ 6 | 7 | /* Program execution log 8 | * 9 | * A file log with multiple log levels. Before it is initialized with an 10 | * output file name, warnings and errors will be directed to the err stream 11 | * (defaults to std::cerr). 12 | */ 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | class Log { 22 | public: 23 | enum LEVEL { 24 | DEBUG = 10, 25 | INFO = 20, 26 | WARNING = 30, 27 | ERROR = 40 28 | }; 29 | static std::string UnMapLevel(LEVEL level) { 30 | switch (level) { 31 | case DEBUG: return "debug"; 32 | case INFO: return "info"; 33 | case WARNING: return "warning"; 34 | case ERROR: return "error"; 35 | default: throw std::runtime_error("Cannot unmap level " + boost::lexical_cast(level)); 36 | } 37 | } 38 | 39 | Log(LEVEL level = WARNING, std::ostream& err = std::cerr); 40 | Log(const std::string& logfile, LEVEL level = INFO, std::ostream& err = std::cerr); 41 | ~Log(); 42 | 43 | void Init(const std::string& logfile); 44 | 45 | void setLevel(LEVEL level); 46 | void setLevel(const std::string& level); 47 | 48 | LEVEL getLevel() const { return m_level; } 49 | 50 | std::ostream& error(); 51 | std::ostream& warning(); 52 | std::ostream& info(); 53 | std::ostream& debug(); 54 | 55 | private: 56 | std::ostream& stream(); 57 | LEVEL m_level; 58 | std::ofstream m_log; 59 | std::ofstream m_null; 60 | std::ostream& m_err; 61 | }; 62 | 63 | #endif // _Log_h_ 64 | -------------------------------------------------------------------------------- /util/Makefile.am: -------------------------------------------------------------------------------- 1 | UTIL_SRCS = \ 2 | Graphviz.cpp \ 3 | Graphviz.h \ 4 | Log.cpp \ 5 | Log.h \ 6 | Util.cpp \ 7 | Util.h 8 | 9 | lib_LIBRARIES = libutil.a 10 | libutil_a_SOURCES = $(UTIL_SRCS) 11 | libutil_a_CXXFLAGS = -ggdb -Wall -pedantic $(BOOST_CXXFLAGS) 12 | -------------------------------------------------------------------------------- /util/Util.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Util.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace Util; 11 | 12 | using std::pair; 13 | using std::string; 14 | using std::stringstream; 15 | using std::vector; 16 | 17 | pair Util::break_word(string s) { 18 | size_t ws_pos = s.find(' '); 19 | return make_pair(string(s, 0, ws_pos), string(s, ws_pos+1, string::npos)); 20 | } 21 | 22 | vector Util::split(const string& s, char delim) { 23 | vector v; 24 | stringstream ss(s); 25 | string item; 26 | while (std::getline(ss, item, delim)) { 27 | v.push_back(item); 28 | } 29 | return v; 30 | } 31 | 32 | string Util::ltrim_space(const string& _s) { 33 | string s(_s); 34 | size_t startpos = s.find_first_not_of(' '); 35 | if (startpos != string::npos) { 36 | return s.substr(startpos); 37 | } 38 | return ""; 39 | } 40 | 41 | string Util::rtrim_space(const string& _s) { 42 | string s(_s); 43 | size_t endpos = s.find_last_not_of(' '); 44 | if (endpos != string::npos) { 45 | return s.substr(0, endpos+1); 46 | } 47 | return ""; 48 | } 49 | 50 | string Util::pad_str(const string& _s, char c, size_t len) { 51 | string s(_s); 52 | while (s.size() < len) { 53 | s = c + s; 54 | } 55 | return s; 56 | } 57 | -------------------------------------------------------------------------------- /util/Util.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Util_h_ 5 | #define _Util_h_ 6 | 7 | /* Miscellaneous utilities */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace Util { 14 | 15 | // Extract the first space-separated word from a string. 16 | // Returns the pair 17 | std::pair break_word(std::string s); 18 | 19 | // Split words of a string by whitespace 20 | std::vector split(const std::string& s, char delim = ' '); 21 | 22 | // Trim whitespace from the left of s 23 | std::string ltrim_space(const std::string& s); 24 | 25 | // Trim whitespace from the right of s 26 | std::string rtrim_space(const std::string& s); 27 | 28 | // Pad a string with a character on the left until it is of a minimum size 29 | std::string pad_str(const std::string& s, char c, size_t len); 30 | 31 | } 32 | 33 | #endif // _Util_h_ 34 | -------------------------------------------------------------------------------- /vm/Call.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Call.h" 5 | 6 | #include "Instructions.h" 7 | #include "Object.h" 8 | #include "VMError.h" 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | using std::auto_ptr; 15 | using std::string; 16 | using std::vector; 17 | 18 | // debug 19 | #include 20 | using std::cout; 21 | using std::endl; 22 | 23 | using namespace vm; 24 | 25 | void Call::exec(Context& context) const { 26 | Exec_Exp exec_Exp(context); 27 | auto_ptr function_obj = boost::apply_visitor(exec_Exp, function); 28 | args_vec args; 29 | for (vector::const_iterator i = argexps.begin(); 30 | i != argexps.end(); ++i) { 31 | args.push_back(boost::apply_visitor(exec_Exp, *i)); 32 | } 33 | // Call the function, discarding its return value 34 | (void) function_obj->callFunction(context, args); 35 | } 36 | -------------------------------------------------------------------------------- /vm/Call.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Call_h_ 5 | #define _Call_h_ 6 | 7 | /* A "procedure" call, i.e. a function call that isn't a method call. */ 8 | 9 | #include "Context.h" 10 | #include "Expression.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | namespace spirit = boost::spirit; 18 | namespace qi = spirit::qi; 19 | namespace ascii = spirit::ascii; 20 | 21 | #include 22 | #include 23 | 24 | namespace vm { 25 | 26 | struct Call { 27 | void exec(Context& context) const; 28 | Expression function; 29 | argexps_vec argexps; 30 | }; 31 | 32 | template struct ExpParser; 33 | 34 | template 35 | struct CallParser : qi::grammar { 36 | public: 37 | CallParser(ExpParser& exp_) 38 | : CallParser::base_type(call_, "Call"), 39 | exp_(exp_) { 40 | using qi::char_; 41 | using qi::lexeme; 42 | using qi::lit; 43 | using qi::graph; 44 | 45 | call_ %= 46 | lit("(call") 47 | > exp_ 48 | > *exp_ 49 | > lit(')') 50 | ; 51 | 52 | //BOOST_SPIRIT_DEBUG_NODE(call_); 53 | } 54 | 55 | private: 56 | ExpParser& exp_; 57 | 58 | qi::rule call_; 59 | }; 60 | 61 | } 62 | 63 | #endif // _Call_h_ 64 | -------------------------------------------------------------------------------- /vm/Cmd.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Cmd.h" 5 | 6 | #include "Instructions.h" 7 | #include "VMError.h" 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | using std::auto_ptr; 14 | using std::string; 15 | using std::vector; 16 | 17 | // debug 18 | #include 19 | using std::cout; 20 | using std::endl; 21 | 22 | using namespace vm; 23 | 24 | void Exec_Cmd::operator() (const Cmd& c, qi::unused_type, qi::unused_type) const { 25 | string cmd = c.cmd; 26 | Exec_Exp exec_Exp(m_context); 27 | size_t braces_pos = 0; 28 | for (Cmd::exp_iter i = c.exps.begin(); i != c.exps.end(); ++i) { 29 | auto_ptr exp = boost::apply_visitor(exec_Exp, *i); 30 | // The expression should have already provided us with the ->str. So just 31 | // need to reach in to extract its actual string value. 32 | boost::optional builtin = exp->builtinData(); 33 | if (!builtin) { 34 | throw VMError("Cmd expression was not a string"); 35 | } 36 | const string& exp_str = boost::get(*builtin); 37 | braces_pos = cmd.find("{}", braces_pos); 38 | if (string::npos == braces_pos) { 39 | throw VMError("Too many args provided to cmd " + c.cmd); 40 | } 41 | cmd.erase(braces_pos, 2); 42 | cmd.insert(braces_pos, exp_str); 43 | braces_pos += exp_str.size(); 44 | } 45 | if (cmd.find("{}", braces_pos) != string::npos) { 46 | throw VMError("Not enough args provided to cmd " + c.cmd); 47 | } 48 | cout << "RUN:" << cmd << endl; 49 | } 50 | -------------------------------------------------------------------------------- /vm/Cmd.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Cmd_h_ 5 | #define _Cmd_h_ 6 | 7 | /* A program (and its arguments) to invoke, preceded by expressions that should 8 | * be interpolated into the command. */ 9 | 10 | #include "Context.h" 11 | #include "Expression.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | namespace spirit = boost::spirit; 20 | namespace qi = spirit::qi; 21 | namespace ascii = spirit::ascii; 22 | 23 | #include 24 | #include 25 | 26 | // debug 27 | #include 28 | using std::cout; 29 | using std::endl; 30 | 31 | namespace vm { 32 | 33 | struct Cmd { 34 | typedef std::vector exp_vec; 35 | typedef exp_vec::const_iterator exp_iter; 36 | 37 | exp_vec exps; 38 | std::string cmd; 39 | }; 40 | 41 | struct Exec_Cmd { 42 | public: 43 | Exec_Cmd(Context& context) 44 | : m_context(context) {} 45 | 46 | void operator() (const Cmd& c, qi::unused_type, qi::unused_type) const; 47 | 48 | private: 49 | Context& m_context; 50 | }; 51 | 52 | template struct ExpParser; 53 | 54 | template 55 | struct CmdParser : qi::grammar { 56 | public: 57 | CmdParser(ExpParser& exp_) 58 | : CmdParser::base_type(cmd_, "Cmd"), 59 | exp_(exp_) { 60 | using qi::char_; 61 | using qi::int_; 62 | using qi::lit; 63 | using qi::no_skip; 64 | 65 | runcmd_ %= lit('[') > +no_skip[~char_("]")] > lit(']'); 66 | cmd_ %= 67 | lit("(cmd") 68 | > *(lit("(exp") > exp_ > ")") 69 | > runcmd_ 70 | > lit(')'); 71 | 72 | //BOOST_SPIRIT_DEBUG_NODE(runcmd_); 73 | //BOOST_SPIRIT_DEBUG_NODE(cmd_); 74 | } 75 | 76 | private: 77 | ExpParser& exp_; 78 | 79 | qi::rule runcmd_; 80 | qi::rule cmd_; 81 | }; 82 | 83 | } 84 | 85 | #endif // _Cmd_h_ 86 | -------------------------------------------------------------------------------- /vm/Context.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Context.h" 5 | 6 | #include "Instructions.h" 7 | #include "Object.h" 8 | #include "VMError.h" 9 | 10 | using namespace vm; 11 | 12 | const symbol_map& Context::globals() const { 13 | return m_globals; 14 | } 15 | 16 | symbol_map& Context::globals() { 17 | return m_globals; 18 | } 19 | 20 | const symbol_map& Context::locals() const { 21 | if (m_callstack.empty()) { 22 | return m_globals; 23 | } 24 | return m_callstack.back(); 25 | } 26 | 27 | symbol_map& Context::locals() { 28 | if (m_callstack.empty()) { 29 | return m_globals; 30 | } 31 | return m_callstack.back(); 32 | } 33 | 34 | const Object* Context::find(const std::string& name) const { 35 | if (!m_callstack.empty()) { 36 | symbol_iter local = m_callstack.back().find(name); 37 | if (local != m_callstack.back().end()) { 38 | return local->second; 39 | } 40 | } 41 | return findGlobal(name); 42 | } 43 | 44 | Object* Context::find(const std::string& name) { 45 | if (!m_callstack.empty()) { 46 | symbol_mod_iter local = m_callstack.back().find(name); 47 | if (local != m_callstack.back().end()) { 48 | return local->second; 49 | } 50 | } 51 | return findGlobal(name); 52 | } 53 | 54 | const Object* Context::findGlobal(const std::string& name) const { 55 | symbol_iter global = m_globals.find(name); 56 | if (global != m_globals.end()) { 57 | return global->second; 58 | } 59 | return NULL; 60 | } 61 | 62 | Object* Context::findGlobal(const std::string& name) { 63 | symbol_mod_iter global = m_globals.find(name); 64 | if (global != m_globals.end()) { 65 | return global->second; 66 | } 67 | return NULL; 68 | } 69 | 70 | void Context::addFrame() { 71 | m_callstack.push_back(stackframe_map()); 72 | } 73 | 74 | void Context::removeFrame() { 75 | if (m_callstack.empty()) { 76 | throw VMError("Cannot return from the top of the call stack!"); 77 | } 78 | m_callstack.pop_back(); 79 | } 80 | -------------------------------------------------------------------------------- /vm/Context.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Context_h_ 5 | #define _Context_h_ 6 | 7 | /* Execution context: call stack and global variables */ 8 | 9 | #include "Symbol.h" 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace vm { 17 | 18 | class Context { 19 | public: 20 | const symbol_map& globals() const; 21 | symbol_map& globals(); 22 | const symbol_map& locals() const; 23 | symbol_map& locals(); 24 | 25 | const Object* find(const std::string& name) const; 26 | Object* find(const std::string& name); 27 | 28 | const Object* findGlobal(const std::string& name) const; 29 | Object* findGlobal(const std::string& name); 30 | 31 | void addFrame(); 32 | void removeFrame(); 33 | 34 | size_t depth() const { return m_callstack.size(); } 35 | 36 | private: 37 | typedef symbol_map stackframe_map; 38 | typedef std::vector callstack_vec; 39 | typedef callstack_vec::const_iterator callstack_iter; 40 | 41 | symbol_map m_globals; 42 | callstack_vec m_callstack; 43 | }; 44 | 45 | inline std::ostream& operator<<(std::ostream& out, const Context& context) { 46 | out << "Context with " << boost::lexical_cast(context.globals().size()) << " globals, stack depth=" << boost::lexical_cast(context.depth()) << "\n"; 47 | out << "Globals: " << context.globals(); 48 | return out; 49 | } 50 | 51 | } 52 | 53 | #endif // _Context_h_ 54 | -------------------------------------------------------------------------------- /vm/Del.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Del.h" 5 | 6 | #include "Instructions.h" 7 | #include "Symbol.h" 8 | #include "VMError.h" 9 | 10 | // debug 11 | #include 12 | using std::cout; 13 | using std::endl; 14 | 15 | using namespace vm; 16 | 17 | void Del::exec(Context& context) const { 18 | cout << "Del: name=" << name << endl; 19 | symbol_mod_iter s = context.locals().find(name); 20 | if (context.locals().end() == s) { 21 | throw VMError("No such local symbol " + name + " to delete"); 22 | } 23 | context.locals().erase(s); 24 | } 25 | -------------------------------------------------------------------------------- /vm/Del.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Del_h_ 5 | #define _Del_h_ 6 | 7 | /* Del instruction: delete an object */ 8 | 9 | #include "Context.h" 10 | #include "Identifier.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | namespace spirit = boost::spirit; 18 | namespace qi = spirit::qi; 19 | namespace ascii = spirit::ascii; 20 | 21 | #include 22 | 23 | namespace vm { 24 | 25 | struct Del { 26 | void exec(Context& context) const; 27 | std::string name; 28 | }; 29 | 30 | template 31 | struct DelParser : qi::grammar { 32 | public: 33 | DelParser() : DelParser::base_type(del_, "Del") { 34 | using qi::char_; 35 | using qi::lexeme; 36 | using qi::lit; 37 | 38 | del_ %= 39 | lit("(del") 40 | > identifier_ 41 | > lit(')') 42 | ; 43 | 44 | //BOOST_SPIRIT_DEBUG_NODE(del_); 45 | } 46 | 47 | private: 48 | IdentifierParser identifier_; 49 | qi::rule del_; 50 | }; 51 | 52 | } 53 | 54 | #endif // _Del_h_ 55 | -------------------------------------------------------------------------------- /vm/Executor.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Executor_h_ 5 | #define _Executor_h_ 6 | 7 | /* VM instruction execution dispatch */ 8 | 9 | #include "Context.h" 10 | #include "Object.h" 11 | 12 | #include "util/Log.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | namespace vm { 22 | 23 | class New; 24 | 25 | class Executor { 26 | public: 27 | Executor(Log& log, std::istream& input); 28 | 29 | // returns true on full successful parse 30 | bool execute(); 31 | 32 | private: 33 | Log& m_log; 34 | std::istream& m_input; 35 | Context m_context; 36 | }; 37 | 38 | } 39 | 40 | #endif // _Executor_h_ 41 | -------------------------------------------------------------------------------- /vm/Identifier.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Identifier_h_ 5 | #define _Identifier_h_ 6 | 7 | /* Identifier */ 8 | 9 | #include 10 | namespace spirit = boost::spirit; 11 | namespace qi = spirit::qi; 12 | namespace ascii = spirit::ascii; 13 | 14 | #include 15 | 16 | namespace vm { 17 | 18 | template 19 | struct IdentifierParser : qi::grammar { 20 | public: 21 | IdentifierParser() : IdentifierParser::base_type(id_, "Identifier") { 22 | using qi::char_; 23 | 24 | id_ %= char_("A-Za-z_:@") > *char_("0-9A-Za-z_:@"); 25 | 26 | //BOOST_SPIRIT_DEBUG_NODE(id_); 27 | } 28 | 29 | private: 30 | qi::rule id_; 31 | }; 32 | 33 | } 34 | 35 | #endif // _Identifier_h_ 36 | -------------------------------------------------------------------------------- /vm/Instruction.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "Instruction.h" 5 | 6 | #include "Instructions.h" 7 | #include "VMError.h" 8 | 9 | #include 10 | namespace qi = boost::spirit::qi; 11 | 12 | using namespace vm; 13 | 14 | void Exec_Instruction::operator() (const Cmd& cmd) const { 15 | Exec_Cmd exec_Cmd(m_context); 16 | exec_Cmd(cmd, NULL, NULL); 17 | } 18 | 19 | void Exec_Instruction::operator() (const New& n) const { 20 | n.exec(m_context); 21 | } 22 | 23 | void Exec_Instruction::operator() (const Del& del) const { 24 | del.exec(m_context); 25 | } 26 | 27 | void Exec_Instruction::operator() (const Call& call) const { 28 | call.exec(m_context); 29 | } 30 | -------------------------------------------------------------------------------- /vm/Instruction.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Instruction_h_ 5 | #define _Instruction_h_ 6 | 7 | /* Executable instructions */ 8 | 9 | #include "Context.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | namespace spirit = boost::spirit; 17 | namespace qi = spirit::qi; 18 | namespace ascii = spirit::ascii; 19 | 20 | #include 21 | #include 22 | 23 | namespace vm { 24 | 25 | struct Call; 26 | struct Cmd; 27 | struct Del; 28 | struct New; 29 | 30 | typedef boost::variant< 31 | boost::recursive_wrapper, 32 | boost::recursive_wrapper, 33 | boost::recursive_wrapper, 34 | boost::recursive_wrapper 35 | > Instruction; 36 | 37 | struct Exec_Instruction : public boost::static_visitor<> { 38 | public: 39 | Exec_Instruction(Context& context) 40 | : m_context(context) {} 41 | 42 | void operator() (const Instruction& instruction, qi::unused_type, qi::unused_type) const { 43 | boost::apply_visitor(*this, instruction); 44 | } 45 | void operator() (const Cmd& cmd) const; 46 | void operator() (const New& n) const; 47 | void operator() (const Del& del) const; 48 | void operator() (const Call& call) const; 49 | 50 | private: 51 | Context& m_context; 52 | }; 53 | 54 | } 55 | 56 | #endif // _Instruction_h_ 57 | -------------------------------------------------------------------------------- /vm/InstructionParser.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _InstructionParser_h_ 5 | #define _InstructionParser_h_ 6 | 7 | /* Instruction parser */ 8 | 9 | #include "Call.h" 10 | #include "Cmd.h" 11 | #include "Context.h" 12 | #include "Del.h" 13 | #include "Instruction.h" 14 | #include "New.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | namespace spirit = boost::spirit; 22 | namespace qi = spirit::qi; 23 | namespace ascii = spirit::ascii; 24 | 25 | #include 26 | #include 27 | 28 | namespace vm { 29 | 30 | template struct ExpParser; 31 | 32 | template 33 | struct InstructionParser 34 | : qi::grammar { 35 | public: 36 | InstructionParser(ExpParser& exp_) 37 | : InstructionParser::base_type(instruction_, "Instruction"), 38 | cmd_(exp_), 39 | new_(exp_), 40 | call_(exp_) { 41 | 42 | instruction_ %= 43 | new_ 44 | | del_ 45 | | call_ 46 | | cmd_ 47 | ; 48 | 49 | //BOOST_SPIRIT_DEBUG_NODE(instruction_); 50 | } 51 | 52 | private: 53 | CmdParser cmd_; 54 | NewParser new_; 55 | DelParser del_; 56 | CallParser call_; 57 | qi::rule instruction_; 58 | }; 59 | 60 | } 61 | 62 | #endif // _InstructionParser_h_ 63 | -------------------------------------------------------------------------------- /vm/Instructions.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Instructions_h_ 5 | #define _Instructions_h_ 6 | 7 | #include "Call.h" 8 | #include "Cmd.h" 9 | #include "Del.h" 10 | #include "New.h" 11 | 12 | #endif // _Instructions_h_ 13 | -------------------------------------------------------------------------------- /vm/Makefile.am: -------------------------------------------------------------------------------- 1 | UTIL_DIR = ../util 2 | UTIL_SRCS = \ 3 | $(UTIL_DIR)/Log.cpp \ 4 | $(UTIL_DIR)/Log.h 5 | 6 | COMMON_SRCS = $(UTIL_SRCS) 7 | 8 | bin_PROGRAMS = shok_vm 9 | shok_vm_SOURCES = $(COMMON_SRCS) \ 10 | Call.cpp \ 11 | Call.h \ 12 | Cmd.cpp \ 13 | Cmd.h \ 14 | Context.cpp \ 15 | Context.h \ 16 | Del.cpp \ 17 | Del.h \ 18 | Executor.cpp \ 19 | Executor.h \ 20 | ExpParser.h \ 21 | Expression.cpp \ 22 | Expression.h \ 23 | Identifier.h \ 24 | Instruction.cpp \ 25 | Instruction.h \ 26 | InstructionParser.h \ 27 | Instructions.h \ 28 | New.cpp \ 29 | New.h \ 30 | Object.cpp \ 31 | Object.h \ 32 | StdLib.cpp \ 33 | StdLib.h \ 34 | Symbol.h \ 35 | VMError.h \ 36 | vm.cpp 37 | shok_vm_CPPFLAGS = $(BOOST_CPPFLAGS) 38 | -------------------------------------------------------------------------------- /vm/New.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "New.h" 5 | 6 | #include "Instructions.h" 7 | #include "VMError.h" 8 | 9 | #include 10 | using std::auto_ptr; 11 | 12 | // debug 13 | #include 14 | using std::cout; 15 | using std::endl; 16 | 17 | using namespace vm; 18 | 19 | void New::exec(Context& context) const { 20 | cout << "New: name=" << name << endl; 21 | Exec_Exp exec_Exp(context); 22 | auto_ptr value = boost::apply_visitor(exec_Exp, exp); 23 | if (context.find(name)) { 24 | throw VMError("Cannot insert symbol " + name + "; already exists"); 25 | } 26 | context.locals().insert(name, value); 27 | } 28 | -------------------------------------------------------------------------------- /vm/New.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _New_h_ 5 | #define _New_h_ 6 | 7 | /* A New instruction: defines a symbol (name, type, value) */ 8 | 9 | #include "Context.h" 10 | #include "Expression.h" 11 | #include "Identifier.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | namespace spirit = boost::spirit; 19 | namespace qi = spirit::qi; 20 | namespace ascii = spirit::ascii; 21 | 22 | #include 23 | 24 | namespace vm { 25 | 26 | struct New { 27 | void exec(Context& context) const; 28 | std::string name; 29 | Expression exp; 30 | }; 31 | 32 | template struct ExpParser; 33 | 34 | template 35 | struct NewParser : qi::grammar { 36 | public: 37 | NewParser(ExpParser& exp_) 38 | : NewParser::base_type(new_, "New"), 39 | exp_(exp_) { 40 | using qi::char_; 41 | using qi::lexeme; 42 | using qi::lit; 43 | using qi::graph; 44 | 45 | new_ %= 46 | lit("(new") 47 | > identifier_ 48 | > exp_ 49 | > lit(')') 50 | ; 51 | 52 | //BOOST_SPIRIT_DEBUG_NODE(new_); 53 | } 54 | 55 | private: 56 | ExpParser& exp_; 57 | 58 | IdentifierParser identifier_; 59 | qi::rule new_; 60 | }; 61 | 62 | } 63 | 64 | #endif // _New_h_ 65 | -------------------------------------------------------------------------------- /vm/Object.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Object_h_ 5 | #define _Object_h_ 6 | 7 | /* Object */ 8 | 9 | #include "Context.h" 10 | #include "Instruction.h" 11 | #include "Symbol.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | namespace vm { 22 | 23 | typedef std::vector function_vec; 24 | typedef function_vec::const_iterator function_iter; 25 | 26 | typedef boost::ptr_vector args_vec; 27 | typedef args_vec::const_iterator args_iter; 28 | 29 | typedef boost::variant< 30 | int, 31 | std::string 32 | > BuiltinData; 33 | 34 | class Object { 35 | public: 36 | Object(); 37 | Object(const Object&); 38 | Object& operator= (const Object&); 39 | ~Object(); 40 | 41 | const Object* find(const std::string& name) const; 42 | Object* find(const std::string& name); 43 | 44 | void insert(const std::string& name, std::auto_ptr value); 45 | void assign(const std::string& name, std::auto_ptr value); 46 | 47 | void insertFunction(std::auto_ptr function); 48 | std::auto_ptr callFunction(Context& context, args_vec& args) const; 49 | 50 | void insertBuiltin(const BuiltinData& builtin) { 51 | m_builtin = builtin; 52 | } 53 | boost::optional builtinData() const { return m_builtin; } 54 | 55 | protected: 56 | symbol_map m_members; 57 | std::auto_ptr m_function; 58 | boost::optional m_builtin; 59 | }; 60 | 61 | } 62 | 63 | #endif // _Object_h_ 64 | -------------------------------------------------------------------------------- /vm/StdLib.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #include "StdLib.h" 5 | 6 | #include "Expression.h" 7 | #include "Instructions.h" 8 | #include "Object.h" 9 | #include "VMError.h" 10 | 11 | #include 12 | #include 13 | using std::auto_ptr; 14 | using std::string; 15 | 16 | using namespace vm; 17 | 18 | std::string StdLib::OBJECT = "object"; 19 | std::string StdLib::FUNCTION = "@"; 20 | std::string StdLib::INTEGER = "int"; 21 | std::string StdLib::STRING = "str"; 22 | 23 | void StdLib::Initialize(symbol_map& symbols) { 24 | { 25 | auto_ptr object(new Object()); 26 | symbols.insert(OBJECT, object); 27 | } 28 | symbol_iter object = symbols.find(OBJECT); 29 | 30 | { 31 | auto_ptr function(new Object(*object->second)); 32 | symbols.insert(FUNCTION, function); 33 | } 34 | symbol_iter function = symbols.find(FUNCTION); 35 | 36 | { 37 | auto_ptr int_(new Object(*object->second)); 38 | symbols.insert(INTEGER, int_); 39 | } 40 | //symbol_iter int_ = symbols.find(INTEGER); 41 | 42 | { 43 | auto_ptr str(new Object(*object->second)); 44 | symbols.insert(STRING, str); 45 | } 46 | //symbol_iter str = symbols.find(STRING); 47 | 48 | { 49 | auto_ptr print(new Object(*function->second)); 50 | symbols.insert("print", print); 51 | } { 52 | symbol_mod_iter print = symbols.find("print"); 53 | auto_ptr function(new function_vec()); 54 | Cmd c; 55 | Variable arg(".arg1"); 56 | c.exps.push_back(arg); 57 | c.cmd = "echo {}"; 58 | function->push_back(c); 59 | print->second->insertFunction(function); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /vm/StdLib.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _StdLib_h_ 5 | #define _StdLib_h_ 6 | 7 | /* A runtime symbol table */ 8 | 9 | #include "Symbol.h" 10 | 11 | #include 12 | #include 13 | 14 | namespace vm { 15 | 16 | class StdLib { 17 | public: 18 | static std::string OBJECT; 19 | static std::string FUNCTION; 20 | static std::string INTEGER; 21 | static std::string STRING; 22 | 23 | static void Initialize(symbol_map& symbols); 24 | }; 25 | 26 | } 27 | 28 | #endif // _StdLib_h_ 29 | -------------------------------------------------------------------------------- /vm/Symbol.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _Symbol_h_ 5 | #define _Symbol_h_ 6 | 7 | /* Symbol */ 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | namespace vm { 16 | 17 | class Object; 18 | 19 | typedef boost::ptr_map symbol_map; 20 | typedef symbol_map::const_iterator symbol_iter; 21 | typedef symbol_map::iterator symbol_mod_iter; 22 | 23 | inline std::ostream& operator<<(std::ostream& out, const symbol_map& smap) { 24 | out << "symbol map with " << boost::lexical_cast(smap.size()) << " members:\n"; 25 | for (symbol_iter i = smap.begin(); i != smap.end(); ++i) { 26 | out << " - " << i->first << "\n"; 27 | } 28 | return out; 29 | } 30 | 31 | } 32 | 33 | #endif // _Symbol_h_ 34 | -------------------------------------------------------------------------------- /vm/VMError.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | #ifndef _VMError_h_ 5 | #define _VMError_h_ 6 | 7 | /* VM errors */ 8 | 9 | #include "util/Log.h" 10 | 11 | #include 12 | 13 | namespace vm { 14 | 15 | class VMError : public std::runtime_error { 16 | public: 17 | VMError(const std::string& what) : std::runtime_error(what) {} 18 | VMError(Log& log, const std::string& what) : std::runtime_error(what) { 19 | log.error(what); 20 | } 21 | }; 22 | 23 | } 24 | 25 | #endif // _VMError_h_ 26 | -------------------------------------------------------------------------------- /vm/vm.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Michael Biggs. See the COPYING file at the top-level 2 | // directory of this distribution and at http://shok.io/code/copyright.html 3 | 4 | /* shok virtual machine execution engine 5 | * 6 | * Reads lines of stack-based "shok vm bytecode", and executes them. 7 | */ 8 | 9 | #include "Executor.h" 10 | #include "Instructions.h" 11 | #include "VMError.h" 12 | 13 | #include "util/Log.h" 14 | 15 | #include 16 | #include 17 | using std::cin; 18 | using std::cout; 19 | using std::endl; 20 | using std::string; 21 | 22 | using namespace vm; 23 | 24 | namespace { 25 | const string PROGRAM_NAME = "shok_vm"; 26 | const string LOGFILE = "vm.log"; 27 | } 28 | 29 | int main(int argc, char *argv[]) { 30 | if (argc < 1 || argc > 2) { 31 | cout << "usage: " << PROGRAM_NAME << " [log level]" << endl; 32 | return 1; 33 | } 34 | 35 | Log log(LOGFILE); 36 | try { 37 | if (2 == argc) { 38 | log.setLevel(argv[1]); 39 | } 40 | Executor executor(log, cin); 41 | if (!executor.execute()) { 42 | cout << "failed to execute program!" << endl; 43 | } 44 | } catch (const VMError& e) { 45 | log.error(string("Error executing bytecode: ") + e.what()); 46 | cout << endl; 47 | } catch (const std::exception& e) { 48 | log.error(string("Unknown error: ") + e.what()); 49 | } catch (...) { 50 | log.error("Unknown error"); 51 | } 52 | 53 | return 0; 54 | } 55 | --------------------------------------------------------------------------------