/* * Copyright (C) 2012-2015 Robin Haberkorn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef __PARSER_H #define __PARSER_H #include #include "sciteco.h" #include "undo.h" #include "error.h" namespace SciTECO { /* TECO uses only lower 7 bits for commands */ #define MAX_TRANSITIONS 127 class State { protected: /* static transitions */ State *transitions[MAX_TRANSITIONS]; inline void init(const gchar *chars, State &state) { while (*chars) transitions[(int)*chars++] = &state; } inline void init(const gchar *chars) { init(chars, *this); } public: State(); static void input(gchar chr); State *get_next_state(gchar chr); protected: static bool eval_colon(void); virtual State * custom(gchar chr) { throw SyntaxError(chr); return NULL; } }; template class MicroStateMachine { protected: /* label pointers */ typedef const void *MicroState; const MicroState StateStart; #define MICROSTATE_START G_STMT_START { \ if (this->state != StateStart) \ goto *this->state; \ } G_STMT_END MicroState state; #ifdef EMSCRIPTEN /* FIXME: Shouldn't be required! */ __attribute__((noinline)) #else inline #endif void set(MicroState next) { if (next != state) undo.push_var(state) = next; } public: MicroStateMachine() : StateStart(NULL), state(StateStart) {} virtual ~MicroStateMachine() {} virtual inline void reset(void) { set(StateStart); } virtual Type input(gchar chr) = 0; }; /* avoid circular dependency on qregisters.h */ class QRegSpecMachine; class StringBuildingMachine : public MicroStateMachine { QRegSpecMachine *qregspec_machine; enum Mode { MODE_NORMAL, MODE_UPPER, MODE_LOWER } mode; bool toctl; public: StringBuildingMachine() : MicroStateMachine(), qregspec_machine(NULL), mode(MODE_NORMAL), toctl(false) {} ~StringBuildingMachine(); void reset(void); gchar *input(gchar chr); }; /* * Super-class for states accepting string arguments * Opaquely cares about alternative-escape characters, * string building commands and accumulation into a string */ class StateExpectString : public State { StringBuildingMachine machine; gint nesting; bool string_building; bool last; public: StateExpectString(bool _building = true, bool _last = true) : State(), nesting(1), string_building(_building), last(_last) {} private: State *custom(gchar chr); protected: virtual void initial(void) {} virtual void process(const gchar *str, gint new_chars) {} virtual State *done(const gchar *str) = 0; }; class StateExpectFile : public StateExpectString { public: StateExpectFile(bool _building = true, bool _last = true) : StateExpectString(_building, _last) {} }; class StateStart : public State { public: StateStart(); private: void insert_integer(tecoInt v); tecoInt read_integer(void); tecoBool move_chars(tecoInt n); tecoBool move_lines(tecoInt n); tecoBool delete_words(tecoInt n); State *custom(gchar chr); }; class StateControl : public State { public: StateControl(); private: State *custom(gchar chr); }; class StateASCII : public State { public: StateASCII(); private: State *custom(gchar chr); }; class StateFCommand : public State { public: StateFCommand(); private: State *custom(gchar chr); }; class StateCondCommand : public State { public: StateCondCommand(); private: State *custom(gchar chr); }; class StateECommand : public State { public: StateECommand(); private: State *custom(gchar chr); }; class StateScintilla_symbols : public StateExpectString { public: StateScintilla_symbols() : StateExpectString(true, false) {} private: State *done(const gchar *str); }; class StateScintilla_lParam : public StateExpectString { private: State *done(const gchar *str); }; /* * also serves as base class for replace-insertion states */ class StateInsert : public StateExpectString { public: StateInsert(bool building = true) : StateExpectString(building) {} protected: void initial(void); void process(const gchar *str, gint new_chars); State *done(const gchar *str); }; class StateInsertIndent : public StateInsert { protected: void initial(void); }; namespace States { extern StateStart start; extern StateControl control; extern StateASCII ascii; extern StateFCommand fcommand; extern StateCondCommand condcommand; extern StateECommand ecommand; extern StateScintilla_symbols scintilla_symbols; extern StateScintilla_lParam scintilla_lparam; extern StateInsert insert_building; extern StateInsert insert_nobuilding; extern StateInsertIndent insert_indent; extern State *current; static inline bool is_string() { return dynamic_cast(current); } static inline bool is_insertion() { return dynamic_cast(current); } static inline bool is_file() { return dynamic_cast(current); } } extern enum Mode { MODE_NORMAL = 0, MODE_PARSE_ONLY_GOTO, MODE_PARSE_ONLY_LOOP, MODE_PARSE_ONLY_COND } mode; #define BEGIN_EXEC(STATE) G_STMT_START { \ if (mode > MODE_NORMAL) \ return STATE; \ } G_STMT_END extern gint macro_pc; extern gchar *strings[2]; extern gchar escape_char; namespace Execute { void step(const gchar *macro, gint stop_pos); void macro(const gchar *macro, bool locals = true); void file(const gchar *filename, bool locals = true); } } /* namespace SciTECO */ #endif