Mercurial > jwe > qt-gui-with-push-parser
comparison parser.yy @ 12:894be158b32d
define parser as a class and eliminate some global variables
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 23 May 2019 17:57:20 -0400 |
parents | b652a5528fb1 |
children | d179b0bb85e4 |
comparison
equal
deleted
inserted
replaced
11:b652a5528fb1 | 12:894be158b32d |
---|---|
12 #include <cstdio> | 12 #include <cstdio> |
13 | 13 |
14 #include "interpreter.h" | 14 #include "interpreter.h" |
15 #include "parser.h" | 15 #include "parser.h" |
16 | 16 |
17 namespace parser | 17 namespace calc |
18 { | 18 { |
19 static void *create_parser_state (void); | |
20 static void delete_parser_state (void *); | |
21 | |
22 parser::parser (interpreter& interp) | |
23 : m_interpreter (interp), | |
24 m_parser_state (create_parser_state ()), | |
25 m_beg_of_stmt (true) | |
26 { } | |
27 | |
28 parser::~parser (void) | |
29 { | |
30 delete_parser_state (m_parser_state); | |
31 } | |
32 | |
33 void parser::emit_error (const char *msg) const | |
34 { | |
35 m_interpreter.emit_error (msg); | |
36 } | |
37 | |
38 void parser::emit_result (double value) const | |
39 { | |
40 m_interpreter.emit_result (value); | |
41 } | |
42 | |
19 // For communication between the lexer and parser. | 43 // For communication between the lexer and parser. |
20 size_t bufptr = 0; | 44 size_t bufptr = 0; |
21 size_t chunk_size = 0; | 45 size_t chunk_size = 0; |
22 const char *buf; | 46 const char *buf; |
23 | 47 |
24 // Used to tell readline whether to display the prompt indicating | 48 static int yylex (YYSTYPE& token_value); |
25 // a continuation line. Is there any way we could do this job | |
26 // without a global variable? | |
27 bool beg_of_stmt = true; | |
28 | |
29 static int yylex (void); | |
30 } | 49 } |
31 | 50 |
32 static void yyerror (char const *); | 51 static void yyerror (calc::parser&, char const *); |
33 | |
34 static void emit_error (const char *msg); | |
35 static void emit_result (double value); | |
36 | 52 |
37 %} | 53 %} |
38 | 54 |
55 %define api.pure full | |
39 %define api.push-pull push | 56 %define api.push-pull push |
57 | |
58 %parse-param {calc::parser& parser} | |
40 | 59 |
41 // Bison declarations. | 60 // Bison declarations. |
42 %token NUM | 61 %token NUM |
43 %left '-' '+' | 62 %left '-' '+' |
44 %left '*' '/' | 63 %left '*' '/' |
58 | 77 |
59 line : ';' | 78 line : ';' |
60 { } | 79 { } |
61 | exp ';' | 80 | exp ';' |
62 { | 81 { |
63 emit_result ($1); | 82 parser.emit_result ($1); |
64 parser::beg_of_stmt = true; | 83 parser.beg_of_stmt (true); |
65 } | 84 } |
66 ; | 85 ; |
67 | 86 |
68 exp : NUM | 87 exp : NUM |
69 { | 88 { |
70 $$ = $1; | 89 $$ = $1; |
71 parser::beg_of_stmt = false; | 90 parser.beg_of_stmt (false); |
72 } | 91 } |
73 | exp '+' exp | 92 | exp '+' exp |
74 { | 93 { |
75 $$ = $1 + $3; | 94 $$ = $1 + $3; |
76 parser::beg_of_stmt = false; | 95 parser.beg_of_stmt (false); |
77 } | 96 } |
78 | exp '-' exp | 97 | exp '-' exp |
79 { | 98 { |
80 $$ = $1 - $3; | 99 $$ = $1 - $3; |
81 parser::beg_of_stmt = false; | 100 parser.beg_of_stmt (false); |
82 } | 101 } |
83 | exp '*' exp | 102 | exp '*' exp |
84 { | 103 { |
85 $$ = $1 * $3; | 104 $$ = $1 * $3; |
86 parser::beg_of_stmt = false; | 105 parser.beg_of_stmt (false); |
87 } | 106 } |
88 | exp '/' exp | 107 | exp '/' exp |
89 { | 108 { |
90 $$ = $1 / $3; | 109 $$ = $1 / $3; |
91 parser::beg_of_stmt = false; | 110 parser.beg_of_stmt (false); |
92 } | 111 } |
93 | '-' exp %prec NEG | 112 | '-' exp %prec NEG |
94 { | 113 { |
95 $$ = -$2; | 114 $$ = -$2; |
96 parser::beg_of_stmt = false; | 115 parser.beg_of_stmt (false); |
97 } | 116 } |
98 | exp '^' exp | 117 | exp '^' exp |
99 { | 118 { |
100 $$ = std::pow ($1, $3); | 119 $$ = std::pow ($1, $3); |
101 parser::beg_of_stmt = false; | 120 parser.beg_of_stmt (false); |
102 } | 121 } |
103 | '(' exp ')' | 122 | '(' exp ')' |
104 { | 123 { |
105 $$ = $2; | 124 $$ = $2; |
106 parser::beg_of_stmt = false; | 125 parser.beg_of_stmt (false); |
107 } | 126 } |
108 ; | 127 ; |
109 | 128 |
110 %% | 129 %% |
111 | 130 |
112 namespace parser | 131 namespace calc |
113 { | 132 { |
114 // The lexical analyzer returns a double floating point number on the | 133 // The lexical analyzer returns a double floating point number on the |
115 // stack and the token NUM, or the numeric code of the character read | 134 // stack and the token NUM, or the numeric code of the character read |
116 // if not a number. It skips all blanks and tabs, and returns -1 for | 135 // if not a number. It skips all blanks and tabs, and returns -1 for |
117 // end-of-input. | 136 // end-of-input. |
118 | 137 |
119 static int yylex (void) | 138 static int yylex (YYSTYPE& token_value) |
120 { | 139 { |
121 int c; | 140 int c; |
122 | 141 |
123 if (bufptr >= chunk_size) | 142 if (bufptr >= chunk_size) |
124 return -1; | 143 return -1; |
130 // Process numbers. | 149 // Process numbers. |
131 if (c == '.' || isdigit (c)) | 150 if (c == '.' || isdigit (c)) |
132 { | 151 { |
133 int chars_read = 0; | 152 int chars_read = 0; |
134 bufptr--; | 153 bufptr--; |
135 sscanf (&buf[bufptr], "%lf%n", &yylval, &chars_read); | 154 sscanf (&buf[bufptr], "%lf%n", &token_value, &chars_read); |
136 bufptr += chars_read; | 155 bufptr += chars_read; |
137 return NUM; | 156 return NUM; |
138 } | 157 } |
139 | 158 |
140 // Return a single char. | 159 // Return a single char. |
141 return c; | 160 return c; |
142 } | 161 } |
143 | 162 |
144 // If we defined a parser object, the parser state could be a | 163 int parser::parse_and_execute (const std::string& line) |
145 // member variable of that object. | |
146 | |
147 static yypstate *ps = 0; | |
148 | |
149 void init (void) | |
150 { | |
151 fini (); | |
152 | |
153 ps = yypstate_new (); | |
154 } | |
155 | |
156 void fini (void) | |
157 { | |
158 if (ps) | |
159 yypstate_delete (ps); | |
160 | |
161 ps = 0; | |
162 } | |
163 | |
164 int parse_and_execute (const std::string& line) | |
165 { | 164 { |
166 bufptr = 0; | 165 bufptr = 0; |
167 chunk_size = line.length (); | 166 chunk_size = line.length (); |
168 buf = line.c_str (); | 167 buf = line.c_str (); |
169 | 168 |
170 int status; | 169 int status; |
171 | 170 |
172 do | 171 do |
173 { | 172 { |
174 ::yychar = yylex (); | 173 YYSTYPE token_value; |
175 | 174 int input_char = yylex (token_value); |
176 if (::yychar < 0) | 175 |
176 if (input_char < 0) | |
177 return -1; | 177 return -1; |
178 | 178 |
179 status = yypush_parse (ps); | 179 status = yypush_parse (static_cast<yypstate *> (m_parser_state), |
180 input_char, &token_value, *this); | |
180 } | 181 } |
181 while (status == YYPUSH_MORE); | 182 while (status == YYPUSH_MORE); |
182 | 183 |
183 return -2; | 184 return -2; |
184 } | 185 } |
186 | |
187 static void *create_parser_state (void) | |
188 { | |
189 return yypstate_new (); | |
190 } | |
191 | |
192 static void delete_parser_state (void *parser_state) | |
193 { | |
194 return yypstate_delete (static_cast<yypstate *> (parser_state)); | |
195 } | |
185 } | 196 } |
186 | 197 |
187 static void yyerror (char const *msg) | 198 static void yyerror (calc::parser& parser, char const *msg) |
188 { | 199 { |
189 emit_error (msg); | 200 parser.emit_error (msg); |
190 } | 201 } |
191 | |
192 static void emit_error (const char *msg) | |
193 { | |
194 calc::interpreter::the_interpreter->emit_error (msg); | |
195 } | |
196 | |
197 static void emit_result (double value) | |
198 { | |
199 calc::interpreter::the_interpreter->emit_result (value); | |
200 } |