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 }