├── .gitignore ├── .travis.yml ├── Makefile ├── test ├── intbasic_token.h ├── README.md ├── lemon_base.h ├── lisp_main.h ├── Makefile ├── any.lemon ├── lisp_main.ragel ├── expr.lemon ├── intbasic.lemon ├── intbasic_lexer.ragel ├── lisp.lemon ├── lisp_cell.h ├── lisp_cell.cpp └── lempar.cxx ├── lemon_base.h ├── README.md ├── lempar.c └── lempar.cxx /.gitignore: -------------------------------------------------------------------------------- 1 | *.dSYM 2 | *.o 3 | lemon 4 | lemon-- 5 | lemon++ 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | script: make 3 | compiler: 4 | - clang 5 | - gcc 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -g -std=c89 2 | 3 | ifdef HOMEBREW_TEMPLATE_PATH 4 | CFLAGS += -DHOMEBREW_TEMPLATE_PATH=\"$(HOMEBREW_TEMPLATE_PATH)\" 5 | endif 6 | 7 | all : lemon lemon++ lemon-- 8 | clean: 9 | $(RM) lemon lemon++ lemon-- 10 | 11 | lemon++ : lemon.c 12 | $(CC) $(CFLAGS) -DLEMONPLUSPLUS=1 -DTEMPLATE_EXTENSION=\".cxx\" $< -o $@ 13 | 14 | lemon-- : lemon.c 15 | $(CC) $(CFLAGS) -DLEMONPLUSPLUS=1 $< -o $@ 16 | 17 | lemon : lemon.c 18 | $(CC) $(CFLAGS) $< -o $@ 19 | -------------------------------------------------------------------------------- /test/intbasic_token.h: -------------------------------------------------------------------------------- 1 | #ifndef __intbasic_token_h__ 2 | #define __intbasic_token_h__ 3 | 4 | #include 5 | 6 | struct token { 7 | std::string stringValue; 8 | int intValue = 0; 9 | 10 | token() = default; 11 | ~token() = default; 12 | 13 | token(const token &) = default; 14 | token(token &&) = default; 15 | 16 | token(int i) : intValue(i) 17 | {} 18 | 19 | token(const std::string &s) : stringValue(s) 20 | {} 21 | 22 | token(std::string &&s) : stringValue(std::move(s)) 23 | {} 24 | 25 | 26 | token &operator=(const token &) = default; 27 | token &operator=(token &&) = default; 28 | }; 29 | 30 | #endif -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # lisp 2 | 3 | An implementation of lisp, as originally intended. (_i.e._, m-expressions). 4 | Demonstrates an object-oriented parser (`lempar.cxx`, `lemon_base.h`) 5 | 6 | x: (1, 2, 3, 4) # a list 7 | cadr[x] : car[cdr[x]] # function definition 8 | y: 1+2*3+4 # math 9 | 10 | car[x] # call a function 11 | cdr[x] 12 | cadr[x] 13 | 14 | 15 | # intbasic 16 | 17 | Apple Integer Basic. Accepts or rejects but doesn't build a parse tree. 18 | 19 | # expr 20 | 21 | Converts infix expressions on the command-line to lisp. Uses smart pointers. 22 | 23 | # any 24 | 25 | A very early test. Tokens have a deleted copy constructor/operator= to verify 26 | move assignment works. 27 | 28 | -------------------------------------------------------------------------------- /lemon_base.h: -------------------------------------------------------------------------------- 1 | #ifndef __lemon_base_h__ 2 | #define __lemon_base_h__ 3 | #include 4 | 5 | template 6 | class lemon_base { 7 | public: 8 | typedef TokenType token_type; 9 | 10 | virtual ~lemon_base() = default; 11 | 12 | //virtual typename std::enable_if::value, void>::type 13 | virtual void parse(int yymajor, TokenType &&yyminor) = 0; 14 | 15 | virtual void trace(FILE *, const char *) {} 16 | 17 | virtual bool will_accept() const = 0; 18 | virtual int fallback(int iToken) const = 0; 19 | 20 | virtual void reset() {} 21 | 22 | protected: 23 | virtual void parse_accept() {} 24 | virtual void parse_failure() {} 25 | virtual void stack_overflow() {} 26 | virtual void syntax_error(int yymajor, TokenType &yyminor) {} 27 | lemon_base() {} 28 | 29 | private: 30 | lemon_base(const lemon_base &) = delete; 31 | lemon_base(lemon_base &&) = delete; 32 | lemon_base &operator=(const lemon_base &) = delete; 33 | lemon_base &operator=(lemon_base &&) = delete; 34 | }; 35 | 36 | #endif -------------------------------------------------------------------------------- /test/lemon_base.h: -------------------------------------------------------------------------------- 1 | #ifndef __lemon_base_h__ 2 | #define __lemon_base_h__ 3 | #include 4 | 5 | template 6 | class lemon_base { 7 | public: 8 | typedef TokenType token_type; 9 | 10 | virtual ~lemon_base() = default; 11 | 12 | #if 0 13 | virtual typename std::enable_if::value, void>::type 14 | parse(int yymajor, const TokenType &yyminor) = 0; 15 | #endif 16 | 17 | //virtual typename std::enable_if::value, void>::type 18 | virtual void parse(int yymajor, TokenType &&yyminor) = 0; 19 | virtual void trace(FILE *, const char *) = 0; 20 | virtual bool will_accept() const = 0; 21 | virtual int fallback(int iToken) const = 0; 22 | 23 | virtual void reset() {} 24 | 25 | protected: 26 | virtual void parse_accept() {} 27 | virtual void parse_failure() {} 28 | virtual void stack_overflow() {} 29 | virtual void syntax_error(int yymajor, TokenType &yyminor) {} 30 | lemon_base() {} 31 | 32 | private: 33 | lemon_base(const lemon_base &) = delete; 34 | lemon_base(lemon_base &&) = delete; 35 | lemon_base &operator=(const lemon_base &) = delete; 36 | lemon_base &operator=(lemon_base &&) = delete; 37 | }; 38 | 39 | #endif -------------------------------------------------------------------------------- /test/lisp_main.h: -------------------------------------------------------------------------------- 1 | #ifndef __lisp_parser_h__ 2 | #define __lisp_parser_h__ 3 | 4 | #include "../lemon_base.h" 5 | #include 6 | #include 7 | #include 8 | 9 | struct Token { 10 | 11 | Token() = default; 12 | Token(const Token &) = default; 13 | Token(Token &&) = default; 14 | 15 | Token(int i) : intValue(i) 16 | {} 17 | Token(const std::string &s) : stringValue(s) 18 | {} 19 | Token(std::string &&s) : stringValue(std::move(s)) 20 | {} 21 | 22 | 23 | Token& operator=(const Token &) = default; 24 | Token& operator=(Token &&) = default; 25 | 26 | int intValue = 0; 27 | std::string stringValue; 28 | }; 29 | 30 | class mexpr_parser : public lemon_base{ 31 | public: 32 | static std::unique_ptr create(); 33 | 34 | using lemon_base::parse; 35 | void parse(int major) { parse(major, Token{}); } 36 | 37 | template 38 | void parse(int major, T &&t) { parse(major, Token(std::forward(t))); } 39 | 40 | bool continuation() const; 41 | 42 | protected: 43 | virtual void parse_failure() final override { 44 | fail = true; 45 | error = true; 46 | //printf("Fail!\n"); 47 | } 48 | virtual void parse_accept() final override { 49 | //printf("Accept!\n"); 50 | error = 0; 51 | } 52 | 53 | virtual void syntax_error(int yymajor, token_type &yyminor) final override { 54 | //printf("Syntax Error!\n"); 55 | error++; 56 | } 57 | 58 | 59 | private: 60 | bool fail = false; 61 | protected: 62 | unsigned error = 0; 63 | 64 | }; 65 | 66 | 67 | 68 | 69 | #endif -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | CXX = clang++ 2 | CXXFLAGS = -g -std=c++14 3 | CCFLAGS = -g 4 | 5 | TARGETS = any expr intbasic lisp 6 | 7 | #.SUFFIXES: 8 | 9 | # prevent intermediate files from being deleted. 10 | .SECONDARY: 11 | 12 | 13 | all : $(TARGETS) 14 | 15 | clean : 16 | $(RM) -- $(TARGETS) $(TARGETS:=.cpp) $(TARGETS:=.h) $(TARGETS:=.out) \ 17 | intbasic_lexer.cpp lisp_main.cpp lisp_main.o 18 | 19 | 20 | intbasic : intbasic.cpp intbasic_lexer.cpp 21 | intbasic_lexer.cpp : intbasic_lexer.ragel intbasic.cpp 22 | 23 | lisp : lisp.o lisp_main.o lisp_cell.o 24 | lisp_cell.o : lisp_cell.cpp lisp_cell.h lisp.h 25 | lisp_main.o : lisp_main.cpp lisp_cell.h lisp.h 26 | 27 | error-1.o : error.c 28 | $(CC) $(CCFLAGS) -c $< -o $@ 29 | 30 | error-2.o : error.cpp 31 | $(CXX) $(CXXFLAGS) -c $< -o $@ 32 | 33 | error.cpp : error.lemon ../lemon++ ../lempar.cxx 34 | ../lemon++ -T../lempar.cxx $(LEMONFLAGS) $< 35 | 36 | expr.o : expr.cpp 37 | ../lemon++ -T../lempar.cpp $(LEMONFLAGS) $< 38 | 39 | 40 | % : %.o 41 | $(CXX) $(LDFLAGS) $^ -o $@ 42 | #$(RM) -- $^ 43 | 44 | #%.o : %.cpp 45 | # $(CXX) $(CXXFLAGS) -c $< -o $@ 46 | 47 | any.cpp : any.lemon ../lemon++ ../lempar.cpp 48 | ../lemon++ -T../lempar.cpp nconflicts=2 $< 49 | 50 | lisp.cpp : lisp.lemon lisp_main.h lisp_cell.h ../lemon++ ../lempar.cxx 51 | ../lemon++ -T../lempar.cxx $< 52 | 53 | %.cpp : %.lemon ../lemon++ ../lempar.cpp 54 | ../lemon++ -T../lempar.cpp $(LEMONFLAGS) $< 55 | 56 | %.c : %.lemon ../lemon ../lempar.c 57 | ../lemon -T../lempar.c $(LEMONFLAGS) $< 58 | 59 | # %.cxx : %.lemon ../lemon++ ../lempar.cxx 60 | # ../lemon++ -T../lempar.cxx $(LEMONFLAGS) $< 61 | 62 | %.cpp : %.ragel 63 | ragel -p -T1 $< -o $@ -------------------------------------------------------------------------------- /test/any.lemon: -------------------------------------------------------------------------------- 1 | 2 | %include { 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "any.h" 10 | 11 | #define YYMALLOCARGTYPE size_t 12 | 13 | /* 14 | * This was _going_ to use std::experimental::any 15 | * as the token type. Unfortunately, my current version of 16 | * libcxx doesn't include experimental/any. In it's place, 17 | * a std::string/int pair. 18 | */ 19 | 20 | /* 21 | * note - the copy constructors are deleted. only the 22 | * move constructors are used in the generated parser! 23 | */ 24 | struct token { 25 | token() = default; 26 | token(token &&) = default; 27 | token(const token &) = delete; 28 | 29 | token &operator=(token &&) = default; 30 | token &operator=(const token &) = delete; 31 | 32 | token(int value) : intValue(value) {} 33 | token(const std::string &value) : stringValue(value) {} 34 | token(std::string &&value) : stringValue(std::move(value)) {} 35 | token(const char *cp) : token(std::string(cp)) {} 36 | 37 | 38 | 39 | operator const std::string &() const { return stringValue; } 40 | operator int() const { return intValue; } 41 | 42 | 43 | std::string stringValue; 44 | int intValue = 0; 45 | }; 46 | 47 | } 48 | %code { 49 | 50 | //void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)); 51 | //void ParseFree(void *p, void (*freeProc)(void*)); 52 | 53 | // could also use "token &" or "const token &" (needs copy constructor enabled) 54 | //void Parse(void *yyp,int yymajor, token &&yyminor); 55 | 56 | int main(int argc, char ** argv) { 57 | void *p; 58 | 59 | p = ParseAlloc(malloc); 60 | 61 | Parse(p, STRING, "string 1"); 62 | Parse(p, STRING, "string 2"); 63 | Parse(p, STRING, "string 3"); 64 | 65 | Parse(p, NUMBER, 1); 66 | Parse(p, NUMBER, 2); 67 | Parse(p, NUMBER, 3); 68 | 69 | Parse(p, STRING, "another 1"); 70 | Parse(p, STRING, "another 2"); 71 | Parse(p, STRING, "another 3"); 72 | 73 | Parse(p, 0, 0); 74 | 75 | 76 | ParseFree(p, free); 77 | return 0; 78 | } 79 | 80 | } 81 | 82 | %token_type {token &&} 83 | %type number_list{std::vector} 84 | %type string_list{std::vector} 85 | 86 | program ::= list. 87 | program ::= . 88 | 89 | list ::= any_list. 90 | list ::= list any_list. 91 | 92 | any_list ::= string_list(L). { 93 | printf("string list!\n"); 94 | for (const auto &s : L) 95 | printf("%s\n", s.c_str()); 96 | } 97 | 98 | any_list ::= number_list(L). { 99 | printf("number list!\n"); 100 | for (auto i : L) 101 | printf("%d\n", i); 102 | } 103 | 104 | 105 | number_list(L) ::= number_list(L) NUMBER(RHS). { 106 | L.push_back(RHS); 107 | //L.push_back(any_cast(RHS)); 108 | } 109 | 110 | number_list(L) ::= NUMBER(RHS). { 111 | L.push_back(RHS); 112 | //L.push_back(any_cast(RHS)); 113 | } 114 | 115 | 116 | string_list(L) ::= string_list(L) STRING(RHS). { 117 | L.emplace_back(std::move(RHS.stringValue)); 118 | //L.emplace_back(any_cast(std::move(RHS))); 119 | } 120 | string_list(L) ::= STRING(RHS). { 121 | L.emplace_back(std::move(RHS.stringValue)); 122 | //L.emplace_back(any_cast(std::move(RHS))); 123 | } 124 | -------------------------------------------------------------------------------- /test/lisp_main.ragel: -------------------------------------------------------------------------------- 1 | #include "lisp_main.h" 2 | #include "lisp.h" 3 | #include "lisp_cell.h" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | %%{ 11 | 12 | machine lexer; 13 | alphtype unsigned char; 14 | 15 | main := |* 16 | 17 | '\n' { 18 | //printf("Will accept: %s\n", pp->will_accept() ? "yes" : "no"); 19 | if (pp->will_accept()) { pp->parse(0); } 20 | }; 21 | # comment. 22 | '#' [^\n]* ; 23 | # escaped new-line. 24 | '\\' '\n' ; 25 | [ \t]+ ; 26 | 27 | '[' => { pp->parse(LBRACKET); }; 28 | ']' => { pp->parse(RBRACKET); }; 29 | '(' => { pp->parse(LPAREN); }; 30 | ')' => { pp->parse(RPAREN); }; 31 | '-' => { pp->parse(MINUS); }; 32 | '+' => { pp->parse(PLUS); }; 33 | '*' => { pp->parse(TIMES); }; 34 | '/' => { pp->parse(DIVIDE); }; 35 | '->' => {pp->parse(ARROW); }; 36 | ':' => {pp->parse(COLON); }; 37 | ';' => {pp->parse(SEMI); }; 38 | '.' => {pp->parse(DOT); }; 39 | ',' => {pp->parse(COMMA); }; 40 | '=' => {pp->parse(EQ); }; 41 | '<>' => {pp->parse(NE); }; 42 | '<' => {pp->parse(LT); }; 43 | '>' => {pp->parse(GT); }; 44 | '<=' => {pp->parse(LE); }; 45 | '>=' => {pp->parse(GE); }; 46 | 47 | [0-9]+ => { 48 | int i = std::accumulate(ts, te, 0, [](int x, unsigned char c){ 49 | return x * 10 + c - '0'; 50 | }); 51 | pp->parse(INTEGER, i); 52 | }; 53 | [A-Z][A-Za-z0-9_]* => { pp->parse(ATOM, std::string(ts, te)); }; 54 | [a-z][a-z0-9_]* => { pp->parse(SYMBOL, std::string(ts, te)); }; 55 | 56 | # ¬ 57 | # NOT SIGN 58 | # Unicode: U+00AC, UTF-8: C2 AC 59 | 0xc2 0xac => { pp->parse(NOT); }; 60 | 61 | # λ 62 | # GREEK SMALL LETTER LAMDA 63 | # Unicode: U+03BB, UTF-8: CE BB 64 | 0xce 0xbb => { pp->parse(LAMBDA); }; 65 | # ',\\' => {pp->parse(LAMBDA); }; 66 | 67 | # ∨ 68 | # LOGICAL OR 69 | # Unicode: U+2228, UTF-8: E2 88 A8 70 | 0xe2 0x88 0xa8 => { pp->parse(OR); }; 71 | 72 | # ∧ 73 | # LOGICAL AND 74 | # Unicode: U+2227, UTF-8: E2 88 A7 75 | 0xe2 0x88 0xa7 => { pp->parse(AND); }; 76 | 77 | # ⊻ 78 | # XOR 79 | # Unicode: U+22BB, UTF-8: E2 8A BB 80 | 0xe2 0x8a 0xbb => { pp->parse(XOR); }; 81 | 82 | # → 83 | # RIGHTWARDS ARROW 84 | # Unicode: U+2192, UTF-8: E2 86 92 85 | 0xe2 0x86 0x92 => { pp->parse(ARROW); }; 86 | 87 | *|; 88 | 89 | 90 | }%% 91 | 92 | 93 | %%write data; 94 | 95 | int main(int argc, char **argv) { 96 | 97 | 98 | 99 | auto pp = mexpr_parser::create(); 100 | 101 | if (argc == 2 && std::string("-g") == argv[1]) pp->trace(stderr, "-> "); 102 | 103 | lisp::initialize(10000); 104 | 105 | 106 | int cs, act; 107 | unsigned char *ts; 108 | unsigned char *te; 109 | %%write init; 110 | 111 | char *line = NULL; 112 | size_t line_cap = 0; 113 | 114 | for(;;) { 115 | unsigned char *p; 116 | unsigned char *pe; 117 | unsigned char *eof; 118 | 119 | ssize_t length; 120 | 121 | /* 122 | there isn't any need to copy buffers around between lines 123 | since the line ends with a newline or eof will be set. 124 | */ 125 | 126 | length = getline(&line, &line_cap, stdin); 127 | if (length < 0) break; 128 | 129 | p = (unsigned char *)line; 130 | pe = p + length; 131 | eof = nullptr; 132 | if (p[length-1] != '\n') eof = pe; 133 | 134 | %%write exec; 135 | if (cs == lexer_error) { 136 | printf("Lexer error\n"); 137 | break; 138 | } 139 | if (eof) break; 140 | } 141 | free(line); 142 | pp->parse(0); 143 | 144 | return 0; 145 | } 146 | -------------------------------------------------------------------------------- /test/expr.lemon: -------------------------------------------------------------------------------- 1 | 2 | %include { 3 | #include 4 | #include "expr.h" 5 | 6 | typedef std::unique_ptr node_ptr; 7 | 8 | struct node { 9 | node(node &&) = default; 10 | node(const node &) = delete; 11 | node() = default; 12 | 13 | virtual ~node() = default; 14 | virtual void print(int indent) = 0; 15 | }; 16 | 17 | 18 | 19 | struct binary_node : public node { 20 | char op; 21 | node_ptr left; 22 | node_ptr right; 23 | 24 | binary_node(binary_node &&) = default; 25 | binary_node(char o, node_ptr &&l, node_ptr &&r) : 26 | op(o), left(std::move(l)), right(std::move(r)) 27 | {} 28 | 29 | virtual void print(int indent); 30 | }; 31 | 32 | struct unary_node : public node { 33 | char op; 34 | node_ptr child; 35 | 36 | unary_node(unary_node &&) = default; 37 | unary_node(char o, node_ptr &&c) : 38 | op(o), child(std::move(c)) 39 | {} 40 | 41 | virtual void print(int indent); 42 | }; 43 | 44 | struct int_node : public node { 45 | int value; 46 | int_node(int_node &&) = default; 47 | int_node(int v) : value(v) {} 48 | 49 | virtual void print(int indent); 50 | }; 51 | 52 | void int_node::print(int indent) { 53 | printf("%d ", value); 54 | } 55 | 56 | void binary_node::print(int indent) { 57 | printf ("(%c ", op); 58 | left->print(indent + 2); 59 | right->print(indent + 2); 60 | printf(") "); 61 | } 62 | 63 | void unary_node::print(int indent) { 64 | printf("(%c ", op); 65 | child->print(indent + 2); 66 | printf(") "); 67 | } 68 | 69 | #define YYMALLOCARGTYPE size_t 70 | } 71 | 72 | %code { 73 | 74 | //void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)); 75 | //void ParseFree(void *p, void (*freeProc)(void*)); 76 | //void Parse(void *yyp,int yymajor, int yyminor); 77 | 78 | int main(int argc, char **argv) { 79 | 80 | void *p = ParseAlloc(malloc); 81 | for (int i = 1; i < argc; ++i) { 82 | const char *cp = argv[i]; 83 | char c; 84 | while ((c = *cp++)) { 85 | switch(c) { 86 | case '0': 87 | case '1': 88 | case '2': 89 | case '3': 90 | case '4': 91 | case '5': 92 | case '6': 93 | case '7': 94 | case '8': 95 | case '9': 96 | Parse(p, NUMBER, c-'0'); 97 | break; 98 | 99 | #undef __ 100 | #define __(k,v) case k: Parse(p,v,0); break; 101 | __('+', PLUS) 102 | __('-', MINUS) 103 | __('*', TIMES) 104 | __('/', DIVIDE) 105 | __('%', MOD) 106 | __('~', NOT) 107 | __('(', LPAREN) 108 | __(')', RPAREN) 109 | #undef __ 110 | default: 111 | break; 112 | } 113 | } 114 | } 115 | Parse(p, 0, 0); 116 | ParseFree(p, free); 117 | return 0; 118 | } 119 | 120 | } 121 | 122 | %left PLUS MINUS. 123 | %left TIMES DIVIDE MOD. 124 | %right NOT. 125 | 126 | %token_type {int} 127 | %type number {int} 128 | 129 | %default_type {node_ptr} 130 | 131 | program ::= expr(E). { 132 | 133 | E->print(0); 134 | printf("\n"); 135 | } 136 | 137 | expr(X) ::= unary(X). 138 | 139 | expr(LHS) ::= expr(A) PLUS expr(B). { 140 | LHS = std::make_unique('+', std::move(A), std::move(B)); 141 | } 142 | 143 | expr(LHS) ::= expr(A) MINUS expr(B). { 144 | LHS = std::make_unique('-', std::move(A), std::move(B)); 145 | } 146 | 147 | expr(LHS) ::= expr(A) TIMES expr(B). { 148 | LHS = std::make_unique('*', std::move(A), std::move(B)); 149 | } 150 | 151 | expr(LHS) ::= expr(A) DIVIDE expr(B). { 152 | LHS = std::make_unique('/', std::move(A), std::move(B)); 153 | } 154 | 155 | expr(LHS) ::= expr(A) MOD expr(B). { 156 | LHS = std::make_unique('%', std::move(A), std::move(B)); 157 | } 158 | 159 | unary(X) ::= term(X). 160 | 161 | unary(LHS) ::= PLUS term(RHS). [NOT] { 162 | LHS = std::move(RHS); 163 | } 164 | unary(LHS) ::= MINUS unary(RHS). [NOT] { 165 | LHS = std::make_unique('-', std::move(RHS)); 166 | } 167 | 168 | unary(LHS) ::= NOT unary(RHS). [NOT] { 169 | LHS = std::make_unique('~', std::move(RHS)); 170 | } 171 | 172 | term(LHS) ::= number(N). { 173 | LHS = std::make_unique(N); 174 | } 175 | 176 | term(LHS) ::= LPAREN expr(E) RPAREN. { 177 | LHS = std::move(E); 178 | } 179 | 180 | 181 | // this should really be performed via the lexer! 182 | number(N) ::= NUMBER(N). 183 | 184 | number(LHS) ::= number(NN) NUMBER(N). { 185 | LHS = NN * 10 + N; 186 | } 187 | -------------------------------------------------------------------------------- /test/intbasic.lemon: -------------------------------------------------------------------------------- 1 | /* integer basic */ 2 | /* http://www.applefritter.com/files/basicman.pdf */ 3 | 4 | %include{#include } 5 | %include{#include } 6 | %include{#include "intbasic_token.h"} 7 | 8 | %token_prefix tk 9 | %token_type {token &&} 10 | %default_type {void} 11 | 12 | %header { 13 | struct token; 14 | void Parse(void *, int, token &&); 15 | void *ParseAlloc( void * (*)(size_t) ); 16 | void ParseFree( void *, void (*)(void *) ); 17 | } 18 | 19 | %syntax_error { 20 | fprintf(stderr, "Syntax Error\n"); 21 | fprintf(stderr, "Major: %s (%d)\n", yyTokenName[yymajor], yymajor); 22 | fprintf(stderr, "Token: %d : %s\n", TOKEN.intValue, TOKEN.stringValue.c_str()); 23 | } 24 | 25 | %parse_failure { 26 | fprintf(stderr, "Parse Failure\n"); 27 | } 28 | 29 | %parse_accept { 30 | fprintf(stdout, "Parse Accept\n"); 31 | } 32 | 33 | %left EXP. 34 | %left MULT DIV MOD. 35 | %left PLUS MINUS. 36 | %left LT GT LE GE EQ NE. 37 | %left AND OR. 38 | 39 | // not a real token but I find it more pleasant 40 | %right RIGHT. 41 | 42 | %nonassoc ERROR. 43 | %wildcard ANY. 44 | 45 | program ::= lines EOF. 46 | program ::= EOF. 47 | 48 | lines ::= lines line. 49 | lines ::= line. 50 | 51 | line ::= INTEGER stmt_list EOL . 52 | line ::= INTEGER EOL . 53 | line ::= EOL . 54 | line ::= error EOL. 55 | 56 | stmt_list ::= stmt. 57 | stmt_list ::= stmt_list COLON stmt. 58 | 59 | // LET LET=5 LET X=5 60 | // PRINT=4 -- error. LET PRINT=4 -- ok. 61 | 62 | /* 63 | * %fallback works with LET x EQ expr. 64 | * it does not work with LET EQ expr, 65 | * so we need extra rules for keywords as variables. 66 | * 67 | * IF(1<2)=1 68 | * is legal but conflicts with 69 | * IF(1<2)THEN... 70 | */ 71 | 72 | //%fallback ID LET . 73 | //%token_class maybe_var LET|TAB. 74 | 75 | stmt ::= LET var EQ expr. 76 | stmt ::= var EQ expr. 77 | //stmt ::= maybe_var EQ expr. 78 | 79 | //maybe_var ::= IF opt_subscript. 80 | //maybe_var ::= THEN opt_subscript. 81 | //maybe_var ::= LET opt_subscript. 82 | 83 | //opt_subscript ::= . 84 | //opt_subscript ::= LPAREN expr RPAREN. 85 | 86 | stmt ::= IF expr THEN stmt. 87 | stmt ::= IF expr THEN INTEGER. 88 | 89 | %ifdef on_goto 90 | stmt ::= ON expr GOTO integer_list. 91 | stmt ::= ON expr GOSUB integer_list. 92 | %endif 93 | 94 | stmt ::= FOR ID EQ expr TO expr. 95 | stmt ::= FOR ID EQ expr TO expr STEP integer. 96 | 97 | stmt ::= END. 98 | stmt ::= RETURN. 99 | stmt ::= GOTO expr. 100 | stmt ::= GOSUB expr. 101 | stmt ::= POP. 102 | stmt ::= NEXT id_list. 103 | stmt ::= PRINT print_args. 104 | 105 | stmt ::= REM rem_args. 106 | 107 | 108 | stmt ::= TAB expr. 109 | stmt ::= VTAB expr. 110 | stmt ::= DIM dim_list. 111 | stmt ::= CALL expr. 112 | stmt ::= POKE expr COMMA expr. 113 | 114 | /* text/graphics stuff */ 115 | 116 | stmt ::= TEXT. 117 | stmt ::= GR. 118 | stmt ::= HLIN expr COMMA expr AT expr. 119 | stmt ::= VLIN expr COMMA expr AT expr. 120 | stmt ::= PLOT expr COMMA expr. 121 | 122 | stmt ::= INPUT STRING COMMA var_list. 123 | stmt ::= INPUT var_list. 124 | 125 | /* 126 | * leading COMMA/SEMI is not allowed, but multiple sep 127 | * or trailing are ok. 128 | */ 129 | 130 | %token_class comma_semi COMMA|SEMI. 131 | 132 | print_args ::= . 133 | print_args ::= print_args_list opt_sep_list. 134 | 135 | print_args_list ::= expr . 136 | print_args_list ::= print_args_list sep_list expr. 137 | 138 | opt_sep_list ::= . 139 | opt_sep_list ::= sep_list. 140 | 141 | sep_list ::= comma_semi . 142 | sep_list ::= sep_list comma_semi . 143 | 144 | rem_args ::= . 145 | rem_args ::= any_list . 146 | 147 | any_list ::= ANY . 148 | any_list ::= any_list ANY . 149 | 150 | 151 | 152 | %ifdef on_goto 153 | integer_list ::= INTEGER. 154 | integer_list ::= integer_list COMMA INTEGER. 155 | %endif 156 | 157 | integer ::= INTEGER. 158 | integer ::= MINUS INTEGER. 159 | integer ::= PLUS INTEGER. 160 | 161 | expr ::= unary. 162 | expr ::= expr AND expr. 163 | expr ::= expr OR expr. 164 | 165 | expr ::= expr LT expr. 166 | expr ::= expr GT expr. 167 | expr ::= expr LE expr. 168 | expr ::= expr GE expr. 169 | expr ::= expr EQ expr. 170 | expr ::= expr NE expr. 171 | 172 | expr ::= expr PLUS expr. 173 | expr ::= expr MINUS expr. 174 | 175 | expr ::= expr MULT expr. 176 | expr ::= expr DIV expr. 177 | expr ::= expr MOD expr. 178 | 179 | expr ::= expr EXP expr. 180 | 181 | unary ::= term. 182 | unary ::= MINUS unary. [RIGHT] 183 | unary ::= PLUS unary. [RIGHT] 184 | unary ::= NOT unary. [RIGHT] 185 | 186 | term ::= var. 187 | term ::= INTEGER. 188 | term ::= STRING. 189 | term ::= LPAREN expr RPAREN. 190 | 191 | // functions 192 | term ::= unary_function LPAREN expr RPAREN. 193 | term ::= binary_function LPAREN expr COMMA expr RPAREN. 194 | 195 | unary_function ::= ABS. 196 | unary_function ::= LEN. 197 | unary_function ::= SGN. 198 | unary_function ::= PDL. 199 | unary_function ::= RND. 200 | unary_function ::= PEEK. 201 | binary_function ::= SCRN. 202 | 203 | id_list ::= ID. 204 | id_list ::= id_list COMMA ID. 205 | 206 | var_list ::= var. 207 | var_list ::= var_list COMMA var. 208 | 209 | dim_list ::= var_sub. 210 | dim_list ::= dim_list COMMA var_sub. 211 | 212 | /* 213 | * id or id(...) id$(1,2) is ok, id(1,2) is not. 214 | */ 215 | var ::= ID. 216 | var ::= STRING_ID. 217 | var ::= var_sub. 218 | 219 | 220 | var_sub ::= ID LPAREN expr RPAREN. 221 | var_sub ::= STRING_ID LPAREN expr RPAREN. 222 | var_sub ::= STRING_ID LPAREN expr COMMA expr RPAREN. 223 | 224 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lemon-- 2 | 3 | An experimental fork of the 4 | [lemon parser generator](http://www.hwaci.com/sw/lemon/lemon.html) 5 | that hopes to be more compatible with c++11. Placement constructors and 6 | destructors are automatically generated, so you shouldn't need to deal with 7 | pointers as much (unless, of course, you want to!) 8 | 9 | 10 | ## contrived example 11 | 12 | 13 | ###lemon-- 14 | 15 | %token_type {std::any} // c++17 16 | %type number_list{std::vector} 17 | %type string_list{std::vector} 18 | // or use a std::shared_ptr or std::unique_ptr... 19 | 20 | program ::= list. 21 | 22 | list ::= number_list(L). { 23 | 24 | for (auto i : L) { 25 | printf("%d\n", i); 26 | } 27 | } 28 | 29 | list ::= string_list(L). { 30 | 31 | for (const auto &s : L) { 32 | printf("%s\n", s.c_str()); 33 | } 34 | } 35 | 36 | number_list(L) ::= NUMBER(N). { 37 | L.push_back(std::any_cast(N)); 38 | } 39 | 40 | number_list(L) ::= number_list(L) NUMBER(N). { 41 | L.push_back(std::any_cast(N)); 42 | } 43 | 44 | string_list(L) ::= STRING(S). { 45 | L.push_back(std::any_cast(S)); 46 | } 47 | 48 | string_list(L) ::= string_list(L) STRING(S). { 49 | L.push_back(std::any_cast(S)); 50 | } 51 | 52 | 53 | ###lemon 54 | 55 | %token_type {std::any *)} 56 | %token_destructor { delete $$ } 57 | 58 | %type number_list{std::vector *} 59 | %type string_list{std::vector *} 60 | %destructor number_list { delete $$ } 61 | %destructor string_list { delete $$ } 62 | 63 | program ::= list. 64 | 65 | list ::= number_list(L). { 66 | 67 | for (auto i : *L) { 68 | printf("%d\n", i); 69 | } 70 | delete L; 71 | } 72 | 73 | list ::= string_list(L). { 74 | 75 | for (const auto &s : *L) { 76 | printf("%s\n", s.c_str()); 77 | } 78 | delete L; 79 | } 80 | 81 | 82 | number_list(L) ::= NUMBER(N). { 83 | L = new std::vector(); 84 | L->push_back(std::any_cast(*N)); 85 | delete N; 86 | } 87 | 88 | number_list(L) ::= number_list(L) NUMBER(N). { 89 | L->push_back(std::any_cast(*N)); 90 | delete N; 91 | } 92 | 93 | string_list(L) ::= STRING(S). { 94 | L = new std::vector(); 95 | L->push_back(std::any_cast(*S)); 96 | delete S; 97 | } 98 | 99 | string_list(L) ::= string_list(L) STRING(S). { 100 | L->push_back(std::any_cast(*S)); 101 | delete S; 102 | } 103 | 104 | ### Notes 105 | 106 | I tried to make these examples fairly similar. Lemon-- automatically 107 | destructs all right-hand-side variables and automatically constructs the 108 | left-hand-side variable. Additionally, it uses placement constructors and 109 | destructors so you use non-POD data type instead of pointers. 110 | 111 | Standard lemon only calls the %destructor for right-hand-side terms that 112 | don't have an alias, hence the manual deletion above. 113 | 114 | 115 | ## Exceptions 116 | 117 | Don't do that. 118 | 119 | one(RHS) ::= two(A). { 120 | RHS = std::move(A); 121 | throw std::exception("oops"); 122 | } 123 | 124 | In the above code, `RHS`'s destructor will not be called and it will leak. 125 | `A` will remain on the parse stack in a valid but unspecified state. Thus 126 | trying to continue parsing may or may not work (additionally, there may be 127 | other parser internals that are out of sync.) The destructor leak is fixable 128 | but due to the other reasons, you'd be better off remaining unexceptional. 129 | 130 | 131 | ## Other enhancements 132 | 133 | There is a new `%header` declaration. This is a block of code that will be 134 | written, verbatim, into the generated header file. 135 | 136 | %header { 137 | void *ParseAlloc(void *(*mallocProc)(size_t)); 138 | void ParseFree(void *p, void (*freeProc)(void*)); 139 | void Parse(void *yyp, int yymajor, struct MyTokenType *yyminor); 140 | } 141 | 142 | 143 | # Object Oriented? 144 | 145 | `test/lisp` uses an experimental object-oriented approach. I find this 146 | works better in many cases. 147 | 148 | The inheritance hierarchy is: 149 | 150 | lemon_base : your_parser : yypParser 151 | 152 | `#define LEMON_BASE your_parser` in your header and use the `lempar.cxx` 153 | template. 154 | 155 | ##Changes: 156 | 157 | * `%extra_argument` is gone. Put anything you need in `your_parser` (`public` 158 | or `protected` so it's accessible). 159 | * `%syntax_error`, `%parse_failure`, `%parse_accept`, and `%stack_overflow` 160 | may still be used but can also be moved into your class. 161 | * `ParseAlloc` and `ParseFree` are gone. Use the normal constructors and 162 | destructors. 163 | 164 | `yypParser` is hidden in an anonymous namespace, so it can only 165 | be created via a `%code` block in your parse definition. The `lisp` example 166 | exposes it as such: 167 | 168 | %code { 169 | std::unique_ptr your_parser::create() { 170 | return std::make_unique(); 171 | } 172 | } 173 | 174 | `yypParser` inherits all your constructors so you can pass in any appropriate 175 | arguments. 176 | 177 | # other versions for your consideration 178 | 179 | Trying to make lemon work better with c++ is not a new idea, apparently. 180 | These are some other efforts. I have no knowledge of their suitability. 181 | 182 | * http://sourceforge.net/projects/lemonxx/ 183 | * http://sourceforge.net/projects/lemonpp/ 184 | -------------------------------------------------------------------------------- /test/intbasic_lexer.ragel: -------------------------------------------------------------------------------- 1 | %%{ 2 | machine intbasic; 3 | 4 | comment := |* 5 | [\r\n] => { fhold; fgoto main; }; 6 | any ; 7 | *|; 8 | 9 | main := |* 10 | 11 | ':' => { Parse(pp, tkCOLON, 0); t = 0; }; 12 | 13 | '<>' => { Parse(pp, tkNE, 0); t++; }; 14 | '#' => { Parse(pp, tkNE, 0); t++; }; 15 | '=' => { Parse(pp, tkEQ, 0); t++; }; 16 | '>' => { Parse(pp, tkGT, 0); t++; }; 17 | '<' => { Parse(pp, tkLT, 0); t++; }; 18 | '>=' => { Parse(pp, tkGE, 0); t++; }; 19 | '<=' => { Parse(pp, tkLE, 0); t++; }; 20 | '(' => { Parse(pp, tkLPAREN, 0); t++; }; 21 | ')' => { Parse(pp, tkRPAREN, 0); t++; }; 22 | '-' => { Parse(pp, tkMINUS, 0); t++; }; 23 | '+' => { Parse(pp, tkPLUS, 0); t++; }; 24 | '*' => { Parse(pp, tkMULT, 0); t++; }; 25 | '/' => { Parse(pp, tkDIV, 0); t++; }; 26 | '^' => { Parse(pp, tkEXP, 0); t++; }; 27 | ',' => { Parse(pp, tkCOMMA, 0); t++; }; 28 | ';' => { Parse(pp, tkSEMI, 0); t++; }; 29 | 30 | # reserved words. also pass text in case it's actually an ID. 31 | 32 | # 33 | # These are not actually reserved words, so they depend on context 34 | # and can't be 100% faithfully parsed by a two-part lexer/parser. 35 | # 36 | # Example: 37 | # 10 letprintx=5 :printx 38 | # is tokenized as 39 | # 10 let printx = 5 : print x 40 | # 41 | # even more fun is rem -- when used as a statement, the rest of the 42 | # line is ignored... but it could also be a variable. 43 | 44 | 45 | # operators 46 | /NOT/i => { Parse(pp, tkNOT, std::string(ts, te)); t++; }; 47 | /AND/i => { Parse(pp, tkAND, std::string(ts, te)); t++; }; 48 | /OR/i => { Parse(pp, tkOR, std::string(ts, te)); t++; }; 49 | /MOD/i => { Parse(pp, tkMOD, std::string(ts, te)); t++; }; 50 | 51 | # keywords 52 | /LET/i => { Parse(pp, tkLET, std::string(ts, te)); t++; }; 53 | /INPUT/i => { Parse(pp, tkINPUT, std::string(ts, te)); t++; }; 54 | /PRINT/i => { Parse(pp, tkPRINT, std::string(ts, te)); t++; }; 55 | /TAB/i => { Parse(pp, tkTAB, std::string(ts, te)); t++; }; 56 | /VTAB/i => { Parse(pp, tkVTAB, std::string(ts, te)); t++; }; 57 | /FOR/i => { Parse(pp, tkFOR, std::string(ts, te)); t++; }; 58 | /TO/i => { Parse(pp, tkTO, std::string(ts, te)); t++; }; 59 | /STEP/i => { Parse(pp, tkSTEP, std::string(ts, te)); t++; }; 60 | /NEXT/i => { Parse(pp, tkNEXT, std::string(ts, te)); t++; }; 61 | /IF/i => { Parse(pp, tkIF, std::string(ts, te)); t++; }; 62 | /THEN/i => { Parse(pp, tkTHEN, std::string(ts, te)); t++; }; 63 | /GOTO/i => { Parse(pp, tkGOTO, std::string(ts, te)); t++; }; 64 | /GOSUB/i => { Parse(pp, tkGOSUB, std::string(ts, te)); t++; }; 65 | /RETURN/i => { Parse(pp, tkRETURN, std::string(ts, te)); t++; }; 66 | /DIM/i => { Parse(pp, tkDIM, std::string(ts, te)); t++; }; 67 | /END/i => { Parse(pp, tkEND, std::string(ts, te)); t++; }; 68 | /POKE/i => { Parse(pp, tkPOKE, std::string(ts, te)); t++; }; 69 | /CALL/i => { Parse(pp, tkCALL, std::string(ts, te)); t++; }; 70 | /TEXT/i => { Parse(pp, tkTEXT, std::string(ts, te)); t++; }; 71 | /AT/i => { Parse(pp, tkAT, std::string(ts, te)); t++; }; 72 | /GR/i => { Parse(pp, tkGR, std::string(ts, te)); t++; }; 73 | /HLIN/i => { Parse(pp, tkHLIN, std::string(ts, te)); t++; }; 74 | /VLIN/i => { Parse(pp, tkVLIN, std::string(ts, te)); t++; }; 75 | /PLOT/i => { Parse(pp, tkPLOT, std::string(ts, te)); t++; }; 76 | 77 | 78 | /REM/i => { 79 | Parse(pp, tkREM, std::string(ts, te)); 80 | t++; 81 | fgoto comment; 82 | }; 83 | 84 | # functions 85 | /ABS/i => { Parse(pp, tkABS, std::string(ts, te)); t++; }; 86 | /SGN/i => { Parse(pp, tkSGN, std::string(ts, te)); t++; }; 87 | /PEEK/i => { Parse(pp, tkPEEK, std::string(ts, te)); t++; }; 88 | /RND/i => { Parse(pp, tkRND, std::string(ts, te)); t++; }; 89 | /LEN/i => { Parse(pp, tkLEN, std::string(ts, te)); t++; }; 90 | /SCRN/i => { Parse(pp, tkSCRN, std::string(ts, te)); t++; }; 91 | 92 | # strings. 93 | ["] [^"\r\n]* ["] => { 94 | Parse(pp, tkSTRING, std::string(ts + 1, te - 1)); 95 | t++; 96 | }; 97 | 98 | 99 | # variables 100 | 101 | [A-Za-z][A-Za-z0-9]* '$' { 102 | Parse(pp, tkSTRING_ID, std::string(ts, te)); 103 | t++; 104 | }; 105 | 106 | 107 | [A-Za-z][A-Za-z0-9]* { 108 | Parse(pp, tkID, std::string(ts, te)); 109 | t++; 110 | }; 111 | 112 | [0-9]+ { 113 | unsigned value = std::accumulate(ts, te, 0, [](int x, char c){ 114 | return x * 10 + c - '0'; 115 | }); 116 | Parse(pp, tkINTEGER, value); 117 | t++; 118 | }; 119 | 120 | 121 | # skip ws. 122 | [ \t]+ ; 123 | 124 | [\r\n] => { Parse(pp, tkEOL, 0); line++; t = 0; }; 125 | 126 | # may be part of a REM statement. 127 | #[^\r\n] => { Parse(pp, tkERROR, std::string(ts, te)); }; 128 | 129 | *|; 130 | }%% 131 | 132 | #include 133 | #include 134 | #include 135 | #include 136 | #include 137 | 138 | #include "intbasic_token.h" 139 | #include "intbasic.h" 140 | 141 | void Parse(void *p, int type) { 142 | Parse(p, type, token(0)) ; 143 | } 144 | 145 | void Parse(void *p, int type, int value) { 146 | Parse(p, type, token(value)); 147 | } 148 | 149 | void Parse(void *p, int type, std::string &&s) { 150 | Parse(p, type, token(std::move(s))); 151 | } 152 | 153 | void ParseTrace(FILE *TraceFILE, char *zTracePrompt); 154 | 155 | int main(int argc, char **argv) { 156 | 157 | int line = 1; 158 | %%write data; 159 | 160 | void *pp = ParseAlloc(malloc); 161 | if (argc == 2 && argv[1] == std::string("-g")) 162 | ParseTrace(stderr, (char *)"-->"); 163 | 164 | 165 | 166 | char buffer[2048]; 167 | 168 | 169 | char *ts = buffer; 170 | char *te = buffer; 171 | char *eof = nullptr; 172 | int offset = 0; 173 | int act; 174 | int cs; 175 | 176 | %%write init; 177 | 178 | int t = 0; 179 | for(;;) { 180 | ssize_t size; 181 | 182 | int space = sizeof(buffer) - offset; 183 | if (!space) { 184 | fprintf(stderr, "Lexer error: Token too big\n"); 185 | break; 186 | } 187 | 188 | size = read(0, buffer + offset, space); 189 | if (size <0) { 190 | perror("read"); 191 | break; 192 | } 193 | 194 | char *p = buffer + offset; 195 | char *pe = buffer + offset + size; 196 | 197 | if (size == 0) { 198 | // eof. 199 | // make sure there's an eol. 200 | *pe++ = '\n'; 201 | eof = pe; 202 | } 203 | 204 | 205 | %%write exec; 206 | 207 | if (cs == intbasic_error) { 208 | fprintf(stderr, "Lexer error on line %d\n", line); 209 | } 210 | if (size == 0) break; // eof. 211 | 212 | if (ts == 0) { 213 | offset = 0; 214 | } else { 215 | // shift around an in-progress token. 216 | offset = pe - ts; 217 | memmove(buffer, ts, offset); 218 | te = buffer + (te-ts); 219 | ts = buffer; 220 | } 221 | 222 | } 223 | 224 | Parse(pp, tkEOF, 0); 225 | Parse(pp, 0, 0); 226 | ParseFree(pp, free); 227 | return 0; 228 | } -------------------------------------------------------------------------------- /test/lisp.lemon: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | * LISP, as John McCarthy intended it. Before the parenthesis took over. 5 | * (IE - M-Expressions) 6 | * 7 | * http://www-formal.stanford.edu/jmc/recursive.pdf 8 | * 9 | * To prevent ambiguity and conflicts, assignment uses : instead of = 10 | */ 11 | 12 | %include{ 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "lisp_main.h" 19 | #include "lisp_cell.h" 20 | #include "lisp.h" 21 | 22 | #define LEMON_SUPER mexpr_parser 23 | //#define YYSTACKDEPTH 0 24 | } 25 | // use dynamic stack (for testing purposes.) 26 | %stack_size 0 27 | 28 | %syntax_error { 29 | 30 | printf("Syntax Error! Suggested tokens:\n"); 31 | const YYACTIONTYPE stateno = yytos->stateno; 32 | for (unsigned i = 0; i < YYNTOKEN; ++i) { 33 | int yyact = yy_find_shift_action(i, stateno); 34 | if (yyact != YY_ERROR_ACTION && yyact != YY_NO_ACTION) { 35 | printf(" %s\n", yyTokenName[i]); 36 | } 37 | } 38 | 39 | } 40 | 41 | %code{ 42 | std::unique_ptr mexpr_parser::create() { 43 | return std::make_unique(); 44 | } 45 | 46 | 47 | // no longer used since will_accept() does it better. 48 | bool mexpr_parser::continuation() const { 49 | yypParser *self = (yypParser *)this; 50 | int depth[2] = { 0, 0 }; 51 | for (const auto &e : *self) { 52 | switch(e.major) { 53 | case LPAREN: 54 | depth[0]++; 55 | break; 56 | case RPAREN: 57 | depth[0]--; 58 | break; 59 | case LBRACKET: 60 | depth[1]++; 61 | break; 62 | case RBRACKET: 63 | depth[1]--; 64 | break; 65 | } 66 | } 67 | return depth[0] || depth[1]; 68 | } 69 | 70 | } 71 | 72 | %token_type {Token} 73 | %default_type {lisp::cell_ptr} 74 | 75 | %left AND OR XOR. 76 | %left EQ NE LT GT LE GE. 77 | %left PLUS MINUS. 78 | %left TIMES DIVIDE. 79 | %right NOT. 80 | 81 | program ::= . 82 | program ::= error. { 83 | error++; 84 | } 85 | program ::= statement(E). { 86 | 87 | if (!error) { 88 | printf("%s\n", E ? E->to_string().c_str() : "#"); 89 | } 90 | lisp::clear_temp_list(); 91 | error = 0; 92 | } 93 | 94 | /* this is here so errors don't pop back to a parse failure */ 95 | /* currently generates a shift-reduce instead of a shift and has problems... */ 96 | /* 97 | statement ::= error. { 98 | error++; 99 | } 100 | */ 101 | statement(X) ::= variable_assignment(X). 102 | 103 | statement(X) ::= function_assignment(X). 104 | 105 | statement(RV) ::= expression(E). { 106 | try { 107 | auto tmp = E->substitute(lisp::env); 108 | tmp = tmp->evaluate(); 109 | RV = tmp; 110 | } 111 | catch(std::exception &e) { 112 | fprintf(stderr, "%s\n", e.what()); 113 | error++; 114 | } 115 | } 116 | 117 | 118 | // these should also add to the table. 119 | variable_assignment(RV) ::= SYMBOL(S) COLON expression(E) . { 120 | 121 | try { 122 | auto tmp = E->substitute(lisp::env); 123 | tmp = tmp->evaluate(); 124 | auto label = lisp::make_symbol(S.stringValue); 125 | if (!error) lisp::env[label] = tmp; 126 | RV = tmp; 127 | } 128 | catch(std::exception &e) { 129 | fprintf(stderr, "%s\n", e.what()); 130 | error++; 131 | } 132 | } 133 | 134 | // function call vs function definition has conflicts unless they use the same argument list. 135 | // need to verify args are actually SYMBOLS and not arbitrary expressions later. 136 | 137 | function_assignment(RV) ::= SYMBOL(S) function_call(F) COLON expression(E). { 138 | 139 | try { 140 | 141 | std::vector parameters; 142 | 143 | std::transform(F.begin(), F.end(), std::back_inserter(parameters), 144 | [](lisp::cell_ptr cell){ return cell->to_symbol(); } 145 | ); 146 | 147 | auto label = lisp::make_symbol(S.stringValue); 148 | auto tmp = lisp::make_lambda(label, std::move(parameters), E); 149 | 150 | tmp = tmp->substitute(lisp::env); 151 | 152 | if (!error) lisp::env[label] = tmp; 153 | RV = tmp; 154 | } 155 | catch(std::exception &e) { 156 | fprintf(stderr, "%s\n", e.what()); 157 | error++; 158 | } 159 | 160 | } 161 | 162 | 163 | 164 | 165 | 166 | /* ,\[[a;b;c]; a+b+c] */ 167 | lambda(RV) ::= LAMBDA LBRACKET function_call(F) SEMI expression(E) RBRACKET. { 168 | 169 | try { 170 | 171 | std::vector parameters; 172 | 173 | std::transform(F.begin(), F.end(), std::back_inserter(parameters), 174 | [](lisp::cell_ptr cell){ return cell->to_symbol(); } 175 | ); 176 | 177 | RV = lisp::make_lambda(nullptr, std::move(parameters), E); 178 | } 179 | catch(std::exception &e) { 180 | fprintf(stderr, "%s\n", e.what()); 181 | error++; 182 | } 183 | } 184 | 185 | function(RV) ::= SYMBOL(S) function_call(ARGS). 186 | { RV = lisp::make_function(lisp::make_symbol(S.stringValue), std::move(ARGS)); } 187 | 188 | function(RV) ::= lambda(F) function_call(ARGS). 189 | { RV = lisp::make_function(F, std::move(ARGS)); } 190 | 191 | function(RV) ::= function(F) function_call(ARGS). 192 | { RV = lisp::make_function(F, std::move(ARGS)); } 193 | 194 | 195 | %token_class mul_op TIMES DIVIDE. 196 | %token_class add_op PLUS MINUS. 197 | %token_class logical_op AND OR XOR. 198 | %token_class compare_op EQ NE LT GT GE LE. 199 | 200 | expression(RV) ::= expression(L) logical_op(OP) expression(R). 201 | { RV = lisp::make_binary(@OP, L, R); } 202 | 203 | 204 | expression(RV) ::= expression(L) compare_op(OP) expression(R). 205 | { RV = lisp::make_binary(@OP, L, R); } 206 | 207 | expression(RV) ::= expression(L) add_op(OP) expression(R). 208 | { RV = lisp::make_binary(@OP, L, R); } 209 | 210 | expression(RV) ::= expression(L) mul_op(OP) expression(R). 211 | { RV = lisp::make_binary(@OP, L, R); } 212 | 213 | expression(RV) ::= NOT(OP) expression(E). 214 | { RV = lisp::make_unary(@OP, E); } 215 | 216 | expression(RV) ::= PLUS(OP) expression(E). [NOT] 217 | { RV = lisp::make_unary(@OP, E); } 218 | 219 | expression(RV) ::= MINUS(OP) expression(E). [NOT] 220 | { RV = lisp::make_unary(@OP, E); } 221 | 222 | expression(X) ::= term(X). 223 | expression(X) ::= conditional(X). 224 | expression(X) ::= list(X). 225 | 226 | term(RV) ::= INTEGER(I). { RV = lisp::make_integer(I.intValue); } 227 | term(RV) ::= ATOM(A). { RV = lisp::make_atom(A.stringValue); } 228 | term(RV) ::= SYMBOL(S). { RV = lisp::make_symbol(S.stringValue); } 229 | term(X) ::= lambda(X) . 230 | term(X) ::= function(X) . 231 | 232 | 233 | 234 | %type conditional_list {std::vector } 235 | %type condition {std::vector } 236 | 237 | 238 | conditional(RV) ::= LBRACKET conditional_list(L) RBRACKET. 239 | { RV = lisp::make_conditional(std::move(L)); } 240 | 241 | conditional_list(C) ::= condition(C). 242 | 243 | conditional_list(L) ::= conditional_list(L) SEMI condition(C). { 244 | L.insert(L.end(), C.begin(), C.end()); 245 | } 246 | 247 | condition(RV) ::= expression(P) ARROW expression(E). { 248 | RV = { P, E }; 249 | } 250 | 251 | /* lists: (), ( A . B) or (A, B, C) (A , B . C) */ 252 | 253 | list(RV) ::= LPAREN RPAREN. { RV = lisp::make_pair(nullptr, nullptr); /* ?? */ } 254 | 255 | list(RV) ::= LPAREN expression_list(L) RPAREN. { 256 | 257 | RV = std::accumulate(L.rbegin(), L.rend(), lisp::cell_ptr(nullptr), [](lisp::cell_ptr cdr, lisp::cell_ptr car){ 258 | return lisp::make_pair(car, cdr); 259 | }); 260 | } 261 | 262 | list(RV) ::= LPAREN expression_list(L) DOT expression(E) RPAREN. { 263 | 264 | RV = std::accumulate(L.rbegin(), L.rend(), E, [](lisp::cell_ptr cdr, lisp::cell_ptr car){ 265 | return lisp::make_pair(car, cdr); 266 | }); 267 | } 268 | 269 | list(RV) ::= LPAREN error RPAREN. { 270 | fprintf(stderr, "Error parsing list.\n"); 271 | RV = lisp::make_pair(nullptr, nullptr); 272 | } 273 | 274 | 275 | %type expression_list {std::vector } 276 | 277 | expression_list(L) ::= expression(E) . 278 | { L.push_back(E); } 279 | 280 | expression_list(L) ::= expression_list(L) COMMA expression(E) . 281 | { L.push_back(E); } 282 | 283 | // parameter list, for function call or function definition. 284 | 285 | %type function_call {std::vector } 286 | %type opt_arg_list {std::vector } 287 | %type arg_list {std::vector } 288 | 289 | function_call(RV) ::= LBRACKET opt_arg_list(X) RBRACKET. 290 | { RV = std::move(X); } 291 | 292 | function_call ::= LBRACKET error RBRACKET. { 293 | fprintf(stderr, "Error parsing function parameters/arguments.\n"); 294 | } 295 | 296 | opt_arg_list ::= . 297 | 298 | opt_arg_list(L) ::= arg_list(L). 299 | 300 | arg_list(L) ::= expression(E). { L.push_back(E); } 301 | arg_list(L) ::= arg_list(L) SEMI expression(E). { L.push_back(E); } 302 | 303 | -------------------------------------------------------------------------------- /test/lisp_cell.h: -------------------------------------------------------------------------------- 1 | #ifndef __lisp_cell_h__ 2 | #define __lisp_cell_h__ 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace lisp { 11 | 12 | typedef class cell * cell_ptr; 13 | typedef class symbol_cell * symbol_cell_ptr; 14 | typedef std::vector hideset; 15 | 16 | typedef std::unordered_map environment; 17 | 18 | extern environment env; 19 | 20 | void initialize(std::size_t); 21 | void clear_temp_list(); 22 | 23 | class cell { 24 | public: 25 | enum type { 26 | undefined, 27 | atom, 28 | symbol, 29 | integer, 30 | builtin, 31 | lambda, 32 | function, // call a function. 33 | pair, 34 | unary, 35 | binary, 36 | conditional, 37 | }; 38 | 39 | 40 | 41 | static void *operator new(std::size_t); 42 | static void operator delete(void *); 43 | 44 | 45 | 46 | cell_ptr substitute(const environment &e) { 47 | hideset hs; 48 | return substitute(hs, e); 49 | } 50 | 51 | cell_ptr evaluate() { 52 | environment e; 53 | return evaluate(e); 54 | } 55 | 56 | virtual std::string to_string() const; 57 | virtual cell_ptr substitute(hideset &hs, const environment &) { return this; } 58 | virtual cell_ptr evaluate(const environment &) { return this; } 59 | virtual cell_ptr label(symbol_cell_ptr) { return this; } 60 | 61 | virtual int to_int() const; 62 | virtual bool to_bool() const; 63 | virtual symbol_cell_ptr to_symbol(); 64 | virtual cell_ptr to_atom(); 65 | virtual std::pair to_pair() const; 66 | 67 | //virtual bool to_bool() const; 68 | 69 | 70 | template 71 | bool is() const { return type == T; } 72 | 73 | protected: 74 | cell(type t) : type(t) 75 | {}; 76 | virtual ~cell() 77 | {} 78 | 79 | friend class unary_cell; 80 | friend class binary_cell; 81 | friend class lambda_cell; 82 | friend class pair_cell; 83 | friend class conditional_cell; 84 | friend class function_cell; 85 | virtual void mark() { alive = true; } 86 | 87 | private: 88 | bool alive = true; 89 | type type = undefined; 90 | 91 | friend void garbage_collect(); 92 | 93 | }; 94 | 95 | 96 | class atom_cell : public cell { 97 | 98 | public: 99 | 100 | atom_cell(const std::string &s) : cell(cell::atom), value(s) 101 | { } 102 | 103 | virtual std::string to_string() const override final; 104 | virtual cell_ptr to_atom() override final; 105 | virtual bool to_bool() const override final; 106 | 107 | private: 108 | std::string value; 109 | }; 110 | 111 | 112 | class symbol_cell : public cell { 113 | 114 | public: 115 | 116 | symbol_cell(const std::string &s) : cell(cell::symbol), value(s) 117 | {} 118 | 119 | virtual std::string to_string() const override final; 120 | virtual cell_ptr substitute(hideset &hs, const environment &e) override final; 121 | virtual cell_ptr evaluate(const environment &e) override final; 122 | 123 | virtual symbol_cell_ptr to_symbol() override final; 124 | 125 | private: 126 | std::string value; 127 | }; 128 | 129 | 130 | class integer_cell : public cell { 131 | 132 | public: 133 | 134 | integer_cell(int i = 0) : cell(cell::integer), value(i) 135 | {} 136 | 137 | virtual std::string to_string() const override final; 138 | virtual int to_int() const override final; 139 | 140 | private: 141 | int value; 142 | 143 | }; 144 | 145 | class pair_cell : public cell { 146 | 147 | public: 148 | 149 | pair_cell(cell_ptr a, cell_ptr b) : cell(cell::pair), car(a), cdr(b) 150 | {} 151 | 152 | virtual std::string to_string() const override final; 153 | virtual cell_ptr substitute(hideset &hs, const environment &e) override final; 154 | virtual cell_ptr evaluate(const environment &e) override final; 155 | 156 | virtual int to_int() const override final; 157 | virtual bool to_bool() const override final; 158 | virtual cell_ptr to_atom() override final; 159 | 160 | virtual std::pair to_pair() const override final; 161 | protected: 162 | virtual void mark() override final; 163 | 164 | 165 | private: 166 | cell_ptr car; 167 | cell_ptr cdr; 168 | }; 169 | 170 | class unary_cell : public cell { 171 | public: 172 | unary_cell(int op, cell_ptr rhs) : cell(cell::unary), op(op), car(rhs) 173 | {} 174 | 175 | virtual cell_ptr substitute(hideset &hs, const environment &e) override final; 176 | virtual cell_ptr evaluate(const environment &e) override final; 177 | 178 | protected: 179 | virtual void mark() override final; 180 | 181 | private: 182 | int op; 183 | cell_ptr car; 184 | }; 185 | 186 | class binary_cell : public cell { 187 | public: 188 | binary_cell(int op, cell_ptr lhs, cell_ptr rhs) : cell(cell::binary), op(op), car(lhs), cdr(rhs) 189 | {} 190 | 191 | virtual cell_ptr substitute(hideset &hs, const environment &e) override final; 192 | virtual cell_ptr evaluate(const environment &e) override final; 193 | 194 | protected: 195 | virtual void mark() override final; 196 | 197 | private: 198 | int op; 199 | cell_ptr car; 200 | cell_ptr cdr; 201 | }; 202 | 203 | 204 | class conditional_cell : public cell { 205 | public: 206 | conditional_cell(std::vector &&pe) : cell(cell::conditional), pe(std::move(pe)) 207 | {} 208 | 209 | virtual cell_ptr substitute(hideset &hs, const environment &e) override final; 210 | virtual cell_ptr evaluate(const environment &e) override final; 211 | 212 | protected: 213 | virtual void mark() override final; 214 | 215 | private: 216 | std::vector pe; 217 | 218 | }; 219 | 220 | class lambda_cell : public cell { 221 | 222 | public: 223 | lambda_cell(symbol_cell_ptr name, std::vector &¶meters, cell_ptr body) 224 | : cell(cell::lambda), 225 | name(name), 226 | parameters(std::move(parameters)), 227 | body(body) 228 | {} 229 | 230 | lambda_cell(symbol_cell_ptr name, const std::vector ¶meters, cell_ptr body) 231 | : cell(cell::lambda), 232 | name(name), 233 | parameters(std::move(parameters)), 234 | body(body) 235 | {} 236 | 237 | virtual std::string to_string() const override final; 238 | virtual cell_ptr substitute(hideset &hs, const environment &e) override final; 239 | virtual cell_ptr evaluate(const environment &e) override final; 240 | virtual cell_ptr label(symbol_cell_ptr) override final; 241 | 242 | protected: 243 | virtual void mark() override final; 244 | 245 | protected: 246 | 247 | cell_ptr call(const std::vector &args); 248 | 249 | private: 250 | 251 | friend class function_cell; 252 | 253 | std::vector parameters; 254 | symbol_cell_ptr name; 255 | cell_ptr body; 256 | 257 | }; 258 | 259 | class builtin_cell : public cell { 260 | public: 261 | typedef cell_ptr (*function_proto)(const std::vector &, const environment &e); 262 | 263 | builtin_cell(std::string name, int arity, function_proto function) : 264 | cell(cell::builtin), name(name), arity(arity), function(function) 265 | {} 266 | 267 | virtual std::string to_string() const override final; 268 | 269 | protected: 270 | cell_ptr call(const std::vector &args, const environment &e); 271 | 272 | private: 273 | friend class function_cell; 274 | 275 | std::string name; 276 | int arity; 277 | function_proto function; 278 | }; 279 | 280 | class function_cell : public cell { 281 | 282 | public: 283 | function_cell(cell_ptr function, std::vector &&arguments) : 284 | cell(cell::function), 285 | function(function), 286 | arguments(std::move(arguments)) 287 | {} 288 | 289 | virtual cell_ptr substitute(hideset &hs, const environment &e) override final; 290 | virtual cell_ptr evaluate(const environment &e) override final; 291 | 292 | protected: 293 | virtual void mark() override final; 294 | 295 | private: 296 | cell_ptr function; // lambda or built-in 297 | std::vector arguments; 298 | }; 299 | 300 | 301 | 302 | 303 | cell_ptr make_pair(cell_ptr a, cell_ptr b); 304 | cell_ptr make_atom(const std::string &s); 305 | symbol_cell_ptr make_symbol(const std::string &s); 306 | cell_ptr make_integer(int i); 307 | cell_ptr make_unary(int op, cell_ptr rhs); 308 | cell_ptr make_binary(int op, cell_ptr lhs, cell_ptr rhs); 309 | cell_ptr make_conditional(std::vector &&pe); 310 | cell_ptr make_lambda(symbol_cell_ptr label, std::vector &¶meters, cell_ptr body); 311 | cell_ptr make_lambda(symbol_cell_ptr label, const std::vector ¶meters, cell_ptr body); 312 | cell_ptr make_function(cell_ptr function, std::vector &¶meters); 313 | 314 | 315 | } // namespace 316 | 317 | #endif 318 | -------------------------------------------------------------------------------- /test/lisp_cell.cpp: -------------------------------------------------------------------------------- 1 | #include "lisp_cell.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "lisp.h" 9 | 10 | namespace lisp { 11 | 12 | environment env; 13 | 14 | namespace { 15 | 16 | typedef typename std::aligned_union<1, 17 | cell, atom_cell, symbol_cell, integer_cell, pair_cell, 18 | unary_cell, binary_cell, conditional_cell, lambda_cell, builtin_cell, 19 | function_cell 20 | >::type chunk; 21 | 22 | 23 | 24 | cell_ptr kTRUE = nullptr; 25 | cell_ptr kFALSE = nullptr; 26 | cell_ptr kUNDEFINED = nullptr; 27 | cell_ptr kNIL = nullptr; 28 | 29 | inline cell_ptr null_to_nil(cell_ptr c) { return c == nullptr ? c : kNIL; } 30 | inline cell_ptr nil_to_null(cell_ptr c) { return c == kNIL ? nullptr : c; } 31 | 32 | 33 | std::vector temp_list; 34 | static std::vector free_list; 35 | static std::vector storage; 36 | 37 | 38 | template 39 | T *temp(T *t) { temp_list.push_back(t); return t; } 40 | 41 | std::array numbers; 42 | 43 | 44 | void arity_error(const std::string &s) { 45 | throw std::runtime_error(s); 46 | } 47 | 48 | 49 | 50 | 51 | cell_ptr builtin_eq(const std::vector &argv, const environment &e) { 52 | if (argv.size() != 2) arity_error("function arity error: eq requires two parameters."); 53 | 54 | auto a = argv[0] ? argv[0]->evaluate(e) : nullptr; 55 | auto b = argv[1] ? argv[1]->evaluate(e) : nullptr; 56 | 57 | return a == b ? kTRUE : kFALSE; 58 | } 59 | 60 | cell_ptr builtin_car(const std::vector &argv, const environment &e) { 61 | if (argv.size() != 1) arity_error("function arity error: car requires one parameter."); 62 | 63 | auto tmp = argv[0] ? argv[0]->evaluate(e) : nullptr; 64 | if (!tmp) return tmp; 65 | auto p = tmp->to_pair(); 66 | 67 | return p.first; 68 | } 69 | 70 | cell_ptr builtin_cdr(const std::vector &argv, const environment &e) { 71 | if (argv.size() != 1) arity_error("function arity error: cdr requires one parameter."); 72 | 73 | auto tmp = argv[0] ? argv[0]->evaluate(e) : nullptr; 74 | if (!tmp) return tmp; 75 | auto p = tmp->to_pair(); 76 | 77 | return p.second; 78 | } 79 | 80 | cell_ptr builtin_atom(const std::vector &argv, const environment &e) { 81 | 82 | if (argv.size() != 1) arity_error("function arity error: atom requires one parameter."); 83 | 84 | auto tmp = argv[0] ? argv[0]->evaluate(e) : nullptr; 85 | if (!tmp) return tmp; 86 | 87 | return tmp->is() ? kTRUE : kFALSE; 88 | } 89 | 90 | cell_ptr builtin_cons(const std::vector &argv, const environment &e) { 91 | if (argv.size() != 2) arity_error("function arity error: cons requires two parameters."); 92 | 93 | auto a = argv[0] ? argv[0]->evaluate(e) : nullptr; 94 | auto b = argv[1] ? argv[1]->evaluate(e) : nullptr; 95 | 96 | return make_pair(a, b); 97 | } 98 | 99 | cell_ptr builtin_label(const std::vector &argv, const environment &e) { 100 | if (argv.size() != 2) arity_error("function arity error: label requires two parameters."); 101 | 102 | auto label = argv[0] ? argv[0]->to_symbol() : nullptr; 103 | auto f = argv[1] ? argv[1]->evaluate(e) : nullptr; 104 | return f ? f->label(label) : nullptr; 105 | } 106 | 107 | cell_ptr builtin_list(const std::vector &argv, const environment &e) { 108 | return std::accumulate(argv.rbegin(), argv.rend(), (cell_ptr)nullptr, 109 | [&](cell_ptr cdr, cell_ptr car){ 110 | car = car->evaluate(e); 111 | return make_pair(car, cdr); 112 | }); 113 | } 114 | 115 | cell_ptr builtin_help(const std::vector &argv, const environment &e) { 116 | fputs( 117 | "LISP HELP\n" 118 | "builtin functions: atom, car, cdr, cons, eq, help, label, list\n" 119 | "terminals: ATOM, symbol, number\n" 120 | "assignment: symbol : expression\n" 121 | "lists: (), (expression [, expression]* ), (expression [, expression]* . expression)\n" 122 | "conditional: [expression → expression [; expression → expression]*]\n" 123 | "function calls: symbol[arguments?]\n" 124 | "arguments: expression [; expression]*\n" 125 | "lambda: λ[[parameters?] ; expression]\n" 126 | "function assignment: symbol[parameters?] : expression\n" 127 | "parameters: symbol [; symbol]*\n" 128 | "operators: + - * / = <> > >= < <= ¬ ∨ ∧ ⊻\n", 129 | 130 | stdout 131 | ); 132 | 133 | return nullptr; 134 | } 135 | 136 | 137 | builtin_cell builtin_eq_cell("eq", 2, builtin_eq); 138 | builtin_cell builtin_atom_cell("atom", 1, builtin_atom); 139 | builtin_cell builtin_cons_cell("cons", 2, builtin_cons); 140 | builtin_cell builtin_car_cell("car", 1, builtin_car); 141 | builtin_cell builtin_cdr_cell("cdr", 1, builtin_cdr); 142 | builtin_cell builtin_label_cell("label", 2, builtin_label); 143 | builtin_cell builtin_list_cell("list", 0, builtin_list); 144 | builtin_cell builtin_help_cell("help", 0, builtin_help); 145 | 146 | std::unordered_map atom_map; 147 | std::unordered_map symbol_map; 148 | }; 149 | 150 | 151 | 152 | void clear_temp_list() { temp_list.clear(); } 153 | 154 | void initialize(std::size_t size) { 155 | 156 | size = std::min(size, (std::size_t)100); 157 | 158 | free_list.reserve(size); 159 | 160 | storage.reserve(size); 161 | storage.resize(size); 162 | std::transform(storage.begin(), storage.end(), std::back_inserter(free_list), 163 | [](chunk &x) { return &x; }); 164 | 165 | 166 | env.emplace(make_symbol("eq"), &builtin_eq_cell); 167 | env.emplace(make_symbol("car"), &builtin_car_cell); 168 | env.emplace(make_symbol("cdr"), &builtin_cdr_cell); 169 | env.emplace(make_symbol("atom"), &builtin_atom_cell); 170 | env.emplace(make_symbol("cons"), &builtin_cons_cell); 171 | env.emplace(make_symbol("label"), &builtin_label_cell); 172 | env.emplace(make_symbol("list"), &builtin_list_cell); 173 | env.emplace(make_symbol("help"), &builtin_help_cell); 174 | 175 | kTRUE = make_atom("T"); 176 | kFALSE = make_atom("F"); 177 | kUNDEFINED = make_atom("UNDEFINED"); 178 | kNIL = make_atom("NIL"); 179 | 180 | 181 | for (int i = 0; i < 256; ++i) { 182 | numbers[i] = integer_cell(i); 183 | } 184 | 185 | } 186 | 187 | void garbage_collect() { 188 | 189 | // 190 | if (!free_list.empty()) return; 191 | 192 | for (auto &x : storage) { 193 | cell_ptr cp = (cell_ptr)&x; 194 | cp->alive = false; 195 | } 196 | 197 | for (auto &kv : env) { 198 | kv.first->mark(); 199 | if (kv.second) kv.second->mark(); 200 | } 201 | 202 | for (auto x : temp_list) { 203 | if (x) x->mark(); 204 | } 205 | 206 | 207 | for (auto &x : storage) { 208 | cell_ptr cp = (cell_ptr)&x; 209 | if (!cp->alive) { 210 | delete cp; 211 | free_list.push_back(&x); 212 | } 213 | } 214 | } 215 | 216 | void *cell::operator new(std::size_t size) { 217 | 218 | if (free_list.empty()) garbage_collect(); 219 | if (free_list.empty()) throw std::bad_alloc(); 220 | void *vp = free_list.back(); 221 | //temp_list.push_back(vp); 222 | free_list.pop_back(); 223 | return vp; 224 | } 225 | 226 | void cell::operator delete(void *vp) { 227 | // remove from temp_list, just in case... should never happen. 228 | //std::erase(temp_list.begin(), std::remove(temp_list.begin(), temp_list.end(), vp)); 229 | //free_list.push_back(vp); 230 | } 231 | 232 | 233 | cell_ptr make_atom(const std::string &s) { 234 | auto &map = atom_map; 235 | 236 | auto iter = map.find(s); 237 | if (iter != map.end()) return iter->second; 238 | auto tmp = new atom_cell(s); 239 | map.emplace(s, tmp); 240 | return tmp; 241 | } 242 | 243 | symbol_cell_ptr make_symbol(const std::string &s) { 244 | auto &map = symbol_map; 245 | 246 | auto iter = map.find(s); 247 | if (iter != map.end()) return iter->second; 248 | auto tmp = new symbol_cell(s); 249 | map.emplace(s, tmp); 250 | return tmp; 251 | } 252 | 253 | 254 | cell_ptr make_integer(int i) { 255 | if (i >= 0 && i < numbers.size()) return &numbers[i]; 256 | 257 | return temp(new integer_cell(i)); 258 | } 259 | 260 | 261 | cell_ptr make_pair(cell_ptr a, cell_ptr b) { 262 | return temp(new pair_cell(a, b)); 263 | } 264 | 265 | cell_ptr make_unary(int op, cell_ptr rhs) { 266 | return temp(new unary_cell(op, rhs)); 267 | } 268 | 269 | cell_ptr make_binary(int op, cell_ptr lhs, cell_ptr rhs) { 270 | return temp(new binary_cell(op, lhs, rhs)); 271 | } 272 | 273 | cell_ptr make_conditional(std::vector &&pe) { 274 | return temp(new conditional_cell(std::move(pe))); 275 | } 276 | 277 | cell_ptr make_lambda(symbol_cell_ptr label, std::vector &¶meters, cell_ptr body) { 278 | return temp(new lambda_cell(label, std::move(parameters), body)); 279 | } 280 | 281 | cell_ptr make_lambda(symbol_cell_ptr label, const std::vector ¶meters, cell_ptr body) { 282 | return temp(new lambda_cell(label, parameters, body)); 283 | } 284 | 285 | cell_ptr make_function(cell_ptr function, std::vector &¶meters) { 286 | return temp(new function_cell(function, std::move(parameters))); 287 | } 288 | 289 | 290 | 291 | 292 | #pragma mark - to_string 293 | 294 | std::string cell::to_string() const { 295 | char *tmp = nullptr; 296 | int size = asprintf(&tmp, "#", this); 297 | std::string s(tmp, tmp+size); 298 | free(tmp); 299 | return s; 300 | } 301 | 302 | std::string integer_cell::to_string() const { 303 | return std::to_string(value); 304 | } 305 | 306 | std::string atom_cell::to_string() const { 307 | return value; 308 | } 309 | 310 | std::string symbol_cell::to_string() const { 311 | return value; 312 | } 313 | 314 | std::string pair_cell::to_string() const { 315 | std::string tmp; 316 | tmp.push_back('('); 317 | 318 | // if this is a normal list, print it with commas 319 | const pair_cell *p = this; 320 | while (p) { 321 | if (!p->car) break; 322 | if (p->cdr && !p->cdr->is()) break; 323 | p = (const pair_cell *)p->cdr; 324 | } 325 | if (p == nullptr) { 326 | // simple, normal list. 327 | p = this; 328 | while (p) { 329 | tmp.append(p->car->to_string()); 330 | if (p->cdr) { 331 | tmp.append(", "); 332 | } 333 | p = (const pair_cell *)p->cdr; 334 | } 335 | } else { 336 | 337 | if (car) { 338 | tmp.append(car->to_string()); 339 | } 340 | if (cdr) { 341 | tmp.append(" . "); 342 | tmp.append(cdr->to_string()); 343 | } 344 | 345 | } 346 | 347 | 348 | tmp.push_back(')'); 349 | return tmp; 350 | } 351 | 352 | 353 | std::string builtin_cell::to_string() const { 354 | char *tmp = nullptr; 355 | int size = asprintf(&tmp, "#", name.c_str()); 356 | std::string s(tmp, tmp+size); 357 | free(tmp); 358 | return s; 359 | } 360 | 361 | 362 | std::string lambda_cell::to_string() const { 363 | char *tmp = nullptr; 364 | int size = asprintf(&tmp, "#", name ? name->to_string().c_str() : ""); 365 | std::string s(tmp, tmp+size); 366 | free(tmp); 367 | return s; 368 | } 369 | 370 | #pragma mark - to_xxx 371 | 372 | symbol_cell_ptr cell::to_symbol() { 373 | throw std::runtime_error("Expected symbol."); 374 | } 375 | 376 | symbol_cell_ptr symbol_cell::to_symbol() { 377 | return this; 378 | } 379 | 380 | int cell::to_int() const { 381 | throw std::runtime_error("Expected integer."); 382 | } 383 | 384 | int integer_cell::to_int() const { 385 | return value; 386 | } 387 | 388 | int pair_cell::to_int() const { 389 | // allow (1) to be treated as an int. 390 | if (car && !cdr) return car->to_int(); 391 | return cell::to_int(); 392 | } 393 | 394 | 395 | bool cell::to_bool() const { 396 | throw std::runtime_error("Expected boolean."); 397 | } 398 | 399 | 400 | bool pair_cell::to_bool() const { 401 | // allow (1) to be treated as an int. 402 | if (car && !cdr) return car->to_bool(); 403 | return cell::to_bool(); 404 | } 405 | 406 | bool atom_cell::to_bool() const { 407 | if (this == kTRUE) return true; 408 | if (this == kFALSE) return false; 409 | return cell::to_bool(); 410 | } 411 | 412 | cell_ptr cell::to_atom() { 413 | throw std::runtime_error("Expected atom."); 414 | } 415 | 416 | cell_ptr atom_cell::to_atom() { 417 | return this; 418 | } 419 | 420 | cell_ptr pair_cell::to_atom() { 421 | // allow (TRUE) to be treated as an int. 422 | if (car && !cdr) return car->to_atom(); 423 | return cell::to_atom(); 424 | } 425 | 426 | std::pair cell::to_pair() const { 427 | throw std::runtime_error("Expected pair."); 428 | } 429 | 430 | 431 | std::pair pair_cell::to_pair() const { 432 | return std::make_pair(car, cdr); 433 | } 434 | 435 | 436 | 437 | #pragma mark - substitute 438 | 439 | cell_ptr symbol_cell::substitute(hideset &hs, const environment &e) { 440 | if (std::find(hs.begin(), hs.end(), this) != hs.end()) return this; 441 | auto iter = e.find(this); 442 | if (iter != e.end()) return iter->second; 443 | return this; 444 | } 445 | 446 | cell_ptr function_cell::substitute(hideset &hs, const environment &e) { 447 | 448 | auto f = function->substitute(hs, e); 449 | 450 | std::vector args; 451 | std::transform(arguments.begin(), arguments.end(), std::back_inserter(args), 452 | [&](cell_ptr cell) { return cell->substitute(hs, e); } 453 | ); 454 | 455 | if (arguments == args && f == function) return this; 456 | return make_function(f, std::move(args)); 457 | } 458 | 459 | cell_ptr lambda_cell::substitute(hideset &hs, const environment &e) { 460 | auto old_size = hs.size(); 461 | if (name) hs.push_back(name); 462 | hs.insert(hs.end(), parameters.begin(), parameters.end()); 463 | auto tmp = body->substitute(hs, e); 464 | hs.resize(old_size); 465 | 466 | if (tmp == body) return this; 467 | return make_lambda(name, parameters, tmp); 468 | } 469 | 470 | cell_ptr conditional_cell::substitute(hideset &hs, const environment &e) { 471 | 472 | std::vector tmp; 473 | std::transform(pe.begin(), pe.end(), std::back_inserter(tmp), [&](cell_ptr cell){ 474 | return cell ? cell->substitute(hs, e) : cell; 475 | }); 476 | 477 | if (pe == tmp) return this; 478 | return make_conditional(std::move(tmp)); 479 | } 480 | 481 | cell_ptr pair_cell::substitute(hideset &hs, const environment &e) { 482 | auto a = car ? car->substitute(hs, e) : car; 483 | auto b = cdr ? cdr->substitute(hs, e) : cdr; 484 | if (a == car && b == cdr) return this; 485 | return make_pair(a, b); 486 | } 487 | 488 | cell_ptr binary_cell::substitute(hideset &hs, const environment &e) { 489 | auto a = car ? car->substitute(hs, e) : car; 490 | auto b = cdr ? cdr->substitute(hs, e) : cdr; 491 | if (a == car && b == cdr) return this; 492 | return make_binary(op, a, b); 493 | } 494 | 495 | cell_ptr unary_cell::substitute(hideset &hs, const environment &e) { 496 | auto a = car ? car->substitute(hs, e) : car; 497 | if (a == car) return this; 498 | return make_unary(op, a); 499 | } 500 | 501 | 502 | #pragma mark - evaluate 503 | 504 | cell_ptr unary_cell::evaluate(const environment &e) { 505 | cell_ptr tmp = car->evaluate(e); 506 | // null ? 507 | switch(op) { 508 | 509 | case PLUS: 510 | return make_integer(tmp->to_int()); 511 | 512 | case MINUS: 513 | return make_integer(-tmp->to_int()); 514 | 515 | case NOT: 516 | return tmp->to_bool() ? kFALSE : kTRUE; 517 | default: 518 | throw std::runtime_error("invalid unary operation."); 519 | } 520 | } 521 | 522 | cell_ptr binary_cell::evaluate(const environment &e) { 523 | switch(op) { 524 | bool ok; 525 | case AND: 526 | ok = car->evaluate(e)->to_bool() && cdr->evaluate(e)->to_bool(); 527 | return ok ? kTRUE: kFALSE; 528 | 529 | case OR: 530 | ok = car->evaluate(e)->to_bool() || cdr->evaluate(e)->to_bool(); 531 | return ok ? kTRUE: kFALSE; 532 | 533 | case XOR: 534 | ok = car->evaluate(e)->to_bool() ^ cdr->evaluate(e)->to_bool(); 535 | return ok ? kTRUE: kFALSE; 536 | } 537 | 538 | int a = car->evaluate(e)->to_int(); 539 | int b = cdr->evaluate(e)->to_int(); 540 | switch(op) { 541 | case PLUS: return make_integer(a + b); 542 | case MINUS: return make_integer(a - b); 543 | case TIMES: return make_integer(a * b); 544 | case DIVIDE: return make_integer(a / b); 545 | case EQ: return a == b ? kTRUE : kFALSE; 546 | case NE: return a != b ? kTRUE : kFALSE; 547 | case LT: return a < b ? kTRUE : kFALSE; 548 | case LE: return a <= b ? kTRUE : kFALSE; 549 | case GT: return a > b ? kTRUE : kFALSE; 550 | case GE: return a >= b ? kTRUE : kFALSE; 551 | default: 552 | throw std::runtime_error("invalid binary operation."); 553 | } 554 | } 555 | 556 | 557 | cell_ptr pair_cell::evaluate(const environment &e) { 558 | auto a = car ? car->evaluate(e) : car; 559 | auto b = cdr ? cdr->evaluate(e) : cdr; 560 | if (a == car && b == cdr) return this; 561 | return make_pair(a, b); 562 | } 563 | 564 | cell_ptr symbol_cell::evaluate(const environment &e) { 565 | auto iter = e.find(this); 566 | if (iter == e.end()) throw std::runtime_error("free variable - " + value); 567 | auto tmp = iter->second; 568 | return tmp->evaluate(); //? does it need e? any parms should be terminals at this point. 569 | } 570 | 571 | cell_ptr conditional_cell::evaluate(const environment &env) { 572 | 573 | for (auto iter = pe.begin(); iter != pe.end(); ) { 574 | auto p = *iter++; 575 | auto e = *iter++; 576 | 577 | if (p->evaluate(env)->to_bool()) return e->evaluate(env); 578 | } 579 | throw std::runtime_error("condition did not have a true clause."); 580 | } 581 | 582 | cell_ptr function_cell::evaluate(const environment &env) { 583 | auto tmp = function->evaluate(env); 584 | 585 | if (!tmp) throw std::runtime_error("nil function."); 586 | 587 | if (tmp->is()) { 588 | auto f = (lambda_cell *)tmp; 589 | 590 | std::vector args; 591 | std::transform(arguments.begin(), arguments.end(), std::back_inserter(args), 592 | [&](cell_ptr cell) { return cell->evaluate(env); } 593 | ); 594 | 595 | return f->call(args); 596 | } 597 | 598 | if (tmp->is()) { 599 | auto f = (builtin_cell *)tmp; 600 | 601 | return f->call(arguments, env); 602 | } 603 | throw std::runtime_error("not a function."); 604 | } 605 | 606 | cell_ptr lambda_cell::evaluate(const environment &e) { 607 | hideset hs; 608 | return substitute(hs, e); 609 | } 610 | 611 | cell_ptr lambda_cell::label(symbol_cell_ptr n) { 612 | if (n == name) return this; 613 | return make_lambda(n, parameters, body); 614 | } 615 | 616 | cell_ptr lambda_cell::call(const std::vector &arguments) { 617 | if (arguments.size() != parameters.size()) 618 | throw std::runtime_error("arity error."); 619 | 620 | environment env; 621 | if (name) env.emplace(name, this); 622 | for (int i = 0; i < parameters.size(); ++i) { 623 | env.emplace(parameters[i], arguments[i]); 624 | } 625 | return body->evaluate(env); 626 | } 627 | 628 | cell_ptr builtin_cell::call(const std::vector &arguments, const environment &e) { 629 | //if (arguments.size() != arity) 630 | // throw std::runtime_error("arity error."); 631 | 632 | return function(arguments, e); 633 | } 634 | 635 | #pragma mark - mark 636 | 637 | void unary_cell::mark() { 638 | cell::mark(); 639 | if (car) car->mark(); 640 | } 641 | 642 | void binary_cell::mark() { 643 | cell::mark(); 644 | if (car) car->mark(); 645 | if (cdr) cdr->mark(); 646 | } 647 | 648 | void pair_cell::mark() { 649 | cell::mark(); 650 | if (car) car->mark(); 651 | if (cdr) cdr->mark(); 652 | } 653 | 654 | void lambda_cell::mark() { 655 | cell::mark(); 656 | if (name) name->mark(); 657 | if (body) body->mark(); 658 | } 659 | 660 | void function_cell::mark() { 661 | cell::mark(); 662 | if (function) function->mark(); 663 | for (auto x : arguments) { if (x) x->mark(); } 664 | } 665 | 666 | void conditional_cell::mark() { 667 | cell::mark(); 668 | for (auto x : pe) { if (x) x->mark(); } 669 | } 670 | 671 | 672 | } // namespace 673 | -------------------------------------------------------------------------------- /lempar.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** 2000-05-29 3 | ** 4 | ** The author disclaims copyright to this source code. In place of 5 | ** a legal notice, here is a blessing: 6 | ** 7 | ** May you do good and not evil. 8 | ** May you find forgiveness for yourself and forgive others. 9 | ** May you share freely, never taking more than you give. 10 | ** 11 | ************************************************************************* 12 | ** Driver template for the LEMON parser generator. 13 | ** 14 | ** The "lemon" program processes an LALR(1) input grammar file, then uses 15 | ** this template to construct a parser. The "lemon" program inserts text 16 | ** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the 17 | ** interstitial "-" characters) contained in this template is changed into 18 | ** the value of the %name directive from the grammar. Otherwise, the content 19 | ** of this template is copied straight through into the generate parser 20 | ** source file. 21 | ** 22 | ** The following is the concatenation of all %include directives from the 23 | ** input grammar file: 24 | */ 25 | #include 26 | #include 27 | /************ Begin %include sections from the grammar ************************/ 28 | %% 29 | /**************** End of %include directives **********************************/ 30 | /* These constants specify the various numeric values for terminal symbols 31 | ** in a format understandable to "makeheaders". This section is blank unless 32 | ** "lemon" is run with the "-m" command-line option. 33 | ***************** Begin makeheaders token definitions *************************/ 34 | %% 35 | /**************** End makeheaders token definitions ***************************/ 36 | 37 | /* The next sections is a series of control #defines. 38 | ** various aspects of the generated parser. 39 | ** YYCODETYPE is the data type used to store the integer codes 40 | ** that represent terminal and non-terminal symbols. 41 | ** "unsigned char" is used if there are fewer than 42 | ** 256 symbols. Larger types otherwise. 43 | ** YYNOCODE is a number of type YYCODETYPE that is not used for 44 | ** any terminal or nonterminal symbol. 45 | ** YYFALLBACK If defined, this indicates that one or more tokens 46 | ** (also known as: "terminal symbols") have fall-back 47 | ** values which should be used if the original symbol 48 | ** would not parse. This permits keywords to sometimes 49 | ** be used as identifiers, for example. 50 | ** YYACTIONTYPE is the data type used for "action codes" - numbers 51 | ** that indicate what to do in response to the next 52 | ** token. 53 | ** ParseTOKENTYPE is the data type used for minor type for terminal 54 | ** symbols. Background: A "minor type" is a semantic 55 | ** value associated with a terminal or non-terminal 56 | ** symbols. For example, for an "ID" terminal symbol, 57 | ** the minor type might be the name of the identifier. 58 | ** Each non-terminal can have a different minor type. 59 | ** Terminal symbols all have the same minor type, though. 60 | ** This macros defines the minor type for terminal 61 | ** symbols. 62 | ** YYMINORTYPE is the data type used for all minor types. 63 | ** This is typically a union of many types, one of 64 | ** which is ParseTOKENTYPE. The entry in the union 65 | ** for terminal symbols is called "yy0". 66 | ** YYSTACKDEPTH is the maximum depth of the parser's stack. If 67 | ** zero the stack is dynamically sized using realloc() 68 | ** ParseARG_SDECL A static variable declaration for the %extra_argument 69 | ** ParseARG_PDECL A parameter declaration for the %extra_argument 70 | ** ParseARG_PARAM Code to pass %extra_argument as a subroutine parameter 71 | ** ParseARG_STORE Code to store %extra_argument into yypParser 72 | ** ParseARG_FETCH Code to extract %extra_argument from yypParser 73 | ** ParseCTX_* As ParseARG_ except for %extra_context 74 | ** YYERRORSYMBOL is the code number of the error symbol. If not 75 | ** defined, then do no error processing. 76 | ** YYNSTATE the combined number of states. 77 | ** YYNRULE the number of rules in the grammar 78 | ** YYNTOKEN Number of terminal symbols 79 | ** YY_MAX_SHIFT Maximum value for shift actions 80 | ** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions 81 | ** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions 82 | ** YY_ERROR_ACTION The yy_action[] code for syntax error 83 | ** YY_ACCEPT_ACTION The yy_action[] code for accept 84 | ** YY_NO_ACTION The yy_action[] code for no-op 85 | ** YY_MIN_REDUCE Minimum value for reduce actions 86 | ** YY_MAX_REDUCE Maximum value for reduce actions 87 | */ 88 | #ifndef INTERFACE 89 | # define INTERFACE 1 90 | #endif 91 | /************* Begin control #defines *****************************************/ 92 | %% 93 | /************* End control #defines *******************************************/ 94 | #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) 95 | 96 | /* Define the yytestcase() macro to be a no-op if is not already defined 97 | ** otherwise. 98 | ** 99 | ** Applications can choose to define yytestcase() in the %include section 100 | ** to a macro that can assist in verifying code coverage. For production 101 | ** code the yytestcase() macro should be turned off. But it is useful 102 | ** for testing. 103 | */ 104 | #ifndef yytestcase 105 | # define yytestcase(X) 106 | #endif 107 | 108 | 109 | /* Next are the tables used to determine what action to take based on the 110 | ** current state and lookahead token. These tables are used to implement 111 | ** functions that take a state number and lookahead value and return an 112 | ** action integer. 113 | ** 114 | ** Suppose the action integer is N. Then the action is determined as 115 | ** follows 116 | ** 117 | ** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead 118 | ** token onto the stack and goto state N. 119 | ** 120 | ** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then 121 | ** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. 122 | ** 123 | ** N == YY_ERROR_ACTION A syntax error has occurred. 124 | ** 125 | ** N == YY_ACCEPT_ACTION The parser accepts its input. 126 | ** 127 | ** N == YY_NO_ACTION No such action. Denotes unused 128 | ** slots in the yy_action[] table. 129 | ** 130 | ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE 131 | ** and YY_MAX_REDUCE 132 | ** 133 | ** The action table is constructed as a single large table named yy_action[]. 134 | ** Given state S and lookahead X, the action is computed as either: 135 | ** 136 | ** (A) N = yy_action[ yy_shift_ofst[S] + X ] 137 | ** (B) N = yy_default[S] 138 | ** 139 | ** The (A) formula is preferred. The B formula is used instead if 140 | ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X. 141 | ** 142 | ** The formulas above are for computing the action when the lookahead is 143 | ** a terminal symbol. If the lookahead is a non-terminal (as occurs after 144 | ** a reduce action) then the yy_reduce_ofst[] array is used in place of 145 | ** the yy_shift_ofst[] array. 146 | ** 147 | ** The following are the tables generated in this section: 148 | ** 149 | ** yy_action[] A single table containing all actions. 150 | ** yy_lookahead[] A table containing the lookahead for each entry in 151 | ** yy_action. Used to detect hash collisions. 152 | ** yy_shift_ofst[] For each state, the offset into yy_action for 153 | ** shifting terminals. 154 | ** yy_reduce_ofst[] For each state, the offset into yy_action for 155 | ** shifting non-terminals after a reduce. 156 | ** yy_default[] Default action for each state. 157 | ** 158 | *********** Begin parsing tables **********************************************/ 159 | %% 160 | /********** End of lemon-generated parsing tables *****************************/ 161 | 162 | /* The next table maps tokens (terminal symbols) into fallback tokens. 163 | ** If a construct like the following: 164 | ** 165 | ** %fallback ID X Y Z. 166 | ** 167 | ** appears in the grammar, then ID becomes a fallback token for X, Y, 168 | ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser 169 | ** but it does not parse, the type of the token is changed to ID and 170 | ** the parse is retried before an error is thrown. 171 | ** 172 | ** This feature can be used, for example, to cause some keywords in a language 173 | ** to revert to identifiers if they keyword does not apply in the context where 174 | ** it appears. 175 | */ 176 | #ifdef YYFALLBACK 177 | static const YYCODETYPE yyFallback[] = { 178 | %% 179 | }; 180 | #endif /* YYFALLBACK */ 181 | 182 | /* The following structure represents a single element of the 183 | ** parser's stack. Information stored includes: 184 | ** 185 | ** + The state number for the parser at this level of the stack. 186 | ** 187 | ** + The value of the token stored at this level of the stack. 188 | ** (In other words, the "major" token.) 189 | ** 190 | ** + The semantic value stored at this level of the stack. This is 191 | ** the information used by the action routines in the grammar. 192 | ** It is sometimes called the "minor" token. 193 | ** 194 | ** After the "shift" half of a SHIFTREDUCE action, the stateno field 195 | ** actually contains the reduce action for the second half of the 196 | ** SHIFTREDUCE. 197 | */ 198 | struct yyStackEntry { 199 | YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ 200 | YYCODETYPE major; /* The major token value. This is the code 201 | ** number for the token at this stack level */ 202 | YYMINORTYPE minor; /* The user-supplied minor token value. This 203 | ** is the value of the token */ 204 | }; 205 | typedef struct yyStackEntry yyStackEntry; 206 | 207 | /* The state of the parser is completely contained in an instance of 208 | ** the following structure */ 209 | struct yyParser { 210 | yyStackEntry *yytos; /* Pointer to top element of the stack */ 211 | #ifdef YYTRACKMAXSTACKDEPTH 212 | int yyhwm; /* High-water mark of the stack */ 213 | #endif 214 | #ifndef YYNOERRORRECOVERY 215 | int yyerrcnt; /* Shifts left before out of the error */ 216 | #endif 217 | ParseARG_SDECL /* A place to hold %extra_argument */ 218 | ParseCTX_SDECL /* A place to hold %extra_context */ 219 | #if YYSTACKDEPTH<=0 220 | int yystksz; /* Current side of the stack */ 221 | yyStackEntry *yystack; /* The parser's stack */ 222 | yyStackEntry yystk0; /* First stack entry */ 223 | #else 224 | yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ 225 | yyStackEntry *yystackEnd; /* Last entry in the stack */ 226 | #endif 227 | }; 228 | typedef struct yyParser yyParser; 229 | 230 | #ifndef NDEBUG 231 | #include 232 | static FILE *yyTraceFILE = 0; 233 | static char *yyTracePrompt = 0; 234 | #endif /* NDEBUG */ 235 | 236 | #ifndef NDEBUG 237 | /* 238 | ** Turn parser tracing on by giving a stream to which to write the trace 239 | ** and a prompt to preface each trace message. Tracing is turned off 240 | ** by making either argument NULL 241 | ** 242 | ** Inputs: 243 | **
    244 | **
  • A FILE* to which trace output should be written. 245 | ** If NULL, then tracing is turned off. 246 | **
  • A prefix string written at the beginning of every 247 | ** line of trace output. If NULL, then tracing is 248 | ** turned off. 249 | **
250 | ** 251 | ** Outputs: 252 | ** None. 253 | */ 254 | void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ 255 | yyTraceFILE = TraceFILE; 256 | yyTracePrompt = zTracePrompt; 257 | if( yyTraceFILE==0 ) yyTracePrompt = 0; 258 | else if( yyTracePrompt==0 ) yyTraceFILE = 0; 259 | } 260 | #endif /* NDEBUG */ 261 | 262 | #if defined(YYCOVERAGE) || !defined(NDEBUG) 263 | /* For tracing shifts, the names of all terminals and nonterminals 264 | ** are required. The following table supplies these names */ 265 | static const char *const yyTokenName[] = { 266 | %% 267 | }; 268 | #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ 269 | 270 | #ifndef NDEBUG 271 | /* For tracing reduce actions, the names of all rules are required. 272 | */ 273 | static const char *const yyRuleName[] = { 274 | %% 275 | }; 276 | #endif /* NDEBUG */ 277 | 278 | 279 | #if YYSTACKDEPTH<=0 280 | /* 281 | ** Try to increase the size of the parser stack. Return the number 282 | ** of errors. Return 0 on success. 283 | */ 284 | static int yyGrowStack(yyParser *p){ 285 | int newSize; 286 | int idx; 287 | yyStackEntry *pNew; 288 | 289 | newSize = p->yystksz*2 + 100; 290 | idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; 291 | if( p->yystack==&p->yystk0 ){ 292 | pNew = malloc(newSize*sizeof(pNew[0])); 293 | if( pNew ) pNew[0] = p->yystk0; 294 | }else{ 295 | pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); 296 | } 297 | if( pNew ){ 298 | p->yystack = pNew; 299 | p->yytos = &p->yystack[idx]; 300 | #ifndef NDEBUG 301 | if( yyTraceFILE ){ 302 | fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", 303 | yyTracePrompt, p->yystksz, newSize); 304 | } 305 | #endif 306 | p->yystksz = newSize; 307 | } 308 | return pNew==0; 309 | } 310 | #endif 311 | 312 | /* Datatype of the argument to the memory allocated passed as the 313 | ** second argument to ParseAlloc() below. This can be changed by 314 | ** putting an appropriate #define in the %include section of the input 315 | ** grammar. 316 | */ 317 | #ifndef YYMALLOCARGTYPE 318 | # define YYMALLOCARGTYPE size_t 319 | #endif 320 | 321 | /* Initialize a new parser that has already been allocated. 322 | */ 323 | void ParseInit(void *yypRawParser ParseCTX_PDECL){ 324 | yyParser *yypParser = (yyParser*)yypRawParser; 325 | ParseCTX_STORE 326 | #ifdef YYTRACKMAXSTACKDEPTH 327 | yypParser->yyhwm = 0; 328 | #endif 329 | #if YYSTACKDEPTH<=0 330 | yypParser->yytos = NULL; 331 | yypParser->yystack = NULL; 332 | yypParser->yystksz = 0; 333 | if( yyGrowStack(yypParser) ){ 334 | yypParser->yystack = &yypParser->yystk0; 335 | yypParser->yystksz = 1; 336 | } 337 | #endif 338 | #ifndef YYNOERRORRECOVERY 339 | yypParser->yyerrcnt = -1; 340 | #endif 341 | yypParser->yytos = yypParser->yystack; 342 | yypParser->yystack[0].stateno = 0; 343 | yypParser->yystack[0].major = 0; 344 | #if YYSTACKDEPTH>0 345 | yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; 346 | #endif 347 | } 348 | 349 | #ifndef Parse_ENGINEALWAYSONSTACK 350 | /* 351 | ** This function allocates a new parser. 352 | ** The only argument is a pointer to a function which works like 353 | ** malloc. 354 | ** 355 | ** Inputs: 356 | ** A pointer to the function used to allocate memory. 357 | ** 358 | ** Outputs: 359 | ** A pointer to a parser. This pointer is used in subsequent calls 360 | ** to Parse and ParseFree. 361 | */ 362 | void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) ParseCTX_PDECL){ 363 | yyParser *yypParser; 364 | yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); 365 | if( yypParser ){ 366 | ParseCTX_STORE 367 | ParseInit(yypParser ParseCTX_PARAM); 368 | } 369 | return (void*)yypParser; 370 | } 371 | #endif /* Parse_ENGINEALWAYSONSTACK */ 372 | 373 | 374 | /* The following function deletes the "minor type" or semantic value 375 | ** associated with a symbol. The symbol can be either a terminal 376 | ** or nonterminal. "yymajor" is the symbol code, and "yypminor" is 377 | ** a pointer to the value to be deleted. The code used to do the 378 | ** deletions is derived from the %destructor and/or %token_destructor 379 | ** directives of the input grammar. 380 | */ 381 | static void yy_destructor( 382 | yyParser *yypParser, /* The parser */ 383 | YYCODETYPE yymajor, /* Type code for object to destroy */ 384 | YYMINORTYPE *yypminor /* The object to be destroyed */ 385 | ){ 386 | ParseARG_FETCH 387 | ParseCTX_FETCH 388 | switch( yymajor ){ 389 | /* Here is inserted the actions which take place when a 390 | ** terminal or non-terminal is destroyed. This can happen 391 | ** when the symbol is popped from the stack during a 392 | ** reduce or during error processing or when a parser is 393 | ** being destroyed before it is finished parsing. 394 | ** 395 | ** Note: during a reduce, the only symbols destroyed are those 396 | ** which appear on the RHS of the rule, but which are *not* used 397 | ** inside the C code. 398 | */ 399 | /********* Begin destructor definitions ***************************************/ 400 | %% 401 | /********* End destructor definitions *****************************************/ 402 | default: break; /* If no destructor action specified: do nothing */ 403 | } 404 | } 405 | 406 | /* 407 | ** Pop the parser's stack once. 408 | ** 409 | ** If there is a destructor routine associated with the token which 410 | ** is popped from the stack, then call it. 411 | */ 412 | static void yy_pop_parser_stack(yyParser *pParser){ 413 | yyStackEntry *yytos; 414 | assert( pParser->yytos!=0 ); 415 | assert( pParser->yytos > pParser->yystack ); 416 | yytos = pParser->yytos--; 417 | #ifndef NDEBUG 418 | if( yyTraceFILE ){ 419 | fprintf(yyTraceFILE,"%sPopping %s\n", 420 | yyTracePrompt, 421 | yyTokenName[yytos->major]); 422 | } 423 | #endif 424 | yy_destructor(pParser, yytos->major, &yytos->minor); 425 | } 426 | 427 | /* 428 | ** Clear all secondary memory allocations from the parser 429 | */ 430 | void ParseFinalize(void *p){ 431 | yyParser *pParser = (yyParser*)p; 432 | while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); 433 | #if YYSTACKDEPTH<=0 434 | if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); 435 | #endif 436 | } 437 | 438 | #ifndef Parse_ENGINEALWAYSONSTACK 439 | /* 440 | ** Deallocate and destroy a parser. Destructors are called for 441 | ** all stack elements before shutting the parser down. 442 | ** 443 | ** If the YYPARSEFREENEVERNULL macro exists (for example because it 444 | ** is defined in a %include section of the input grammar) then it is 445 | ** assumed that the input pointer is never NULL. 446 | */ 447 | void ParseFree( 448 | void *p, /* The parser to be deleted */ 449 | void (*freeProc)(void*) /* Function used to reclaim memory */ 450 | ){ 451 | #ifndef YYPARSEFREENEVERNULL 452 | if( p==0 ) return; 453 | #endif 454 | ParseFinalize(p); 455 | (*freeProc)(p); 456 | } 457 | #endif /* Parse_ENGINEALWAYSONSTACK */ 458 | 459 | /* 460 | ** Return the peak depth of the stack for a parser. 461 | */ 462 | #ifdef YYTRACKMAXSTACKDEPTH 463 | int ParseStackPeak(void *p){ 464 | yyParser *pParser = (yyParser*)p; 465 | return pParser->yyhwm; 466 | } 467 | #endif 468 | 469 | /* This array of booleans keeps track of the parser statement 470 | ** coverage. The element yycoverage[X][Y] is set when the parser 471 | ** is in state X and has a lookahead token Y. In a well-tested 472 | ** systems, every element of this matrix should end up being set. 473 | */ 474 | #if defined(YYCOVERAGE) 475 | static unsigned char yycoverage[YYNSTATE][YYNTOKEN]; 476 | #endif 477 | 478 | /* 479 | ** Write into out a description of every state/lookahead combination that 480 | ** 481 | ** (1) has not been used by the parser, and 482 | ** (2) is not a syntax error. 483 | ** 484 | ** Return the number of missed state/lookahead combinations. 485 | */ 486 | #if defined(YYCOVERAGE) 487 | int ParseCoverage(FILE *out){ 488 | int stateno, iLookAhead, i; 489 | int nMissed = 0; 490 | for(stateno=0; statenoYY_MAX_SHIFT ) return stateno; 517 | assert( stateno <= YY_SHIFT_MAX ); 518 | #if defined(YYCOVERAGE) 519 | yycoverage[stateno][iLookAhead] = 1; 520 | #endif 521 | do{ 522 | i = stateno <= YY_SHIFT_COUNT ? yy_shift_ofst[stateno] : stateno; 523 | assert( i>=0 ); 524 | assert( i<=YY_ACTTAB_COUNT ); 525 | assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); 526 | assert( iLookAhead!=YYNOCODE ); 527 | assert( iLookAhead < YYNTOKEN ); 528 | i += iLookAhead; 529 | assert( i<(int)YY_NLOOKAHEAD ); 530 | if( yy_lookahead[i]!=iLookAhead ){ 531 | #ifdef YYFALLBACK 532 | YYCODETYPE iFallback; /* Fallback token */ 533 | assert( iLookAhead %s\n", 539 | yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); 540 | } 541 | #endif 542 | assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ 543 | iLookAhead = iFallback; 544 | continue; 545 | } 546 | #endif 547 | #ifdef YYWILDCARD 548 | { 549 | int j = i - iLookAhead + YYWILDCARD; 550 | assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) ); 551 | if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){ 552 | #ifndef NDEBUG 553 | if( yyTraceFILE ){ 554 | fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", 555 | yyTracePrompt, yyTokenName[iLookAhead], 556 | yyTokenName[YYWILDCARD]); 557 | } 558 | #endif /* NDEBUG */ 559 | return yy_action[j]; 560 | } 561 | } 562 | #endif /* YYWILDCARD */ 563 | return yy_default[stateno]; 564 | }else{ 565 | assert( i>=0 && iYY_REDUCE_COUNT ){ 582 | return yy_default[stateno]; 583 | } 584 | #else 585 | assert( stateno<=YY_REDUCE_COUNT ); 586 | #endif 587 | i = yy_reduce_ofst[stateno]; 588 | assert( iLookAhead!=YYNOCODE ); 589 | i += iLookAhead; 590 | #ifdef YYERRORSYMBOL 591 | if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ 592 | return yy_default[stateno]; 593 | } 594 | #else 595 | assert( i>=0 && iyytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); 613 | /* Here code is inserted which will execute if the parser 614 | ** stack every overflows */ 615 | /******** Begin %stack_overflow code ******************************************/ 616 | %% 617 | /******** End %stack_overflow code ********************************************/ 618 | ParseARG_STORE /* Suppress warning about unused %extra_argument var */ 619 | ParseCTX_STORE 620 | } 621 | 622 | /* 623 | ** Print tracing information for a SHIFT action 624 | */ 625 | #ifndef NDEBUG 626 | static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){ 627 | if( yyTraceFILE ){ 628 | if( yyNewStateyytos->major], 631 | yyNewState); 632 | }else{ 633 | fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n", 634 | yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major], 635 | yyNewState - YY_MIN_REDUCE); 636 | } 637 | } 638 | } 639 | #else 640 | # define yyTraceShift(X,Y,Z) 641 | #endif 642 | 643 | /* 644 | ** Perform a shift action. 645 | */ 646 | static void yy_shift( 647 | yyParser *yypParser, /* The parser to be shifted */ 648 | YYACTIONTYPE yyNewState, /* The new state to shift in */ 649 | YYCODETYPE yyMajor, /* The major token to shift in */ 650 | ParseTOKENTYPE yyMinor /* The minor token to shift in */ 651 | ){ 652 | yyStackEntry *yytos; 653 | yypParser->yytos++; 654 | #ifdef YYTRACKMAXSTACKDEPTH 655 | if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ 656 | yypParser->yyhwm++; 657 | assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); 658 | } 659 | #endif 660 | #if YYSTACKDEPTH>0 661 | if( yypParser->yytos>yypParser->yystackEnd ){ 662 | yypParser->yytos--; 663 | yyStackOverflow(yypParser); 664 | return; 665 | } 666 | #else 667 | if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ 668 | if( yyGrowStack(yypParser) ){ 669 | yypParser->yytos--; 670 | yyStackOverflow(yypParser); 671 | return; 672 | } 673 | } 674 | #endif 675 | if( yyNewState > YY_MAX_SHIFT ){ 676 | yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; 677 | } 678 | yytos = yypParser->yytos; 679 | yytos->stateno = yyNewState; 680 | yytos->major = yyMajor; 681 | yytos->minor.yy0 = yyMinor; 682 | yyTraceShift(yypParser, yyNewState, "Shift"); 683 | } 684 | 685 | /* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side 686 | ** of that rule */ 687 | static const YYCODETYPE yyRuleInfoLhs[] = { 688 | %% 689 | }; 690 | 691 | /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number 692 | ** of symbols on the right-hand side of that rule. */ 693 | static const signed char yyRuleInfoNRhs[] = { 694 | %% 695 | }; 696 | 697 | static void yy_accept(yyParser*); /* Forward Declaration */ 698 | 699 | /* 700 | ** Perform a reduce action and the shift that must immediately 701 | ** follow the reduce. 702 | ** 703 | ** The yyLookahead and yyLookaheadToken parameters provide reduce actions 704 | ** access to the lookahead token (if any). The yyLookahead will be YYNOCODE 705 | ** if the lookahead token has already been consumed. As this procedure is 706 | ** only called from one place, optimizing compilers will in-line it, which 707 | ** means that the extra parameters have no performance impact. 708 | */ 709 | static YYACTIONTYPE yy_reduce( 710 | yyParser *yypParser, /* The parser */ 711 | unsigned int yyruleno, /* Number of the rule by which to reduce */ 712 | int yyLookahead, /* Lookahead token, or YYNOCODE if none */ 713 | ParseTOKENTYPE yyLookaheadToken /* Value of the lookahead token */ 714 | ParseCTX_PDECL /* %extra_context */ 715 | ){ 716 | int yygoto; /* The next state */ 717 | YYACTIONTYPE yyact; /* The next action */ 718 | yyStackEntry *yymsp; /* The top of the parser's stack */ 719 | int yysize; /* Amount to pop the stack */ 720 | ParseARG_FETCH 721 | (void)yyLookahead; 722 | (void)yyLookaheadToken; 723 | yymsp = yypParser->yytos; 724 | #ifndef NDEBUG 725 | if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ 726 | yysize = yyRuleInfoNRhs[yyruleno]; 727 | if( yysize ){ 728 | fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n", 729 | yyTracePrompt, 730 | yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno); 731 | }else{ 732 | fprintf(yyTraceFILE, "%sReduce %d [%s].\n", 733 | yyTracePrompt, yyruleno, yyRuleName[yyruleno]); 734 | } 735 | } 736 | #endif /* NDEBUG */ 737 | 738 | /* Check that the stack is large enough to grow by a single entry 739 | ** if the RHS of the rule is empty. This ensures that there is room 740 | ** enough on the stack to push the LHS value */ 741 | if( yyRuleInfoNRhs[yyruleno]==0 ){ 742 | #ifdef YYTRACKMAXSTACKDEPTH 743 | if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ 744 | yypParser->yyhwm++; 745 | assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); 746 | } 747 | #endif 748 | #if YYSTACKDEPTH>0 749 | if( yypParser->yytos>=yypParser->yystackEnd ){ 750 | yyStackOverflow(yypParser); 751 | /* The call to yyStackOverflow() above pops the stack until it is 752 | ** empty, causing the main parser loop to exit. So the return value 753 | ** is never used and does not matter. */ 754 | return 0; 755 | } 756 | #else 757 | if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ 758 | if( yyGrowStack(yypParser) ){ 759 | yyStackOverflow(yypParser); 760 | /* The call to yyStackOverflow() above pops the stack until it is 761 | ** empty, causing the main parser loop to exit. So the return value 762 | ** is never used and does not matter. */ 763 | return 0; 764 | } 765 | yymsp = yypParser->yytos; 766 | } 767 | #endif 768 | } 769 | 770 | switch( yyruleno ){ 771 | /* Beginning here are the reduction cases. A typical example 772 | ** follows: 773 | ** case 0: 774 | ** #line 775 | ** { ... } // User supplied code 776 | ** #line 777 | ** break; 778 | */ 779 | /********** Begin reduce actions **********************************************/ 780 | %% 781 | /********** End reduce actions ************************************************/ 782 | }; 783 | assert( yyrulenoYY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); 791 | 792 | /* It is not possible for a REDUCE to be followed by an error */ 793 | assert( yyact!=YY_ERROR_ACTION ); 794 | 795 | yymsp += yysize+1; 796 | yypParser->yytos = yymsp; 797 | yymsp->stateno = (YYACTIONTYPE)yyact; 798 | yymsp->major = (YYCODETYPE)yygoto; 799 | yyTraceShift(yypParser, yyact, "... then shift"); 800 | return yyact; 801 | } 802 | 803 | /* 804 | ** The following code executes when the parse fails 805 | */ 806 | #ifndef YYNOERRORRECOVERY 807 | static void yy_parse_failed( 808 | yyParser *yypParser /* The parser */ 809 | ){ 810 | ParseARG_FETCH 811 | ParseCTX_FETCH 812 | #ifndef NDEBUG 813 | if( yyTraceFILE ){ 814 | fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); 815 | } 816 | #endif 817 | while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); 818 | /* Here code is inserted which will be executed whenever the 819 | ** parser fails */ 820 | /************ Begin %parse_failure code ***************************************/ 821 | %% 822 | /************ End %parse_failure code *****************************************/ 823 | ParseARG_STORE /* Suppress warning about unused %extra_argument variable */ 824 | ParseCTX_STORE 825 | } 826 | #endif /* YYNOERRORRECOVERY */ 827 | 828 | /* 829 | ** The following code executes when a syntax error first occurs. 830 | */ 831 | static void yy_syntax_error( 832 | yyParser *yypParser, /* The parser */ 833 | int yymajor, /* The major type of the error token */ 834 | ParseTOKENTYPE yyminor /* The minor type of the error token */ 835 | ){ 836 | ParseARG_FETCH 837 | ParseCTX_FETCH 838 | #define TOKEN yyminor 839 | /************ Begin %syntax_error code ****************************************/ 840 | %% 841 | /************ End %syntax_error code ******************************************/ 842 | ParseARG_STORE /* Suppress warning about unused %extra_argument variable */ 843 | ParseCTX_STORE 844 | } 845 | 846 | /* 847 | ** The following is executed when the parser accepts 848 | */ 849 | static void yy_accept( 850 | yyParser *yypParser /* The parser */ 851 | ){ 852 | ParseARG_FETCH 853 | ParseCTX_FETCH 854 | #ifndef NDEBUG 855 | if( yyTraceFILE ){ 856 | fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); 857 | } 858 | #endif 859 | #ifndef YYNOERRORRECOVERY 860 | yypParser->yyerrcnt = -1; 861 | #endif 862 | assert( yypParser->yytos==yypParser->yystack ); 863 | /* Here code is inserted which will be executed whenever the 864 | ** parser accepts */ 865 | /*********** Begin %parse_accept code *****************************************/ 866 | %% 867 | /*********** End %parse_accept code *******************************************/ 868 | ParseARG_STORE /* Suppress warning about unused %extra_argument variable */ 869 | ParseCTX_STORE 870 | } 871 | 872 | /* The main parser program. 873 | ** The first argument is a pointer to a structure obtained from 874 | ** "ParseAlloc" which describes the current state of the parser. 875 | ** The second argument is the major token number. The third is 876 | ** the minor token. The fourth optional argument is whatever the 877 | ** user wants (and specified in the grammar) and is available for 878 | ** use by the action routines. 879 | ** 880 | ** Inputs: 881 | **
    882 | **
  • A pointer to the parser (an opaque structure.) 883 | **
  • The major token number. 884 | **
  • The minor token number. 885 | **
  • An option argument of a grammar-specified type. 886 | **
887 | ** 888 | ** Outputs: 889 | ** None. 890 | */ 891 | void Parse( 892 | void *yyp, /* The parser */ 893 | int yymajor, /* The major token code number */ 894 | ParseTOKENTYPE yyminor /* The value for the token */ 895 | ParseARG_PDECL /* Optional %extra_argument parameter */ 896 | ){ 897 | YYMINORTYPE yyminorunion; 898 | YYACTIONTYPE yyact; /* The parser action. */ 899 | #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 900 | int yyendofinput; /* True if we are at the end of input */ 901 | #endif 902 | #ifdef YYERRORSYMBOL 903 | int yyerrorhit = 0; /* True if yymajor has invoked an error */ 904 | #endif 905 | yyParser *yypParser = (yyParser*)yyp; /* The parser */ 906 | ParseCTX_FETCH 907 | ParseARG_STORE 908 | 909 | assert( yypParser->yytos!=0 ); 910 | #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 911 | yyendofinput = (yymajor==0); 912 | #endif 913 | 914 | yyact = yypParser->yytos->stateno; 915 | #ifndef NDEBUG 916 | if( yyTraceFILE ){ 917 | if( yyact < YY_MIN_REDUCE ){ 918 | fprintf(yyTraceFILE,"%sInput '%s' in state %d\n", 919 | yyTracePrompt,yyTokenName[yymajor],yyact); 920 | }else{ 921 | fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", 922 | yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); 923 | } 924 | } 925 | #endif 926 | 927 | do{ 928 | assert( yyact==yypParser->yytos->stateno ); 929 | yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); 930 | if( yyact >= YY_MIN_REDUCE ){ 931 | yyact = yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor, 932 | yyminor ParseCTX_PARAM); 933 | }else if( yyact <= YY_MAX_SHIFTREDUCE ){ 934 | yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor); 935 | #ifndef YYNOERRORRECOVERY 936 | yypParser->yyerrcnt--; 937 | #endif 938 | break; 939 | }else if( yyact==YY_ACCEPT_ACTION ){ 940 | yypParser->yytos--; 941 | yy_accept(yypParser); 942 | return; 943 | }else{ 944 | assert( yyact == YY_ERROR_ACTION ); 945 | yyminorunion.yy0 = yyminor; 946 | #ifdef YYERRORSYMBOL 947 | int yymx; 948 | #endif 949 | #ifndef NDEBUG 950 | if( yyTraceFILE ){ 951 | fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); 952 | } 953 | #endif 954 | #ifdef YYERRORSYMBOL 955 | /* A syntax error has occurred. 956 | ** The response to an error depends upon whether or not the 957 | ** grammar defines an error token "ERROR". 958 | ** 959 | ** This is what we do if the grammar does define ERROR: 960 | ** 961 | ** * Call the %syntax_error function. 962 | ** 963 | ** * Begin popping the stack until we enter a state where 964 | ** it is legal to shift the error symbol, then shift 965 | ** the error symbol. 966 | ** 967 | ** * Set the error count to three. 968 | ** 969 | ** * Begin accepting and shifting new tokens. No new error 970 | ** processing will occur until three tokens have been 971 | ** shifted successfully. 972 | ** 973 | */ 974 | if( yypParser->yyerrcnt<0 ){ 975 | yy_syntax_error(yypParser,yymajor,yyminor); 976 | } 977 | yymx = yypParser->yytos->major; 978 | if( yymx==YYERRORSYMBOL || yyerrorhit ){ 979 | #ifndef NDEBUG 980 | if( yyTraceFILE ){ 981 | fprintf(yyTraceFILE,"%sDiscard input token %s\n", 982 | yyTracePrompt,yyTokenName[yymajor]); 983 | } 984 | #endif 985 | yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); 986 | yymajor = YYNOCODE; 987 | }else{ 988 | while( yypParser->yytos > yypParser->yystack 989 | && (yyact = yy_find_reduce_action( 990 | yypParser->yytos->stateno, 991 | YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE 992 | ){ 993 | yy_pop_parser_stack(yypParser); 994 | } 995 | if( yypParser->yytos == yypParser->yystack || yymajor==0 ){ 996 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); 997 | yy_parse_failed(yypParser); 998 | #ifndef YYNOERRORRECOVERY 999 | yypParser->yyerrcnt = -1; 1000 | #endif 1001 | yymajor = YYNOCODE; 1002 | }else if( yymx!=YYERRORSYMBOL ){ 1003 | yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); 1004 | } 1005 | } 1006 | yypParser->yyerrcnt = 3; 1007 | yyerrorhit = 1; 1008 | if( yymajor==YYNOCODE ) break; 1009 | yyact = yypParser->yytos->stateno; 1010 | #elif defined(YYNOERRORRECOVERY) 1011 | /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to 1012 | ** do any kind of error recovery. Instead, simply invoke the syntax 1013 | ** error routine and continue going as if nothing had happened. 1014 | ** 1015 | ** Applications can set this macro (for example inside %include) if 1016 | ** they intend to abandon the parse upon the first syntax error seen. 1017 | */ 1018 | yy_syntax_error(yypParser,yymajor, yyminor); 1019 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); 1020 | break; 1021 | #else /* YYERRORSYMBOL is not defined */ 1022 | /* This is what we do if the grammar does not define ERROR: 1023 | ** 1024 | ** * Report an error message, and throw away the input token. 1025 | ** 1026 | ** * If the input token is $, then fail the parse. 1027 | ** 1028 | ** As before, subsequent error messages are suppressed until 1029 | ** three input tokens have been successfully shifted. 1030 | */ 1031 | if( yypParser->yyerrcnt<=0 ){ 1032 | yy_syntax_error(yypParser,yymajor, yyminor); 1033 | } 1034 | yypParser->yyerrcnt = 3; 1035 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); 1036 | if( yyendofinput ){ 1037 | yy_parse_failed(yypParser); 1038 | #ifndef YYNOERRORRECOVERY 1039 | yypParser->yyerrcnt = -1; 1040 | #endif 1041 | } 1042 | break; 1043 | #endif 1044 | } 1045 | }while( yypParser->yytos>yypParser->yystack ); 1046 | #ifndef NDEBUG 1047 | if( yyTraceFILE ){ 1048 | yyStackEntry *i; 1049 | char cDiv = '['; 1050 | fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); 1051 | for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ 1052 | fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); 1053 | cDiv = ' '; 1054 | } 1055 | fprintf(yyTraceFILE,"]\n"); 1056 | } 1057 | #endif 1058 | return; 1059 | } 1060 | 1061 | /* 1062 | ** Return the fallback token corresponding to canonical token iToken, or 1063 | ** 0 if iToken has no fallback. 1064 | */ 1065 | int ParseFallback(int iToken){ 1066 | #ifdef YYFALLBACK 1067 | assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); 1068 | return yyFallback[iToken]; 1069 | #else 1070 | (void)iToken; 1071 | #endif 1072 | return 0; 1073 | } 1074 | -------------------------------------------------------------------------------- /test/lempar.cxx: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | January, 2016. Sample class-based version. 4 | #define LEMON_SUPER as the name of a class which overrides lemon_base. 5 | The parser will be implemented in terms of that. 6 | add a %code section to instantiate it. 7 | */ 8 | 9 | /* 10 | ** 2000-05-29 11 | ** 12 | ** The author disclaims copyright to this source code. In place of 13 | ** a legal notice, here is a blessing: 14 | ** 15 | ** May you do good and not evil. 16 | ** May you find forgiveness for yourself and forgive others. 17 | ** May you share freely, never taking more than you give. 18 | ** 19 | ************************************************************************* 20 | ** Driver template for the LEMON parser generator. 21 | ** 22 | ** The "lemon" program processes an LALR(1) input grammar file, then uses 23 | ** this template to construct a parser. The "lemon" program inserts text 24 | ** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the 25 | ** interstitial "-" characters) contained in this template is changed into 26 | ** the value of the %name directive from the grammar. Otherwise, the content 27 | ** of this template is copied straight through into the generate parser 28 | ** source file. 29 | ** 30 | ** The following is the concatenation of all %include directives from the 31 | ** input grammar file: 32 | */ 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | namespace { 42 | 43 | // use std::allocator etc? 44 | 45 | 46 | // this is here so you can do something like Parse(void *, int, my_token &&) or (... const my_token &) 47 | template struct yy_fix_type { 48 | typedef typename std::remove_const::type>::type type; 49 | }; 50 | 51 | template<> 52 | struct yy_fix_type { 53 | typedef struct {} type; 54 | }; 55 | 56 | template 57 | typename yy_fix_type::type &yy_constructor(void *vp, Args&&... args ) { 58 | typedef typename yy_fix_type::type TT; 59 | TT *tmp = ::new(vp) TT(std::forward(args)...); 60 | return *tmp; 61 | } 62 | 63 | 64 | template 65 | typename yy_fix_type::type &yy_cast(void *vp) { 66 | typedef typename yy_fix_type::type TT; 67 | return *(TT *)vp; 68 | } 69 | 70 | 71 | template 72 | void yy_destructor(void *vp) { 73 | typedef typename yy_fix_type::type TT; 74 | ((TT *)vp)->~TT(); 75 | } 76 | 77 | 78 | template 79 | void yy_destructor(T &t) { 80 | t.~T(); 81 | } 82 | 83 | 84 | 85 | template 86 | void yy_move(void *dest, void *src) { 87 | typedef typename yy_fix_type::type TT; 88 | 89 | TT &tmp = yy_cast(src); 90 | yy_constructor(dest, std::move(tmp)); 91 | yy_destructor(tmp); 92 | } 93 | 94 | 95 | // this is to destruct references in the event of an exception. 96 | // only the LHS needs to be deleted -- other items remain on the 97 | // shift/reduce stack in a valid state 98 | // (as long as the destructor) doesn't throw! 99 | template 100 | struct yy_auto_deleter { 101 | 102 | yy_auto_deleter(T &t) : ref(t), enaged(true) 103 | {} 104 | yy_auto_deleter(const yy_auto_deleter &) = delete; 105 | yy_auto_deleter(yy_auto_deleter &&) = delete; 106 | yy_auto_deleter &operator=(const yy_auto_deleter &) = delete; 107 | yy_auto_deleter &operator=(yy_auto_deleter &&) = delete; 108 | 109 | ~yy_auto_deleter() { 110 | if (enaged) yy_destructor(ref); 111 | } 112 | void cancel() { enaged = false; } 113 | 114 | private: 115 | T& ref; 116 | bool enaged=false; 117 | }; 118 | 119 | template 120 | class yy_storage { 121 | private: 122 | typedef typename yy_fix_type::type TT; 123 | 124 | public: 125 | typedef typename std::conditional< 126 | std::is_trivial::value, 127 | TT, 128 | typename std::aligned_storage::type 129 | >::type type; 130 | }; 131 | 132 | } 133 | 134 | /************ Begin %include sections from the grammar ************************/ 135 | %% 136 | /**************** End of %include directives **********************************/ 137 | /* These constants specify the various numeric values for terminal symbols 138 | ** in a format understandable to "makeheaders". This section is blank unless 139 | ** "lemon" is run with the "-m" command-line option. 140 | ***************** Begin makeheaders token definitions *************************/ 141 | %% 142 | /**************** End makeheaders token definitions ***************************/ 143 | 144 | /* The next sections is a series of control #defines. 145 | ** various aspects of the generated parser. 146 | ** YYCODETYPE is the data type used to store the integer codes 147 | ** that represent terminal and non-terminal symbols. 148 | ** "unsigned char" is used if there are fewer than 149 | ** 256 symbols. Larger types otherwise. 150 | ** YYNOCODE is a number of type YYCODETYPE that is not used for 151 | ** any terminal or nonterminal symbol. 152 | ** YYFALLBACK If defined, this indicates that one or more tokens 153 | ** (also known as: "terminal symbols") have fall-back 154 | ** values which should be used if the original symbol 155 | ** would not parse. This permits keywords to sometimes 156 | ** be used as identifiers, for example. 157 | ** YYACTIONTYPE is the data type used for "action codes" - numbers 158 | ** that indicate what to do in response to the next 159 | ** token. 160 | ** ParseTOKENTYPE is the data type used for minor type for terminal 161 | ** symbols. Background: A "minor type" is a semantic 162 | ** value associated with a terminal or non-terminal 163 | ** symbols. For example, for an "ID" terminal symbol, 164 | ** the minor type might be the name of the identifier. 165 | ** Each non-terminal can have a different minor type. 166 | ** Terminal symbols all have the same minor type, though. 167 | ** This macros defines the minor type for terminal 168 | ** symbols. 169 | ** YYMINORTYPE is the data type used for all minor types. 170 | ** This is typically a union of many types, one of 171 | ** which is ParseTOKENTYPE. The entry in the union 172 | ** for terminal symbols is called "yy0". 173 | ** YYSTACKDEPTH is the maximum depth of the parser's stack. If 174 | ** zero the stack is dynamically sized using realloc() 175 | ** ParseARG_SDECL A static variable declaration for the %extra_argument 176 | ** ParseARG_PDECL A parameter declaration for the %extra_argument 177 | ** ParseARG_PARAM Code to pass %extra_argument as a subroutine parameter 178 | ** ParseARG_STORE Code to store %extra_argument into yypParser 179 | ** ParseARG_FETCH Code to extract %extra_argument from yypParser 180 | ** ParseCTX_* As ParseARG_ except for %extra_context 181 | ** YYERRORSYMBOL is the code number of the error symbol. If not 182 | ** defined, then do no error processing. 183 | ** YYNSTATE the combined number of states. 184 | ** YYNRULE the number of rules in the grammar 185 | ** YYNTOKEN Number of terminal symbols 186 | ** YY_MAX_SHIFT Maximum value for shift actions 187 | ** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions 188 | ** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions 189 | ** YY_ERROR_ACTION The yy_action[] code for syntax error 190 | ** YY_ACCEPT_ACTION The yy_action[] code for accept 191 | ** YY_NO_ACTION The yy_action[] code for no-op 192 | ** YY_MIN_REDUCE Minimum value for reduce actions 193 | ** YY_MAX_REDUCE Maximum value for reduce actions 194 | */ 195 | #ifndef INTERFACE 196 | # define INTERFACE 1 197 | #endif 198 | /************* Begin control #defines *****************************************/ 199 | %% 200 | /************* End control #defines *******************************************/ 201 | #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) 202 | 203 | namespace { 204 | 205 | /* Define the yytestcase() macro to be a no-op if is not already defined 206 | ** otherwise. 207 | ** 208 | ** Applications can choose to define yytestcase() in the %include section 209 | ** to a macro that can assist in verifying code coverage. For production 210 | ** code the yytestcase() macro should be turned off. But it is useful 211 | ** for testing. 212 | */ 213 | #ifndef yytestcase 214 | # define yytestcase(X) 215 | #endif 216 | 217 | 218 | /* Next are the tables used to determine what action to take based on the 219 | ** current state and lookahead token. These tables are used to implement 220 | ** functions that take a state number and lookahead value and return an 221 | ** action integer. 222 | ** 223 | ** Suppose the action integer is N. Then the action is determined as 224 | ** follows 225 | ** 226 | ** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead 227 | ** token onto the stack and goto state N. 228 | ** 229 | ** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then 230 | ** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. 231 | ** 232 | ** N == YY_ERROR_ACTION A syntax error has occurred. 233 | ** 234 | ** N == YY_ACCEPT_ACTION The parser accepts its input. 235 | ** 236 | ** N == YY_NO_ACTION No such action. Denotes unused 237 | ** slots in the yy_action[] table. 238 | ** 239 | ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE 240 | ** and YY_MAX_REDUCE 241 | ** 242 | ** The action table is constructed as a single large table named yy_action[]. 243 | ** Given state S and lookahead X, the action is computed as either: 244 | ** 245 | ** (A) N = yy_action[ yy_shift_ofst[S] + X ] 246 | ** (B) N = yy_default[S] 247 | ** 248 | ** The (A) formula is preferred. The B formula is used instead if 249 | ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X. 250 | ** 251 | ** The formulas above are for computing the action when the lookahead is 252 | ** a terminal symbol. If the lookahead is a non-terminal (as occurs after 253 | ** a reduce action) then the yy_reduce_ofst[] array is used in place of 254 | ** the yy_shift_ofst[] array. 255 | ** 256 | ** The following are the tables generated in this section: 257 | ** 258 | ** yy_action[] A single table containing all actions. 259 | ** yy_lookahead[] A table containing the lookahead for each entry in 260 | ** yy_action. Used to detect hash collisions. 261 | ** yy_shift_ofst[] For each state, the offset into yy_action for 262 | ** shifting terminals. 263 | ** yy_reduce_ofst[] For each state, the offset into yy_action for 264 | ** shifting non-terminals after a reduce. 265 | ** yy_default[] Default action for each state. 266 | ** 267 | *********** Begin parsing tables **********************************************/ 268 | %% 269 | /********** End of lemon-generated parsing tables *****************************/ 270 | 271 | /* The next table maps tokens (terminal symbols) into fallback tokens. 272 | ** If a construct like the following: 273 | ** 274 | ** %fallback ID X Y Z. 275 | ** 276 | ** appears in the grammar, then ID becomes a fallback token for X, Y, 277 | ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser 278 | ** but it does not parse, the type of the token is changed to ID and 279 | ** the parse is retried before an error is thrown. 280 | ** 281 | ** This feature can be used, for example, to cause some keywords in a language 282 | ** to revert to identifiers if they keyword does not apply in the context where 283 | ** it appears. 284 | */ 285 | #ifdef YYFALLBACK 286 | static const YYCODETYPE yyFallback[] = { 287 | %% 288 | }; 289 | #endif /* YYFALLBACK */ 290 | 291 | /* The following structure represents a single element of the 292 | ** parser's stack. Information stored includes: 293 | ** 294 | ** + The state number for the parser at this level of the stack. 295 | ** 296 | ** + The value of the token stored at this level of the stack. 297 | ** (In other words, the "major" token.) 298 | ** 299 | ** + The semantic value stored at this level of the stack. This is 300 | ** the information used by the action routines in the grammar. 301 | ** It is sometimes called the "minor" token. 302 | ** 303 | ** After the "shift" half of a SHIFTREDUCE action, the stateno field 304 | ** actually contains the reduce action for the second half of the 305 | ** SHIFTREDUCE. 306 | */ 307 | struct yyStackEntry { 308 | YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ 309 | YYCODETYPE major; /* The major token value. This is the code 310 | ** number for the token at this stack level */ 311 | YYMINORTYPE minor; /* The user-supplied minor token value. This 312 | ** is the value of the token */ 313 | }; 314 | 315 | /* The state of the parser is completely contained in an instance of 316 | ** the following structure */ 317 | 318 | #ifndef LEMON_SUPER 319 | #error "LEMON_SUPER must be defined." 320 | #endif 321 | 322 | /* outside the class so the templates above are still accessible */ 323 | void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor); 324 | void yy_move(YYCODETYPE yymajor, YYMINORTYPE *yyDest, YYMINORTYPE *yySource); 325 | 326 | class yypParser : public LEMON_SUPER { 327 | public: 328 | //using LEMON_SUPER::LEMON_SUPER; 329 | 330 | template 331 | yypParser(Args&&... args); 332 | 333 | virtual ~yypParser() override final; 334 | virtual void parse(int, ParseTOKENTYPE &&) override final; 335 | 336 | #ifndef NDEBUG 337 | virtual void trace(FILE *, const char *) final override; 338 | #endif 339 | 340 | virtual void reset() final override; 341 | virtual bool will_accept() const final override; 342 | virtual bool fallback(int iToken) const final override; 343 | /* 344 | ** Return the peak depth of the stack for a parser. 345 | */ 346 | #ifdef YYTRACKMAXSTACKDEPTH 347 | int yypParser::stack_peak(){ 348 | return yyhwm; 349 | } 350 | #endif 351 | 352 | #ifdef YYCOVERAGE 353 | int coverage(FILE *out); 354 | #endif 355 | 356 | const yyStackEntry *begin() const { return yystack; } 357 | const yyStackEntry *end() const { return yytos + 1; } 358 | 359 | protected: 360 | private: 361 | yyStackEntry *yytos; /* Pointer to top element of the stack */ 362 | #ifdef YYTRACKMAXSTACKDEPTH 363 | int yyhwm = 0; /* Maximum value of yyidx */ 364 | #endif 365 | #ifndef YYNOERRORRECOVERY 366 | int yyerrcnt = -1; /* Shifts left before out of the error */ 367 | #endif 368 | #if YYSTACKDEPTH<=0 369 | int yystksz = 0; /* Current side of the stack */ 370 | yyStackEntry *yystack = nullptr; /* The parser's stack */ 371 | yyStackEntry yystk0; /* First stack entry */ 372 | int yyGrowStack(); 373 | #else 374 | yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ 375 | yyStackEntry *yystackEnd; /* Last entry in the stack */ 376 | #endif 377 | 378 | 379 | 380 | void yy_accept(); 381 | void yy_parse_failed(); 382 | void yy_syntax_error(int yymajor, ParseTOKENTYPE &yyminor); 383 | 384 | void yy_transfer(yyStackEntry *yySource, yyStackEntry *yyDest); 385 | 386 | void yy_pop_parser_stack(); 387 | YYACTIONTYPE yy_find_shift_action(YYCODETYPE iLookAhead, YYACTIONTYPE stateno) const; 388 | YYACTIONTYPE yy_find_reduce_action(YYACTIONTYPE stateno, YYCODETYPE iLookAhead) const; 389 | 390 | void yy_shift(YYACTIONTYPE yyNewState, YYCODETYPE yyMajor, ParseTOKENTYPE &&yypMinor); 391 | YYACTIONTYPE yy_reduce(unsigned int yyruleno, int yyLookahead); 392 | void yyStackOverflow(); 393 | 394 | #ifndef NDEBUG 395 | void yyTraceShift(int yyNewState, const char *zTag) const; 396 | #else 397 | # define yyTraceShift(X,Y) 398 | #endif 399 | 400 | #ifdef YYCOVERAGE 401 | mutable unsigned char yycoverage[YYNSTATE][YYNTOKEN] = {}; 402 | #endif 403 | 404 | #ifndef NDEBUG 405 | FILE *yyTraceFILE = 0; 406 | const char *yyTracePrompt = 0; 407 | #endif /* NDEBUG */ 408 | 409 | int yyidx() const { 410 | return (int)(yytos - yystack); 411 | } 412 | 413 | }; 414 | 415 | 416 | 417 | 418 | #ifndef NDEBUG 419 | /* 420 | ** Turn parser tracing on by giving a stream to which to write the trace 421 | ** and a prompt to preface each trace message. Tracing is turned off 422 | ** by making either argument NULL 423 | ** 424 | ** Inputs: 425 | **
    426 | **
  • A FILE* to which trace output should be written. 427 | ** If NULL, then tracing is turned off. 428 | **
  • A prefix string written at the beginning of every 429 | ** line of trace output. If NULL, then tracing is 430 | ** turned off. 431 | **
432 | ** 433 | ** Outputs: 434 | ** None. 435 | */ 436 | void yypParser::trace(FILE *TraceFILE, const char *zTracePrompt){ 437 | yyTraceFILE = TraceFILE; 438 | yyTracePrompt = zTracePrompt; 439 | if( yyTraceFILE==0 ) yyTracePrompt = 0; 440 | else if( yyTracePrompt==0 ) yyTraceFILE = 0; 441 | } 442 | #endif /* NDEBUG */ 443 | 444 | #if defined(YYCOVERAGE) || !defined(NDEBUG) 445 | /* For tracing shifts, the names of all terminals and nonterminals 446 | ** are required. The following table supplies these names */ 447 | static const char *const yyTokenName[] = { 448 | %% 449 | }; 450 | #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ 451 | 452 | #ifndef NDEBUG 453 | /* For tracing reduce actions, the names of all rules are required. 454 | */ 455 | const char *const yyRuleName[] = { 456 | %% 457 | }; 458 | #endif /* NDEBUG */ 459 | 460 | 461 | #if YYSTACKDEPTH<=0 462 | /* 463 | ** Try to increase the size of the parser stack. Return the number 464 | ** of errors. Return 0 on success. 465 | */ 466 | int yypParser::yyGrowStack(){ 467 | int newSize; 468 | yyStackEntry *pNew; 469 | yyStackEntry *pOld = yystack; 470 | int oldSize = yystksz; 471 | 472 | newSize = oldSize*2 + 100; 473 | pNew = (yyStackEntry *)calloc(newSize, sizeof(pNew[0])); 474 | if( pNew ){ 475 | yystack = pNew; 476 | for (int i = 0; i < oldSize; ++i) { 477 | pNew[i].stateno = pOld[i].stateno; 478 | pNew[i].major = pOld[i].major; 479 | yy_move(pOld[i].major, &pNew[i].minor, &pOld[i].minor); 480 | } 481 | if (pOld != &yystk0) free(pOld); 482 | #ifndef NDEBUG 483 | if( yyTraceFILE ){ 484 | fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", 485 | yyTracePrompt, yystksz, newSize); 486 | } 487 | #endif 488 | yystksz = newSize; 489 | } 490 | return pNew==0; 491 | } 492 | #endif 493 | 494 | 495 | /* The following function deletes the "minor type" or semantic value 496 | ** associated with a symbol. The symbol can be either a terminal 497 | ** or nonterminal. "yymajor" is the symbol code, and "yypminor" is 498 | ** a pointer to the value to be deleted. The code used to do the 499 | ** deletions is derived from the %destructor and/or %token_destructor 500 | ** directives of the input grammar. 501 | */ 502 | void yy_destructor( 503 | YYCODETYPE yymajor, /* Type code for object to destroy */ 504 | YYMINORTYPE *yypminor /* The object to be destroyed */ 505 | ){ 506 | switch( yymajor ){ 507 | /* Here is inserted the actions which take place when a 508 | ** terminal or non-terminal is destroyed. This can happen 509 | ** when the symbol is popped from the stack during a 510 | ** reduce or during error processing or when a parser is 511 | ** being destroyed before it is finished parsing. 512 | ** 513 | ** Note: during a reduce, the only symbols destroyed are those 514 | ** which appear on the RHS of the rule, but which are *not* used 515 | ** inside the C code. 516 | */ 517 | /********* Begin destructor definitions ***************************************/ 518 | %% 519 | /********* End destructor definitions *****************************************/ 520 | default: break; /* If no destructor action specified: do nothing */ 521 | } 522 | } 523 | 524 | 525 | /* 526 | * moves an object (such as when growing the stack). 527 | * Source is constructed. 528 | * Destination is also destructed. 529 | * 530 | */ 531 | void yy_move( 532 | YYCODETYPE yymajor, /* Type code for object to move */ 533 | YYMINORTYPE *yyDest, /* */ 534 | YYMINORTYPE *yySource /* */ 535 | ){ 536 | switch( yymajor ){ 537 | 538 | /********* Begin move definitions ***************************************/ 539 | %% 540 | /********* End move definitions *****************************************/ 541 | default: break; /* If no move action specified: do nothing */ 542 | //yyDest.minor = yySource.minor; 543 | } 544 | } 545 | 546 | 547 | /* 548 | ** Pop the parser's stack once. 549 | ** 550 | ** If there is a destructor routine associated with the token which 551 | ** is popped from the stack, then call it. 552 | */ 553 | void yypParser::yy_pop_parser_stack(){ 554 | yyStackEntry *yymsp; 555 | assert( yytos!=0 ); 556 | assert( yytos > yystack ); 557 | yymsp = yytos--; 558 | #ifndef NDEBUG 559 | if( yyTraceFILE ){ 560 | fprintf(yyTraceFILE,"%sPopping %s\n", 561 | yyTracePrompt, 562 | yyTokenName[yymsp->major]); 563 | } 564 | #endif 565 | yy_destructor(yymsp->major, &yymsp->minor); 566 | } 567 | 568 | 569 | template 570 | yypParser::yypParser(Args&&... args) : LEMON_SUPER(std::forward(args)...) 571 | { 572 | #if YYSTACKDEPTH<=0 573 | if( yyGrowStack() ){ 574 | yystack = &yystk0; 575 | yystksz = 1; 576 | } 577 | #else 578 | std::memset(yystack, 0, sizeof(yystack)); 579 | #endif 580 | 581 | yytos = yystack; 582 | yystack[0].stateno = 0; 583 | yystack[0].major = 0; 584 | #if YYSTACKDEPTH>0 585 | yystackEnd = &yystack[YYSTACKDEPTH-1]; 586 | #endif 587 | } 588 | 589 | void yypParser::reset() { 590 | 591 | while( yytos>yystack ) yy_pop_parser_stack(); 592 | 593 | #ifndef YYNOERRORRECOVERY 594 | yyerrcnt = -1; 595 | #endif 596 | 597 | yytos = yystack; 598 | yystack[0].stateno = 0; 599 | yystack[0].major = 0; 600 | 601 | LEMON_SUPER::reset(); 602 | } 603 | 604 | 605 | /* 606 | ** Deallocate and destroy a parser. Destructors are called for 607 | ** all stack elements before shutting the parser down. 608 | ** 609 | ** If the YYPARSEFREENEVERNULL macro exists (for example because it 610 | ** is defined in a %include section of the input grammar) then it is 611 | ** assumed that the input pointer is never NULL. 612 | */ 613 | 614 | yypParser::~yypParser() { 615 | while( yytos>yystack ) yy_pop_parser_stack(); 616 | #if YYSTACKDEPTH<=0 617 | if( yystack!=&yystk0 ) free(yystack); 618 | #endif 619 | } 620 | 621 | 622 | /* 623 | ** Write into out a description of every state/lookahead combination that 624 | ** 625 | ** (1) has not been used by the parser, and 626 | ** (2) is not a syntax error. 627 | ** 628 | ** Return the number of missed state/lookahead combinations. 629 | */ 630 | #if defined(YYCOVERAGE) 631 | int yypParser::coverage(FILE *out){ 632 | int stateno, iLookAhead, i; 633 | int nMissed = 0; 634 | for(stateno=0; statenoYY_MAX_SHIFT ) return stateno; 661 | assert( stateno <= YY_SHIFT_COUNT ); 662 | #if defined(YYCOVERAGE) 663 | yycoverage[stateno][iLookAhead] = 1; 664 | #endif 665 | do{ 666 | i = yy_shift_ofst[stateno]; 667 | assert( i>=0 ); 668 | /* assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); */ 669 | assert( iLookAhead!=YYNOCODE ); 670 | assert( iLookAhead < YYNTOKEN ); 671 | i += iLookAhead; 672 | if( i>=YY_NLOOKAHEAD || yy_lookahead[i]!=iLookAhead ){ 673 | #ifdef YYFALLBACK 674 | YYCODETYPE iFallback; /* Fallback token */ 675 | if( iLookAhead %s\n", 680 | yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); 681 | } 682 | #endif 683 | assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ 684 | iLookAhead = iFallback; 685 | continue; 686 | } 687 | #endif 688 | #ifdef YYWILDCARD 689 | { 690 | int j = i - iLookAhead + YYWILDCARD; 691 | if( 692 | #if YY_SHIFT_MIN+YYWILDCARD<0 693 | j>=0 && 694 | #endif 695 | #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT 696 | j0 700 | ){ 701 | #ifndef NDEBUG 702 | if( yyTraceFILE ){ 703 | fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", 704 | yyTracePrompt, yyTokenName[iLookAhead], 705 | yyTokenName[YYWILDCARD]); 706 | } 707 | #endif /* NDEBUG */ 708 | return yy_action[j]; 709 | } 710 | } 711 | #endif /* YYWILDCARD */ 712 | return yy_default[stateno]; 713 | }else{ 714 | return yy_action[i]; 715 | } 716 | }while(1); 717 | } 718 | 719 | /* 720 | ** Find the appropriate action for a parser given the non-terminal 721 | ** look-ahead token iLookAhead. 722 | */ 723 | YYACTIONTYPE yypParser::yy_find_reduce_action( 724 | YYACTIONTYPE stateno, /* Current state number */ 725 | YYCODETYPE iLookAhead /* The look-ahead token */ 726 | ) const { 727 | int i; 728 | #ifdef YYERRORSYMBOL 729 | if( stateno>YY_REDUCE_COUNT ){ 730 | return yy_default[stateno]; 731 | } 732 | #else 733 | assert( stateno<=YY_REDUCE_COUNT ); 734 | #endif 735 | i = yy_reduce_ofst[stateno]; 736 | assert( iLookAhead!=YYNOCODE ); 737 | i += iLookAhead; 738 | #ifdef YYERRORSYMBOL 739 | if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ 740 | return yy_default[stateno]; 741 | } 742 | #else 743 | assert( i>=0 && iyystack ) yy_pop_parser_stack(); 759 | /* Here code is inserted which will execute if the parser 760 | ** stack every overflows */ 761 | /******** Begin %stack_overflow code ******************************************/ 762 | %% 763 | /******** End %stack_overflow code ********************************************/ 764 | LEMON_SUPER::stack_overflow(); 765 | } 766 | 767 | /* 768 | ** Print tracing information for a SHIFT action 769 | */ 770 | #ifndef NDEBUG 771 | void yypParser::yyTraceShift(int yyNewState, const char *zTag) const { 772 | if( yyTraceFILE ){ 773 | if( yyNewStateyytos->major], 776 | yyNewState); 777 | }else{ 778 | fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n", 779 | yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major], 780 | yyNewState - YY_MIN_REDUCE); 781 | } 782 | } 783 | } 784 | #endif 785 | 786 | /* 787 | ** Perform a shift action. 788 | */ 789 | void yypParser::yy_shift( 790 | YYACTIONTYPE yyNewState, /* The new state to shift in */ 791 | YYCODETYPE yyMajor, /* The major token to shift in */ 792 | ParseTOKENTYPE &&yyMinor /* The minor token to shift in */ 793 | ){ 794 | yytos++; 795 | #ifdef YYTRACKMAXSTACKDEPTH 796 | if( yyidx()>yyhwm ){ 797 | yyhwm++; 798 | assert(yyhwm == yyidx()); 799 | } 800 | #endif 801 | #if YYSTACKDEPTH>0 802 | if( yytos>yystackEnd ){ 803 | yytos--; 804 | yyStackOverflow(); 805 | return; 806 | } 807 | #else 808 | if( yytos>=&yystack[yystksz] ){ 809 | if( yyGrowStack() ){ 810 | yytos--; 811 | yyStackOverflow(); 812 | return; 813 | } 814 | } 815 | #endif 816 | if( yyNewState > YY_MAX_SHIFT ){ 817 | yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; 818 | } 819 | yytos->stateno = yyNewState; 820 | yytos->major = yyMajor; 821 | //yytos->minor.yy0 = yyMinor; 822 | //yy_move also calls the destructor... 823 | //yy_move(std::addressof(yytos->minor.yy0), std::addressof(yyMinor)); 824 | yy_constructor(std::addressof(yytos->minor.yy0), std::move(yyMinor)); 825 | yyTraceShift(yyNewState, "Shift"); 826 | } 827 | 828 | /* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side 829 | ** of that rule */ 830 | static const YYCODETYPE yyRuleInfoLhs[] = { 831 | %% 832 | }; 833 | 834 | /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number 835 | ** of symbols on the right-hand side of that rule. */ 836 | static const signed char yyRuleInfoNRhs[] = { 837 | %% 838 | }; 839 | 840 | /* 841 | ** Perform a reduce action and the shift that must immediately 842 | ** follow the reduce. 843 | */ 844 | YYACTIONTYPE yypParser::yy_reduce( 845 | unsigned int yyruleno, /* Number of the rule by which to reduce */ 846 | int yyLookahead /* Lookahead token, or YYNOCODE if none */ 847 | ){ 848 | int yygoto; /* The next state */ 849 | YYACTIONTYPE yyact; /* The next action */ 850 | yyStackEntry *yymsp; /* The top of the parser's stack */ 851 | int yysize; /* Amount to pop the stack */ 852 | yymsp = yytos; 853 | #ifndef NDEBUG 854 | if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ 855 | yysize = yyRuleInfoNRhs[yyruleno]; 856 | if( yysize ){ 857 | fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n", 858 | yyTracePrompt, 859 | yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno); 860 | }else{ 861 | fprintf(yyTraceFILE, "%sReduce %d [%s].\n", 862 | yyTracePrompt, yyruleno, yyRuleName[yyruleno]); 863 | } 864 | } 865 | #endif /* NDEBUG */ 866 | 867 | /* Check that the stack is large enough to grow by a single entry 868 | ** if the RHS of the rule is empty. This ensures that there is room 869 | ** enough on the stack to push the LHS value */ 870 | if( yyRuleInfoNRhs[yyruleno]==0 ){ 871 | #ifdef YYTRACKMAXSTACKDEPTH 872 | if( yyidx()>yyhwm ){ 873 | yyhwm++; 874 | assert(yyhwm == yyidx()); 875 | } 876 | #endif 877 | #if YYSTACKDEPTH>0 878 | if( yytos>=yystackEnd ){ 879 | yyStackOverflow(); 880 | /* The call to yyStackOverflow() above pops the stack until it is 881 | ** empty, causing the main parser loop to exit. So the return value 882 | ** is never used and does not matter. */ 883 | return; 884 | } 885 | #else 886 | if( yytos>=&yystack[yystksz-1] ){ 887 | if( yyGrowStack() ){ 888 | yyStackOverflow(); 889 | /* The call to yyStackOverflow() above pops the stack until it is 890 | ** empty, causing the main parser loop to exit. So the return value 891 | ** is never used and does not matter. */ 892 | return 0; 893 | } 894 | yymsp = yytos; 895 | } 896 | #endif 897 | } 898 | 899 | switch( yyruleno ){ 900 | /* Beginning here are the reduction cases. A typical example 901 | ** follows: 902 | ** case 0: 903 | ** #line 904 | ** { ... } // User supplied code 905 | ** #line 906 | ** break; 907 | */ 908 | /********** Begin reduce actions **********************************************/ 909 | %% 910 | /********** End reduce actions ************************************************/ 911 | }; 912 | assert( yyrulenoYY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); 920 | 921 | /* It is not possible for a REDUCE to be followed by an error */ 922 | assert( yyact!=YY_ERROR_ACTION ); 923 | 924 | yymsp += yysize+1; 925 | yytos = yymsp; 926 | yymsp->stateno = (YYACTIONTYPE)yyact; 927 | yymsp->major = (YYCODETYPE)yygoto; 928 | yyTraceShift(yyact, "... then shift"); 929 | return yyact; 930 | } 931 | 932 | /* 933 | ** The following code executes when the parse fails 934 | */ 935 | #ifndef YYNOERRORRECOVERY 936 | void yypParser::yy_parse_failed(){ 937 | #ifndef NDEBUG 938 | if( yyTraceFILE ){ 939 | fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); 940 | } 941 | #endif 942 | while( yytos>yystack ) yy_pop_parser_stack(); 943 | /* Here code is inserted which will be executed whenever the 944 | ** parser fails */ 945 | /************ Begin %parse_failure code ***************************************/ 946 | %% 947 | /************ End %parse_failure code *****************************************/ 948 | LEMON_SUPER::parse_failure(); 949 | } 950 | #endif /* YYNOERRORRECOVERY */ 951 | 952 | /* 953 | ** The following code executes when a syntax error first occurs. 954 | */ 955 | void yypParser::yy_syntax_error( 956 | int yymajor, /* The major type of the error token */ 957 | ParseTOKENTYPE &yyminor /* The minor type of the error token */ 958 | ){ 959 | //#define TOKEN yyminor 960 | auto &TOKEN = yyminor; 961 | /************ Begin %syntax_error code ****************************************/ 962 | %% 963 | /************ End %syntax_error code ******************************************/ 964 | LEMON_SUPER::syntax_error(yymajor, TOKEN); 965 | } 966 | 967 | /* 968 | ** The following is executed when the parser accepts 969 | */ 970 | void yypParser::yy_accept(){ 971 | #ifndef NDEBUG 972 | if( yyTraceFILE ){ 973 | fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); 974 | } 975 | #endif 976 | #ifndef YYNOERRORRECOVERY 977 | yyerrcnt = -1; 978 | #endif 979 | assert( yytos==yystack ); 980 | /* Here code is inserted which will be executed whenever the 981 | ** parser accepts */ 982 | /*********** Begin %parse_accept code *****************************************/ 983 | %% 984 | /*********** End %parse_accept code *******************************************/ 985 | LEMON_SUPER::parse_accept(); 986 | } 987 | 988 | /* The main parser program. 989 | ** The first argument is a pointer to a structure obtained from 990 | ** "ParseAlloc" which describes the current state of the parser. 991 | ** The second argument is the major token number. The third is 992 | ** the minor token. The fourth optional argument is whatever the 993 | ** user wants (and specified in the grammar) and is available for 994 | ** use by the action routines. 995 | ** 996 | ** Inputs: 997 | **
    998 | **
  • A pointer to the parser (an opaque structure.) 999 | **
  • The major token number. 1000 | **
  • The minor token number. 1001 | **
  • An option argument of a grammar-specified type. 1002 | **
1003 | ** 1004 | ** Outputs: 1005 | ** None. 1006 | */ 1007 | 1008 | 1009 | 1010 | void yypParser::parse( 1011 | int yymajor, /* The major token code number */ 1012 | ParseTOKENTYPE &&yyminor /* The value for the token */ 1013 | ){ 1014 | //YYMINORTYPE yyminorunion; 1015 | YYACTIONTYPE yyact; /* The parser action. */ 1016 | #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 1017 | int yyendofinput; /* True if we are at the end of input */ 1018 | #endif 1019 | #ifdef YYERRORSYMBOL 1020 | int yyerrorhit = 0; /* True if yymajor has invoked an error */ 1021 | #endif 1022 | 1023 | assert( yytos!=0 ); 1024 | #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 1025 | yyendofinput = (yymajor==0); 1026 | #endif 1027 | 1028 | yyact = yytos->stateno; 1029 | #ifndef NDEBUG 1030 | if( yyTraceFILE ){ 1031 | if( yyact < YY_MIN_REDUCE ){ 1032 | fprintf(yyTraceFILE,"%sInput '%s' in state %d\n", 1033 | yyTracePrompt,yyTokenName[yymajor],yyact); 1034 | }else{ 1035 | fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", 1036 | yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); 1037 | } 1038 | } 1039 | #endif 1040 | 1041 | do{ 1042 | assert( yyact==yytos->stateno ); 1043 | yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); 1044 | if( yyact >= YY_MIN_REDUCE ){ 1045 | yyact = yy_reduce(yyact-YY_MIN_REDUCE,yymajor, 1046 | yyminor ParseCTX_PARAM); 1047 | }else if( yyact <= YY_MAX_SHIFTREDUCE ){ 1048 | yy_shift(yyact,(YYCODETYPE)yymajor,yyminor); 1049 | #ifndef YYNOERRORRECOVERY 1050 | yyerrcnt--; 1051 | #endif 1052 | break; 1053 | }else if( yyact==YY_ACCEPT_ACTION ){ 1054 | yytos--; 1055 | yy_accept(); 1056 | return; 1057 | }else{ 1058 | assert( yyact == YY_ERROR_ACTION ); 1059 | yyminorunion.yy0 = yyminor; 1060 | #ifdef YYERRORSYMBOL 1061 | int yymx; 1062 | #endif 1063 | #ifndef NDEBUG 1064 | if( yyTraceFILE ){ 1065 | fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); 1066 | } 1067 | #endif 1068 | #ifdef YYERRORSYMBOL 1069 | /* A syntax error has occurred. 1070 | ** The response to an error depends upon whether or not the 1071 | ** grammar defines an error token "ERROR". 1072 | ** 1073 | ** This is what we do if the grammar does define ERROR: 1074 | ** 1075 | ** * Call the %syntax_error function. 1076 | ** 1077 | ** * Begin popping the stack until we enter a state where 1078 | ** it is legal to shift the error symbol, then shift 1079 | ** the error symbol. 1080 | ** 1081 | ** * Set the error count to three. 1082 | ** 1083 | ** * Begin accepting and shifting new tokens. No new error 1084 | ** processing will occur until three tokens have been 1085 | ** shifted successfully. 1086 | ** 1087 | */ 1088 | if( yyerrcnt<0 ){ 1089 | yy_syntax_error(yymajor,yyminor); 1090 | } 1091 | yymx = yytos->major; 1092 | if( yymx==YYERRORSYMBOL || yyerrorhit ){ 1093 | #ifndef NDEBUG 1094 | if( yyTraceFILE ){ 1095 | fprintf(yyTraceFILE,"%sDiscard input token %s\n", 1096 | yyTracePrompt,yyTokenName[yymajor]); 1097 | } 1098 | #endif 1099 | //yy_destructor(yyminor); 1100 | yymajor = YYNOCODE; 1101 | }else{ 1102 | while( yytos >= yystack 1103 | && (yyact = yy_find_reduce_action( 1104 | yytos->stateno, 1105 | YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE 1106 | ){ 1107 | yy_pop_parser_stack(); 1108 | } 1109 | if( yytos < yystack || yymajor==0 ){ 1110 | //yy_destructor(yyminor); 1111 | yy_parse_failed(); 1112 | #ifndef YYNOERRORRECOVERY 1113 | yyerrcnt = -1; 1114 | #endif 1115 | yymajor = YYNOCODE; 1116 | }else if( yymx!=YYERRORSYMBOL ){ 1117 | yy_shift(yyact,YYERRORSYMBOL,std::move(yyminor)); 1118 | } 1119 | } 1120 | yyerrcnt = 3; 1121 | yyerrorhit = 1; 1122 | if( yymajor==YYNOCODE ) break; 1123 | yyact = yytos->stateno; 1124 | #elif defined(YYNOERRORRECOVERY) 1125 | /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to 1126 | ** do any kind of error recovery. Instead, simply invoke the syntax 1127 | ** error routine and continue going as if nothing had happened. 1128 | ** 1129 | ** Applications can set this macro (for example inside %include) if 1130 | ** they intend to abandon the parse upon the first syntax error seen. 1131 | */ 1132 | yy_syntax_error(yymajor,yyminor); 1133 | //yy_destructor(yyminor); 1134 | break; 1135 | 1136 | #else /* YYERRORSYMBOL is not defined */ 1137 | /* This is what we do if the grammar does not define ERROR: 1138 | ** 1139 | ** * Report an error message, and throw away the input token. 1140 | ** 1141 | ** * If the input token is $, then fail the parse. 1142 | ** 1143 | ** As before, subsequent error messages are suppressed until 1144 | ** three input tokens have been successfully shifted. 1145 | */ 1146 | if( yyerrcnt<=0 ){ 1147 | yy_syntax_error(yymajor,yyminor); 1148 | } 1149 | yyerrcnt = 3; 1150 | //yy_destructor(yyminor); 1151 | if( yyendofinput ){ 1152 | yy_parse_failed(); 1153 | #ifndef YYNOERRORRECOVERY 1154 | yyerrcnt = -1; 1155 | #endif 1156 | } 1157 | break; 1158 | #endif 1159 | } 1160 | }while( yytos>yystack ); 1161 | #ifndef NDEBUG 1162 | if( yyTraceFILE ){ 1163 | yyStackEntry *i; 1164 | char cDiv = '['; 1165 | fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); 1166 | for(i=&yystack[1]; i<=yytos; i++){ 1167 | fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); 1168 | cDiv = ' '; 1169 | } 1170 | if (cDiv == '[') fprintf(yyTraceFILE,"["); 1171 | fprintf(yyTraceFILE,"]\n"); 1172 | } 1173 | #endif 1174 | return; 1175 | } 1176 | 1177 | 1178 | bool yypParser::will_accept() const { 1179 | 1180 | 1181 | struct stack_entry { 1182 | YYACTIONTYPE stateno; 1183 | YYCODETYPE major; 1184 | }; 1185 | 1186 | YYACTIONTYPE yyact; 1187 | const YYCODETYPE yymajor = 0; 1188 | ParseTOKENTYPE yyminor; 1189 | std::vector stack; 1190 | 1191 | 1192 | // copy stack to stack. 1193 | stack.reserve(yyidx()+1); 1194 | std::transform(begin(), end(), std::back_inserter(stack), [](const yyStackEntry &e){ 1195 | return stack_entry({e.stateno, e.major}); 1196 | }); 1197 | 1198 | do { 1199 | yyact = yy_find_shift_action(yymajor, stack.back().stateno); 1200 | 1201 | 1202 | if( yyact==YY_ACCEPT_ACTION ) return true; 1203 | if( yyact >= YY_MIN_REDUCE ){ 1204 | // reduce... 1205 | unsigned yyruleno = yyact - YY_MIN_REDUCE; 1206 | 1207 | YYCODETYPE yygoto = yyRuleInfoLhs[yyruleno]; 1208 | int yysize = -yyRuleInfoNRhs[yyruleno]; /* stored as negative value */ 1209 | 1210 | while (yysize--) stack.pop_back(); 1211 | 1212 | yyact = yy_find_reduce_action(stack.back().stateno, yygoto); 1213 | stack.push_back({yyact, yygoto}); 1214 | } 1215 | else { 1216 | return false; 1217 | } 1218 | 1219 | } while (!stack.empty()); 1220 | 1221 | return false; 1222 | 1223 | 1224 | } 1225 | 1226 | /* 1227 | ** Return the fallback token corresponding to canonical token iToken, or 1228 | ** 0 if iToken has no fallback. 1229 | */ 1230 | int yypParser::fallback(int iToken) const { 1231 | #ifdef YYFALLBACK 1232 | if( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ){ 1233 | return yyFallback[iToken]; 1234 | } 1235 | #else 1236 | (void)iToken; 1237 | #endif 1238 | return 0; 1239 | } 1240 | 1241 | 1242 | 1243 | } // namespace 1244 | -------------------------------------------------------------------------------- /lempar.cxx: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | January, 2016. Sample class-based version. 4 | #define LEMON_SUPER as the name of a class which overrides lemon_base. 5 | The parser will be implemented in terms of that. 6 | add a %code section to instantiate it. 7 | */ 8 | 9 | /* 10 | ** 2000-05-29 11 | ** 12 | ** The author disclaims copyright to this source code. In place of 13 | ** a legal notice, here is a blessing: 14 | ** 15 | ** May you do good and not evil. 16 | ** May you find forgiveness for yourself and forgive others. 17 | ** May you share freely, never taking more than you give. 18 | ** 19 | ************************************************************************* 20 | ** Driver template for the LEMON parser generator. 21 | ** 22 | ** The "lemon" program processes an LALR(1) input grammar file, then uses 23 | ** this template to construct a parser. The "lemon" program inserts text 24 | ** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the 25 | ** interstitial "-" characters) contained in this template is changed into 26 | ** the value of the %name directive from the grammar. Otherwise, the content 27 | ** of this template is copied straight through into the generate parser 28 | ** source file. 29 | ** 30 | ** The following is the concatenation of all %include directives from the 31 | ** input grammar file: 32 | */ 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | namespace { 43 | 44 | // use std::allocator etc? 45 | 46 | 47 | // this is here so you can do something like Parse(void *, int, my_token &&) or (... const my_token &) 48 | template struct yy_fix_type { 49 | typedef typename std::remove_const::type>::type type; 50 | }; 51 | 52 | template<> 53 | struct yy_fix_type { 54 | typedef struct {} type; 55 | }; 56 | 57 | template 58 | typename yy_fix_type::type &yy_constructor(void *vp, Args&&... args ) { 59 | typedef typename yy_fix_type::type TT; 60 | TT *tmp = ::new(vp) TT(std::forward(args)...); 61 | return *tmp; 62 | } 63 | 64 | 65 | template 66 | typename yy_fix_type::type &yy_cast(void *vp) { 67 | typedef typename yy_fix_type::type TT; 68 | return *(TT *)vp; 69 | } 70 | 71 | 72 | template 73 | void yy_destructor(void *vp) { 74 | typedef typename yy_fix_type::type TT; 75 | ((TT *)vp)->~TT(); 76 | } 77 | 78 | 79 | template 80 | void yy_destructor(T &t) { 81 | t.~T(); 82 | } 83 | 84 | 85 | 86 | template 87 | void yy_move(void *dest, void *src) { 88 | typedef typename yy_fix_type::type TT; 89 | 90 | TT &tmp = yy_cast(src); 91 | yy_constructor(dest, std::move(tmp)); 92 | yy_destructor(tmp); 93 | } 94 | 95 | 96 | // this is to destruct references in the event of an exception. 97 | // only the LHS needs to be deleted -- other items remain on the 98 | // shift/reduce stack in a valid state 99 | // (as long as the destructor) doesn't throw! 100 | template 101 | struct yy_auto_deleter { 102 | 103 | yy_auto_deleter(T &t) : ref(t), enaged(true) 104 | {} 105 | yy_auto_deleter(const yy_auto_deleter &) = delete; 106 | yy_auto_deleter(yy_auto_deleter &&) = delete; 107 | yy_auto_deleter &operator=(const yy_auto_deleter &) = delete; 108 | yy_auto_deleter &operator=(yy_auto_deleter &&) = delete; 109 | 110 | ~yy_auto_deleter() { 111 | if (enaged) yy_destructor(ref); 112 | } 113 | void cancel() { enaged = false; } 114 | 115 | private: 116 | T& ref; 117 | bool enaged=false; 118 | }; 119 | 120 | template 121 | class yy_storage { 122 | private: 123 | typedef typename yy_fix_type::type TT; 124 | 125 | public: 126 | typedef typename std::conditional< 127 | std::is_trivial::value, 128 | TT, 129 | typename std::aligned_storage::type 130 | >::type type; 131 | }; 132 | 133 | } 134 | 135 | /************ Begin %include sections from the grammar ************************/ 136 | %% 137 | /**************** End of %include directives **********************************/ 138 | /* These constants specify the various numeric values for terminal symbols 139 | ** in a format understandable to "makeheaders". This section is blank unless 140 | ** "lemon" is run with the "-m" command-line option. 141 | ***************** Begin makeheaders token definitions *************************/ 142 | %% 143 | /**************** End makeheaders token definitions ***************************/ 144 | 145 | /* The next sections is a series of control #defines. 146 | ** various aspects of the generated parser. 147 | ** YYCODETYPE is the data type used to store the integer codes 148 | ** that represent terminal and non-terminal symbols. 149 | ** "unsigned char" is used if there are fewer than 150 | ** 256 symbols. Larger types otherwise. 151 | ** YYNOCODE is a number of type YYCODETYPE that is not used for 152 | ** any terminal or nonterminal symbol. 153 | ** YYFALLBACK If defined, this indicates that one or more tokens 154 | ** (also known as: "terminal symbols") have fall-back 155 | ** values which should be used if the original symbol 156 | ** would not parse. This permits keywords to sometimes 157 | ** be used as identifiers, for example. 158 | ** YYACTIONTYPE is the data type used for "action codes" - numbers 159 | ** that indicate what to do in response to the next 160 | ** token. 161 | ** ParseTOKENTYPE is the data type used for minor type for terminal 162 | ** symbols. Background: A "minor type" is a semantic 163 | ** value associated with a terminal or non-terminal 164 | ** symbols. For example, for an "ID" terminal symbol, 165 | ** the minor type might be the name of the identifier. 166 | ** Each non-terminal can have a different minor type. 167 | ** Terminal symbols all have the same minor type, though. 168 | ** This macros defines the minor type for terminal 169 | ** symbols. 170 | ** YYMINORTYPE is the data type used for all minor types. 171 | ** This is typically a union of many types, one of 172 | ** which is ParseTOKENTYPE. The entry in the union 173 | ** for terminal symbols is called "yy0". 174 | ** YYSTACKDEPTH is the maximum depth of the parser's stack. If 175 | ** zero the stack is dynamically sized using realloc() 176 | ** ParseARG_SDECL A static variable declaration for the %extra_argument 177 | ** ParseARG_PDECL A parameter declaration for the %extra_argument 178 | ** ParseARG_PARAM Code to pass %extra_argument as a subroutine parameter 179 | ** ParseARG_STORE Code to store %extra_argument into yypParser 180 | ** ParseARG_FETCH Code to extract %extra_argument from yypParser 181 | ** ParseCTX_* As ParseARG_ except for %extra_context 182 | ** YYERRORSYMBOL is the code number of the error symbol. If not 183 | ** defined, then do no error processing. 184 | ** YYNSTATE the combined number of states. 185 | ** YYNRULE the number of rules in the grammar 186 | ** YYNTOKEN Number of terminal symbols 187 | ** YY_MAX_SHIFT Maximum value for shift actions 188 | ** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions 189 | ** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions 190 | ** YY_ERROR_ACTION The yy_action[] code for syntax error 191 | ** YY_ACCEPT_ACTION The yy_action[] code for accept 192 | ** YY_NO_ACTION The yy_action[] code for no-op 193 | ** YY_MIN_REDUCE Minimum value for reduce actions 194 | ** YY_MAX_REDUCE Maximum value for reduce actions 195 | */ 196 | #ifndef INTERFACE 197 | # define INTERFACE 1 198 | #endif 199 | /************* Begin control #defines *****************************************/ 200 | %% 201 | /************* End control #defines *******************************************/ 202 | #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) 203 | 204 | namespace { 205 | 206 | /* Define the yytestcase() macro to be a no-op if is not already defined 207 | ** otherwise. 208 | ** 209 | ** Applications can choose to define yytestcase() in the %include section 210 | ** to a macro that can assist in verifying code coverage. For production 211 | ** code the yytestcase() macro should be turned off. But it is useful 212 | ** for testing. 213 | */ 214 | #ifndef yytestcase 215 | # define yytestcase(X) 216 | #endif 217 | 218 | 219 | /* Next are the tables used to determine what action to take based on the 220 | ** current state and lookahead token. These tables are used to implement 221 | ** functions that take a state number and lookahead value and return an 222 | ** action integer. 223 | ** 224 | ** Suppose the action integer is N. Then the action is determined as 225 | ** follows 226 | ** 227 | ** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead 228 | ** token onto the stack and goto state N. 229 | ** 230 | ** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then 231 | ** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. 232 | ** 233 | ** N == YY_ERROR_ACTION A syntax error has occurred. 234 | ** 235 | ** N == YY_ACCEPT_ACTION The parser accepts its input. 236 | ** 237 | ** N == YY_NO_ACTION No such action. Denotes unused 238 | ** slots in the yy_action[] table. 239 | ** 240 | ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE 241 | ** and YY_MAX_REDUCE 242 | ** 243 | ** The action table is constructed as a single large table named yy_action[]. 244 | ** Given state S and lookahead X, the action is computed as either: 245 | ** 246 | ** (A) N = yy_action[ yy_shift_ofst[S] + X ] 247 | ** (B) N = yy_default[S] 248 | ** 249 | ** The (A) formula is preferred. The B formula is used instead if 250 | ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X. 251 | ** 252 | ** The formulas above are for computing the action when the lookahead is 253 | ** a terminal symbol. If the lookahead is a non-terminal (as occurs after 254 | ** a reduce action) then the yy_reduce_ofst[] array is used in place of 255 | ** the yy_shift_ofst[] array. 256 | ** 257 | ** The following are the tables generated in this section: 258 | ** 259 | ** yy_action[] A single table containing all actions. 260 | ** yy_lookahead[] A table containing the lookahead for each entry in 261 | ** yy_action. Used to detect hash collisions. 262 | ** yy_shift_ofst[] For each state, the offset into yy_action for 263 | ** shifting terminals. 264 | ** yy_reduce_ofst[] For each state, the offset into yy_action for 265 | ** shifting non-terminals after a reduce. 266 | ** yy_default[] Default action for each state. 267 | ** 268 | *********** Begin parsing tables **********************************************/ 269 | %% 270 | /********** End of lemon-generated parsing tables *****************************/ 271 | 272 | /* The next table maps tokens (terminal symbols) into fallback tokens. 273 | ** If a construct like the following: 274 | ** 275 | ** %fallback ID X Y Z. 276 | ** 277 | ** appears in the grammar, then ID becomes a fallback token for X, Y, 278 | ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser 279 | ** but it does not parse, the type of the token is changed to ID and 280 | ** the parse is retried before an error is thrown. 281 | ** 282 | ** This feature can be used, for example, to cause some keywords in a language 283 | ** to revert to identifiers if they keyword does not apply in the context where 284 | ** it appears. 285 | */ 286 | #ifdef YYFALLBACK 287 | static const YYCODETYPE yyFallback[] = { 288 | %% 289 | }; 290 | #endif /* YYFALLBACK */ 291 | 292 | /* The following structure represents a single element of the 293 | ** parser's stack. Information stored includes: 294 | ** 295 | ** + The state number for the parser at this level of the stack. 296 | ** 297 | ** + The value of the token stored at this level of the stack. 298 | ** (In other words, the "major" token.) 299 | ** 300 | ** + The semantic value stored at this level of the stack. This is 301 | ** the information used by the action routines in the grammar. 302 | ** It is sometimes called the "minor" token. 303 | ** 304 | ** After the "shift" half of a SHIFTREDUCE action, the stateno field 305 | ** actually contains the reduce action for the second half of the 306 | ** SHIFTREDUCE. 307 | */ 308 | struct yyStackEntry { 309 | YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ 310 | YYCODETYPE major; /* The major token value. This is the code 311 | ** number for the token at this stack level */ 312 | YYMINORTYPE minor; /* The user-supplied minor token value. This 313 | ** is the value of the token */ 314 | }; 315 | 316 | /* The state of the parser is completely contained in an instance of 317 | ** the following structure */ 318 | 319 | #ifndef LEMON_SUPER 320 | #error "LEMON_SUPER must be defined." 321 | #endif 322 | 323 | /* outside the class so the templates above are still accessible */ 324 | void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor); 325 | void yy_move(YYCODETYPE yymajor, YYMINORTYPE *yyDest, YYMINORTYPE *yySource); 326 | 327 | class yypParser : public LEMON_SUPER { 328 | public: 329 | //using LEMON_SUPER::LEMON_SUPER; 330 | 331 | template 332 | yypParser(Args&&... args); 333 | 334 | virtual ~yypParser() override final; 335 | virtual void parse(int, ParseTOKENTYPE &&) override final; 336 | 337 | #ifndef NDEBUG 338 | virtual void trace(FILE *, const char *) final override; 339 | #endif 340 | 341 | virtual void reset() final override; 342 | virtual bool will_accept() const final override; 343 | virtual int fallback(int iToken) const final override; 344 | /* 345 | ** Return the peak depth of the stack for a parser. 346 | */ 347 | #ifdef YYTRACKMAXSTACKDEPTH 348 | int yypParser::stack_peak(){ 349 | return yyhwm; 350 | } 351 | #endif 352 | 353 | #ifdef YYCOVERAGE 354 | int coverage(FILE *out); 355 | #endif 356 | 357 | const yyStackEntry *begin() const { return yystack; } 358 | const yyStackEntry *end() const { return yytos + 1; } 359 | 360 | protected: 361 | private: 362 | yyStackEntry *yytos; /* Pointer to top element of the stack */ 363 | #ifdef YYTRACKMAXSTACKDEPTH 364 | int yyhwm = 0; /* Maximum value of yyidx */ 365 | #endif 366 | #ifndef YYNOERRORRECOVERY 367 | int yyerrcnt = -1; /* Shifts left before out of the error */ 368 | #endif 369 | #if YYSTACKDEPTH<=0 370 | int yystksz = 0; /* Current side of the stack */ 371 | yyStackEntry *yystack = nullptr; /* The parser's stack */ 372 | yyStackEntry yystk0; /* First stack entry */ 373 | int yyGrowStack(); 374 | #else 375 | yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ 376 | yyStackEntry *yystackEnd; /* Last entry in the stack */ 377 | #endif 378 | 379 | 380 | 381 | void yy_accept(); 382 | void yy_parse_failed(); 383 | void yy_syntax_error(int yymajor, ParseTOKENTYPE &yyminor); 384 | 385 | void yy_transfer(yyStackEntry *yySource, yyStackEntry *yyDest); 386 | 387 | void yy_pop_parser_stack(); 388 | YYACTIONTYPE yy_find_shift_action(YYCODETYPE iLookAhead, YYACTIONTYPE stateno) const; 389 | YYACTIONTYPE yy_find_reduce_action(YYACTIONTYPE stateno, YYCODETYPE iLookAhead) const; 390 | 391 | void yy_shift(YYACTIONTYPE yyNewState, YYCODETYPE yyMajor, ParseTOKENTYPE &&yypMinor); 392 | #ifdef YYERRORSYMBOL 393 | void yy_shift_error(YYACTIONTYPE yyNewState); 394 | #endif 395 | YYACTIONTYPE yy_reduce(unsigned int yyruleno, int yyLookahead, const ParseTOKENTYPE &yyLookaheadToken); 396 | void yyStackOverflow(); 397 | 398 | #ifndef NDEBUG 399 | void yyTraceShift(int yyNewState, const char *zTag) const; 400 | #else 401 | # define yyTraceShift(X,Y) 402 | #endif 403 | 404 | #ifdef YYCOVERAGE 405 | mutable unsigned char yycoverage[YYNSTATE][YYNTOKEN] = {}; 406 | #endif 407 | 408 | #ifndef NDEBUG 409 | FILE *yyTraceFILE = 0; 410 | const char *yyTracePrompt = 0; 411 | #endif /* NDEBUG */ 412 | 413 | int yyidx() const { 414 | return (int)(yytos - yystack); 415 | } 416 | 417 | }; 418 | 419 | 420 | 421 | 422 | #ifndef NDEBUG 423 | /* 424 | ** Turn parser tracing on by giving a stream to which to write the trace 425 | ** and a prompt to preface each trace message. Tracing is turned off 426 | ** by making either argument NULL 427 | ** 428 | ** Inputs: 429 | **
    430 | **
  • A FILE* to which trace output should be written. 431 | ** If NULL, then tracing is turned off. 432 | **
  • A prefix string written at the beginning of every 433 | ** line of trace output. If NULL, then tracing is 434 | ** turned off. 435 | **
436 | ** 437 | ** Outputs: 438 | ** None. 439 | */ 440 | void yypParser::trace(FILE *TraceFILE, const char *zTracePrompt){ 441 | yyTraceFILE = TraceFILE; 442 | yyTracePrompt = zTracePrompt; 443 | if( yyTraceFILE==0 ) yyTracePrompt = 0; 444 | else if( yyTracePrompt==0 ) yyTraceFILE = 0; 445 | } 446 | #endif /* NDEBUG */ 447 | 448 | #if defined(YYCOVERAGE) || !defined(NDEBUG) 449 | /* For tracing shifts, the names of all terminals and nonterminals 450 | ** are required. The following table supplies these names */ 451 | static const char *const yyTokenName[] = { 452 | %% 453 | }; 454 | #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ 455 | 456 | #ifndef NDEBUG 457 | /* For tracing reduce actions, the names of all rules are required. 458 | */ 459 | const char *const yyRuleName[] = { 460 | %% 461 | }; 462 | #endif /* NDEBUG */ 463 | 464 | 465 | #if YYSTACKDEPTH<=0 466 | /* 467 | ** Try to increase the size of the parser stack. Return the number 468 | ** of errors. Return 0 on success. 469 | */ 470 | int yypParser::yyGrowStack(){ 471 | int newSize; 472 | yyStackEntry *pNew; 473 | yyStackEntry *pOld = yystack; 474 | int oldSize = yystksz; 475 | 476 | newSize = oldSize*2 + 100; 477 | pNew = (yyStackEntry *)calloc(newSize, sizeof(pNew[0])); 478 | if( pNew ){ 479 | yystack = pNew; 480 | for (int i = 0; i < oldSize; ++i) { 481 | pNew[i].stateno = pOld[i].stateno; 482 | pNew[i].major = pOld[i].major; 483 | yy_move(pOld[i].major, &pNew[i].minor, &pOld[i].minor); 484 | } 485 | if (pOld != &yystk0) free(pOld); 486 | #ifndef NDEBUG 487 | if( yyTraceFILE ){ 488 | fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", 489 | yyTracePrompt, yystksz, newSize); 490 | } 491 | #endif 492 | yystksz = newSize; 493 | } 494 | return pNew==0; 495 | } 496 | #endif 497 | 498 | 499 | /* The following function deletes the "minor type" or semantic value 500 | ** associated with a symbol. The symbol can be either a terminal 501 | ** or nonterminal. "yymajor" is the symbol code, and "yypminor" is 502 | ** a pointer to the value to be deleted. The code used to do the 503 | ** deletions is derived from the %destructor and/or %token_destructor 504 | ** directives of the input grammar. 505 | */ 506 | void yy_destructor( 507 | YYCODETYPE yymajor, /* Type code for object to destroy */ 508 | YYMINORTYPE *yypminor /* The object to be destroyed */ 509 | ){ 510 | switch( yymajor ){ 511 | /* Here is inserted the actions which take place when a 512 | ** terminal or non-terminal is destroyed. This can happen 513 | ** when the symbol is popped from the stack during a 514 | ** reduce or during error processing or when a parser is 515 | ** being destroyed before it is finished parsing. 516 | ** 517 | ** Note: during a reduce, the only symbols destroyed are those 518 | ** which appear on the RHS of the rule, but which are *not* used 519 | ** inside the C code. 520 | */ 521 | /********* Begin destructor definitions ***************************************/ 522 | %% 523 | /********* End destructor definitions *****************************************/ 524 | default: break; /* If no destructor action specified: do nothing */ 525 | } 526 | } 527 | 528 | 529 | /* 530 | * moves an object (such as when growing the stack). 531 | * Source is constructed. 532 | * Destination is also destructed. 533 | * 534 | */ 535 | void yy_move( 536 | YYCODETYPE yymajor, /* Type code for object to move */ 537 | YYMINORTYPE *yyDest, /* */ 538 | YYMINORTYPE *yySource /* */ 539 | ){ 540 | switch( yymajor ){ 541 | 542 | /********* Begin move definitions ***************************************/ 543 | %% 544 | /********* End move definitions *****************************************/ 545 | default: break; /* If no move action specified: do nothing */ 546 | //yyDest.minor = yySource.minor; 547 | } 548 | } 549 | 550 | 551 | /* 552 | ** Pop the parser's stack once. 553 | ** 554 | ** If there is a destructor routine associated with the token which 555 | ** is popped from the stack, then call it. 556 | */ 557 | void yypParser::yy_pop_parser_stack(){ 558 | yyStackEntry *yymsp; 559 | assert( yytos!=0 ); 560 | assert( yytos > yystack ); 561 | yymsp = yytos--; 562 | #ifndef NDEBUG 563 | if( yyTraceFILE ){ 564 | fprintf(yyTraceFILE,"%sPopping %s\n", 565 | yyTracePrompt, 566 | yyTokenName[yymsp->major]); 567 | } 568 | #endif 569 | yy_destructor(yymsp->major, &yymsp->minor); 570 | } 571 | 572 | 573 | template 574 | yypParser::yypParser(Args&&... args) : LEMON_SUPER(std::forward(args)...) 575 | { 576 | #if YYSTACKDEPTH<=0 577 | if( yyGrowStack() ){ 578 | yystack = &yystk0; 579 | yystksz = 1; 580 | } 581 | #else 582 | std::memset(yystack, 0, sizeof(yystack)); 583 | #endif 584 | 585 | yytos = yystack; 586 | yystack[0].stateno = 0; 587 | yystack[0].major = 0; 588 | #if YYSTACKDEPTH>0 589 | yystackEnd = &yystack[YYSTACKDEPTH-1]; 590 | #endif 591 | } 592 | 593 | void yypParser::reset() { 594 | 595 | while( yytos>yystack ) yy_pop_parser_stack(); 596 | 597 | #ifndef YYNOERRORRECOVERY 598 | yyerrcnt = -1; 599 | #endif 600 | 601 | yytos = yystack; 602 | yystack[0].stateno = 0; 603 | yystack[0].major = 0; 604 | 605 | LEMON_SUPER::reset(); 606 | } 607 | 608 | 609 | /* 610 | ** Deallocate and destroy a parser. Destructors are called for 611 | ** all stack elements before shutting the parser down. 612 | ** 613 | ** If the YYPARSEFREENEVERNULL macro exists (for example because it 614 | ** is defined in a %include section of the input grammar) then it is 615 | ** assumed that the input pointer is never NULL. 616 | */ 617 | 618 | yypParser::~yypParser() { 619 | while( yytos>yystack ) yy_pop_parser_stack(); 620 | #if YYSTACKDEPTH<=0 621 | if( yystack!=&yystk0 ) free(yystack); 622 | #endif 623 | } 624 | 625 | 626 | /* 627 | ** Write into out a description of every state/lookahead combination that 628 | ** 629 | ** (1) has not been used by the parser, and 630 | ** (2) is not a syntax error. 631 | ** 632 | ** Return the number of missed state/lookahead combinations. 633 | */ 634 | #if defined(YYCOVERAGE) 635 | int yypParser::coverage(FILE *out){ 636 | int stateno, iLookAhead, i; 637 | int nMissed = 0; 638 | for(stateno=0; statenoYY_MAX_SHIFT ) return stateno; 665 | assert( stateno <= YY_SHIFT_MAX ); 666 | #if defined(YYCOVERAGE) 667 | yycoverage[stateno][iLookAhead] = 1; 668 | #endif 669 | do{ 670 | i = stateno <= YY_SHIFT_COUNT ? yy_shift_ofst[stateno] : stateno; 671 | assert( i>=0 ); 672 | assert( i<=YY_ACTTAB_COUNT ); 673 | assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); 674 | assert( iLookAhead!=YYNOCODE ); 675 | assert( iLookAhead < YYNTOKEN ); 676 | i += iLookAhead; 677 | assert( i<(int)YY_NLOOKAHEAD ); 678 | if( yy_lookahead[i]!=iLookAhead ){ 679 | #ifdef YYFALLBACK 680 | YYCODETYPE iFallback; /* Fallback token */ 681 | assert( iLookAhead %s\n", 687 | yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); 688 | } 689 | #endif 690 | assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ 691 | iLookAhead = iFallback; 692 | continue; 693 | } 694 | #endif 695 | #ifdef YYWILDCARD 696 | { 697 | int j = i - iLookAhead + YYWILDCARD; 698 | assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) ); 699 | if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){ 700 | #ifndef NDEBUG 701 | if( yyTraceFILE ){ 702 | fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", 703 | yyTracePrompt, yyTokenName[iLookAhead], 704 | yyTokenName[YYWILDCARD]); 705 | } 706 | #endif /* NDEBUG */ 707 | return yy_action[j]; 708 | } 709 | } 710 | #endif /* YYWILDCARD */ 711 | return yy_default[stateno]; 712 | }else{ 713 | assert( i>=0 && iYY_REDUCE_COUNT ){ 730 | return yy_default[stateno]; 731 | } 732 | #else 733 | assert( stateno<=YY_REDUCE_COUNT ); 734 | #endif 735 | i = yy_reduce_ofst[stateno]; 736 | assert( iLookAhead!=YYNOCODE ); 737 | i += iLookAhead; 738 | #ifdef YYERRORSYMBOL 739 | if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ 740 | return yy_default[stateno]; 741 | } 742 | #else 743 | assert( i>=0 && iyystack ) yy_pop_parser_stack(); 759 | /* Here code is inserted which will execute if the parser 760 | ** stack every overflows */ 761 | /******** Begin %stack_overflow code ******************************************/ 762 | %% 763 | /******** End %stack_overflow code ********************************************/ 764 | LEMON_SUPER::stack_overflow(); 765 | } 766 | 767 | /* 768 | ** Print tracing information for a SHIFT action 769 | */ 770 | #ifndef NDEBUG 771 | void yypParser::yyTraceShift(int yyNewState, const char *zTag) const { 772 | if( yyTraceFILE ){ 773 | if( yyNewStatemajor], 776 | yyNewState); 777 | }else{ 778 | fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n", 779 | yyTracePrompt, zTag, yyTokenName[yytos->major], 780 | yyNewState - YY_MIN_REDUCE); 781 | } 782 | } 783 | } 784 | #endif 785 | 786 | /* 787 | ** Perform a shift action. 788 | */ 789 | void yypParser::yy_shift( 790 | YYACTIONTYPE yyNewState, /* The new state to shift in */ 791 | YYCODETYPE yyMajor, /* The major token to shift in */ 792 | ParseTOKENTYPE &&yyMinor /* The minor token to shift in */ 793 | ){ 794 | yytos++; 795 | #ifdef YYTRACKMAXSTACKDEPTH 796 | if( yyidx()>yyhwm ){ 797 | yyhwm++; 798 | assert(yyhwm == yyidx()); 799 | } 800 | #endif 801 | #if YYSTACKDEPTH>0 802 | if( yytos>yystackEnd ){ 803 | yytos--; 804 | yyStackOverflow(); 805 | return; 806 | } 807 | #else 808 | if( yytos>=&yystack[yystksz] ){ 809 | if( yyGrowStack() ){ 810 | yytos--; 811 | yyStackOverflow(); 812 | return; 813 | } 814 | } 815 | #endif 816 | if( yyNewState > YY_MAX_SHIFT ){ 817 | yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; 818 | } 819 | yytos->stateno = yyNewState; 820 | yytos->major = yyMajor; 821 | //yytos->minor.yy0 = yyMinor; 822 | //yy_move also calls the destructor... 823 | //yy_move(std::addressof(yytos->minor.yy0), std::addressof(yyMinor)); 824 | yy_constructor(std::addressof(yytos->minor.yy0), std::move(yyMinor)); 825 | yyTraceShift(yyNewState, "Shift"); 826 | } 827 | 828 | #ifdef YYERRORSYMBOL 829 | void yypParser::yy_shift_error( 830 | YYACTIONTYPE yyNewState /* The new state to shift in */ 831 | ){ 832 | yytos++; 833 | #ifdef YYTRACKMAXSTACKDEPTH 834 | if( yyidx()>yyhwm ){ 835 | yyhwm++; 836 | assert(yyhwm == yyidx()); 837 | } 838 | #endif 839 | #if YYSTACKDEPTH>0 840 | if( yytos>yystackEnd ){ 841 | yytos--; 842 | yyStackOverflow(); 843 | return; 844 | } 845 | #else 846 | if( yytos>=&yystack[yystksz] ){ 847 | if( yyGrowStack() ){ 848 | yytos--; 849 | yyStackOverflow(); 850 | return; 851 | } 852 | } 853 | #endif 854 | if( yyNewState > YY_MAX_SHIFT ){ 855 | yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; 856 | } 857 | yytos->stateno = yyNewState; 858 | yytos->major = YYERRORSYMBOL; 859 | yytos->minor.YYERRSYMDT = 0; 860 | yyTraceShift(yyNewState, "Shift"); 861 | } 862 | #endif 863 | 864 | /* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side 865 | ** of that rule */ 866 | static const YYCODETYPE yyRuleInfoLhs[] = { 867 | %% 868 | }; 869 | 870 | /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number 871 | ** of symbols on the right-hand side of that rule. */ 872 | static const signed char yyRuleInfoNRhs[] = { 873 | %% 874 | }; 875 | 876 | /* 877 | ** Perform a reduce action and the shift that must immediately 878 | ** follow the reduce. 879 | */ 880 | YYACTIONTYPE yypParser::yy_reduce( 881 | unsigned int yyruleno, /* Number of the rule by which to reduce */ 882 | int yyLookahead, /* Lookahead token, or YYNOCODE if none */ 883 | const ParseTOKENTYPE &yyLookaheadToken /* Value of the lookahead token */ 884 | ){ 885 | int yygoto; /* The next state */ 886 | YYACTIONTYPE yyact; /* The next action */ 887 | yyStackEntry *yymsp; /* The top of the parser's stack */ 888 | int yysize; /* Amount to pop the stack */ 889 | yymsp = yytos; 890 | #ifndef NDEBUG 891 | if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ 892 | yysize = yyRuleInfoNRhs[yyruleno]; 893 | if( yysize ){ 894 | fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n", 895 | yyTracePrompt, 896 | yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno); 897 | }else{ 898 | fprintf(yyTraceFILE, "%sReduce %d [%s].\n", 899 | yyTracePrompt, yyruleno, yyRuleName[yyruleno]); 900 | } 901 | } 902 | #endif /* NDEBUG */ 903 | 904 | /* Check that the stack is large enough to grow by a single entry 905 | ** if the RHS of the rule is empty. This ensures that there is room 906 | ** enough on the stack to push the LHS value */ 907 | if( yyRuleInfoNRhs[yyruleno]==0 ){ 908 | #ifdef YYTRACKMAXSTACKDEPTH 909 | if( yyidx()>yyhwm ){ 910 | yyhwm++; 911 | assert(yyhwm == yyidx()); 912 | } 913 | #endif 914 | #if YYSTACKDEPTH>0 915 | if( yytos>=yystackEnd ){ 916 | yyStackOverflow(); 917 | /* The call to yyStackOverflow() above pops the stack until it is 918 | ** empty, causing the main parser loop to exit. So the return value 919 | ** is never used and does not matter. */ 920 | return 0; 921 | } 922 | #else 923 | if( yytos>=&yystack[yystksz-1] ){ 924 | if( yyGrowStack() ){ 925 | yyStackOverflow(); 926 | /* The call to yyStackOverflow() above pops the stack until it is 927 | ** empty, causing the main parser loop to exit. So the return value 928 | ** is never used and does not matter. */ 929 | return 0; 930 | } 931 | yymsp = yytos; 932 | } 933 | #endif 934 | } 935 | 936 | switch( yyruleno ){ 937 | /* Beginning here are the reduction cases. A typical example 938 | ** follows: 939 | ** case 0: 940 | ** #line 941 | ** { ... } // User supplied code 942 | ** #line 943 | ** break; 944 | */ 945 | /********** Begin reduce actions **********************************************/ 946 | %% 947 | /********** End reduce actions ************************************************/ 948 | }; 949 | assert( yyrulenoYY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); 957 | 958 | /* It is not possible for a REDUCE to be followed by an error */ 959 | assert( yyact!=YY_ERROR_ACTION ); 960 | 961 | yymsp += yysize+1; 962 | yytos = yymsp; 963 | yymsp->stateno = (YYACTIONTYPE)yyact; 964 | yymsp->major = (YYCODETYPE)yygoto; 965 | yyTraceShift(yyact, "... then shift"); 966 | return yyact; 967 | } 968 | 969 | /* 970 | ** The following code executes when the parse fails 971 | */ 972 | #ifndef YYNOERRORRECOVERY 973 | void yypParser::yy_parse_failed(){ 974 | #ifndef NDEBUG 975 | if( yyTraceFILE ){ 976 | fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); 977 | } 978 | #endif 979 | while( yytos>yystack ) yy_pop_parser_stack(); 980 | /* Here code is inserted which will be executed whenever the 981 | ** parser fails */ 982 | /************ Begin %parse_failure code ***************************************/ 983 | %% 984 | /************ End %parse_failure code *****************************************/ 985 | LEMON_SUPER::parse_failure(); 986 | } 987 | #endif /* YYNOERRORRECOVERY */ 988 | 989 | /* 990 | ** The following code executes when a syntax error first occurs. 991 | */ 992 | void yypParser::yy_syntax_error( 993 | int yymajor, /* The major type of the error token */ 994 | ParseTOKENTYPE &yyminor /* The minor type of the error token */ 995 | ){ 996 | //#define TOKEN yyminor 997 | auto &TOKEN = yyminor; 998 | /************ Begin %syntax_error code ****************************************/ 999 | %% 1000 | /************ End %syntax_error code ******************************************/ 1001 | LEMON_SUPER::syntax_error(yymajor, TOKEN); 1002 | } 1003 | 1004 | /* 1005 | ** The following is executed when the parser accepts 1006 | */ 1007 | void yypParser::yy_accept(){ 1008 | #ifndef NDEBUG 1009 | if( yyTraceFILE ){ 1010 | fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); 1011 | } 1012 | #endif 1013 | #ifndef YYNOERRORRECOVERY 1014 | yyerrcnt = -1; 1015 | #endif 1016 | assert( yytos==yystack ); 1017 | /* Here code is inserted which will be executed whenever the 1018 | ** parser accepts */ 1019 | /*********** Begin %parse_accept code *****************************************/ 1020 | %% 1021 | /*********** End %parse_accept code *******************************************/ 1022 | LEMON_SUPER::parse_accept(); 1023 | } 1024 | 1025 | /* The main parser program. 1026 | ** The first argument is a pointer to a structure obtained from 1027 | ** "ParseAlloc" which describes the current state of the parser. 1028 | ** The second argument is the major token number. The third is 1029 | ** the minor token. The fourth optional argument is whatever the 1030 | ** user wants (and specified in the grammar) and is available for 1031 | ** use by the action routines. 1032 | ** 1033 | ** Inputs: 1034 | **
    1035 | **
  • A pointer to the parser (an opaque structure.) 1036 | **
  • The major token number. 1037 | **
  • The minor token number. 1038 | **
  • An option argument of a grammar-specified type. 1039 | **
1040 | ** 1041 | ** Outputs: 1042 | ** None. 1043 | */ 1044 | 1045 | 1046 | 1047 | void yypParser::parse( 1048 | int yymajor, /* The major token code number */ 1049 | ParseTOKENTYPE &&yyminor /* The value for the token */ 1050 | ){ 1051 | //YYMINORTYPE yyminorunion; 1052 | YYACTIONTYPE yyact; /* The parser action. */ 1053 | #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 1054 | int yyendofinput; /* True if we are at the end of input */ 1055 | #endif 1056 | #ifdef YYERRORSYMBOL 1057 | int yyerrorhit = 0; /* True if yymajor has invoked an error */ 1058 | #endif 1059 | 1060 | assert( yytos!=0 ); 1061 | #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 1062 | yyendofinput = (yymajor==0); 1063 | #endif 1064 | 1065 | yyact = yytos->stateno; 1066 | #ifndef NDEBUG 1067 | if( yyTraceFILE ){ 1068 | if( yyact < YY_MIN_REDUCE ){ 1069 | fprintf(yyTraceFILE,"%sInput '%s' in state %d\n", 1070 | yyTracePrompt,yyTokenName[yymajor],yyact); 1071 | }else{ 1072 | fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", 1073 | yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); 1074 | } 1075 | } 1076 | #endif 1077 | 1078 | do{ 1079 | assert( yyact==yytos->stateno ); 1080 | yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); 1081 | if( yyact >= YY_MIN_REDUCE ){ 1082 | yyact = yy_reduce(yyact-YY_MIN_REDUCE,yymajor, yyminor); 1083 | }else if( yyact <= YY_MAX_SHIFTREDUCE ){ 1084 | yy_shift(yyact,(YYCODETYPE)yymajor,std::move(yyminor)); 1085 | #ifndef YYNOERRORRECOVERY 1086 | yyerrcnt--; 1087 | #endif 1088 | break; 1089 | }else if( yyact==YY_ACCEPT_ACTION ){ 1090 | yytos--; 1091 | yy_accept(); 1092 | return; 1093 | }else{ 1094 | assert( yyact == YY_ERROR_ACTION ); 1095 | //yyminorunion.yy0 = yyminor; 1096 | #ifdef YYERRORSYMBOL 1097 | int yymx; 1098 | #endif 1099 | #ifndef NDEBUG 1100 | if( yyTraceFILE ){ 1101 | fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); 1102 | } 1103 | #endif 1104 | #ifdef YYERRORSYMBOL 1105 | /* A syntax error has occurred. 1106 | ** The response to an error depends upon whether or not the 1107 | ** grammar defines an error token "ERROR". 1108 | ** 1109 | ** This is what we do if the grammar does define ERROR: 1110 | ** 1111 | ** * Call the %syntax_error function. 1112 | ** 1113 | ** * Begin popping the stack until we enter a state where 1114 | ** it is legal to shift the error symbol, then shift 1115 | ** the error symbol. 1116 | ** 1117 | ** * Set the error count to three. 1118 | ** 1119 | ** * Begin accepting and shifting new tokens. No new error 1120 | ** processing will occur until three tokens have been 1121 | ** shifted successfully. 1122 | ** 1123 | */ 1124 | if( yyerrcnt<0 ){ 1125 | yy_syntax_error(yymajor,yyminor); 1126 | } 1127 | yymx = yytos->major; 1128 | if( yymx==YYERRORSYMBOL || yyerrorhit ){ 1129 | #ifndef NDEBUG 1130 | if( yyTraceFILE ){ 1131 | fprintf(yyTraceFILE,"%sDiscard input token %s\n", 1132 | yyTracePrompt,yyTokenName[yymajor]); 1133 | } 1134 | #endif 1135 | //yy_destructor(yyminor); 1136 | yymajor = YYNOCODE; 1137 | }else{ 1138 | while( yytos > yystack 1139 | && (yyact = yy_find_reduce_action( 1140 | yytos->stateno, 1141 | YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE 1142 | ){ 1143 | yy_pop_parser_stack(); 1144 | } 1145 | if( yytos == yystack || yymajor==0 ){ 1146 | //yy_destructor(yyminor); 1147 | yy_parse_failed(); 1148 | #ifndef YYNOERRORRECOVERY 1149 | yyerrcnt = -1; 1150 | #endif 1151 | yymajor = YYNOCODE; 1152 | }else if( yymx!=YYERRORSYMBOL ){ 1153 | yy_shift_error(yyact); 1154 | } 1155 | } 1156 | yyerrcnt = 3; 1157 | yyerrorhit = 1; 1158 | if( yymajor==YYNOCODE ) break; 1159 | yyact = yytos->stateno; 1160 | #elif defined(YYNOERRORRECOVERY) 1161 | /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to 1162 | ** do any kind of error recovery. Instead, simply invoke the syntax 1163 | ** error routine and continue going as if nothing had happened. 1164 | ** 1165 | ** Applications can set this macro (for example inside %include) if 1166 | ** they intend to abandon the parse upon the first syntax error seen. 1167 | */ 1168 | yy_syntax_error(yymajor,yyminor); 1169 | //yy_destructor(yyminor); 1170 | break; 1171 | 1172 | #else /* YYERRORSYMBOL is not defined */ 1173 | /* This is what we do if the grammar does not define ERROR: 1174 | ** 1175 | ** * Report an error message, and throw away the input token. 1176 | ** 1177 | ** * If the input token is $, then fail the parse. 1178 | ** 1179 | ** As before, subsequent error messages are suppressed until 1180 | ** three input tokens have been successfully shifted. 1181 | */ 1182 | if( yyerrcnt<=0 ){ 1183 | yy_syntax_error(yymajor,yyminor); 1184 | } 1185 | yyerrcnt = 3; 1186 | //yy_destructor(yyminor); 1187 | if( yyendofinput ){ 1188 | yy_parse_failed(); 1189 | #ifndef YYNOERRORRECOVERY 1190 | yyerrcnt = -1; 1191 | #endif 1192 | } 1193 | break; 1194 | #endif 1195 | } 1196 | }while( yytos>yystack ); 1197 | #ifndef NDEBUG 1198 | if( yyTraceFILE ){ 1199 | yyStackEntry *i; 1200 | char cDiv = '['; 1201 | fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); 1202 | for(i=&yystack[1]; i<=yytos; i++){ 1203 | fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); 1204 | cDiv = ' '; 1205 | } 1206 | if (cDiv == '[') fprintf(yyTraceFILE,"["); 1207 | fprintf(yyTraceFILE,"]\n"); 1208 | } 1209 | #endif 1210 | return; 1211 | } 1212 | 1213 | 1214 | bool yypParser::will_accept() const { 1215 | 1216 | 1217 | struct stack_entry { 1218 | YYACTIONTYPE stateno; 1219 | YYCODETYPE major; 1220 | }; 1221 | 1222 | YYACTIONTYPE yyact; 1223 | const YYCODETYPE yymajor = 0; 1224 | ParseTOKENTYPE yyminor; 1225 | std::vector stack; 1226 | 1227 | 1228 | // copy stack to stack. 1229 | stack.reserve(yyidx()+1); 1230 | std::transform(begin(), end(), std::back_inserter(stack), [](const yyStackEntry &e){ 1231 | return stack_entry({e.stateno, e.major}); 1232 | }); 1233 | 1234 | do { 1235 | yyact = yy_find_shift_action(yymajor, stack.back().stateno); 1236 | 1237 | 1238 | if( yyact==YY_ACCEPT_ACTION ) return true; 1239 | if( yyact >= YY_MIN_REDUCE ){ 1240 | // reduce... 1241 | unsigned yyruleno = yyact - YY_MIN_REDUCE; 1242 | 1243 | YYCODETYPE yygoto = yyRuleInfoLhs[yyruleno]; 1244 | int yysize = -yyRuleInfoNRhs[yyruleno]; /* stored as negative value */ 1245 | 1246 | while (yysize--) stack.pop_back(); 1247 | 1248 | yyact = yy_find_reduce_action(stack.back().stateno, yygoto); 1249 | stack.push_back({yyact, yygoto}); 1250 | } 1251 | else { 1252 | return false; 1253 | } 1254 | 1255 | } while (!stack.empty()); 1256 | 1257 | return false; 1258 | 1259 | 1260 | } 1261 | 1262 | /* 1263 | ** Return the fallback token corresponding to canonical token iToken, or 1264 | ** 0 if iToken has no fallback. 1265 | */ 1266 | int yypParser::fallback(int iToken) const { 1267 | #ifdef YYFALLBACK 1268 | assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); 1269 | return yyFallback[iToken]; 1270 | #else 1271 | (void)iToken; 1272 | #endif 1273 | return 0; 1274 | } 1275 | 1276 | 1277 | 1278 | } // namespace 1279 | --------------------------------------------------------------------------------