1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
|
@q file: parse_env.w@>
@q% Copyright Dave Bone 1998 - 2015@>
@q% /*@>
@q% This Source Code Form is subject to the terms of the Mozilla Public@>
@q% License, v. 2.0. If a copy of the MPL was not distributed with this@>
@q% file, You can obtain one at http://mozilla.org/MPL/2.0/.@>
@q% */@>
@** Parse stack environment.\fbreak
\fbreak
\fbreak
\convertMPtoPDF{"/usr/local/yacco2/diagrams/parse_stk_env.1"}{1}{1}
\fbreak
\fbreak
Some general comments on the parse stack environment:\fbreak
Firstly it's just an array of |parse_record| whereby
the determinist push-down automaton straddles 2 array records: the first record
contains the state address and its stacked symbol and the second
record contains the goto state that it vectors to.
To improve parsing speed, the rule's ``birth-run-delete'' cyle
has been replaced by recycling of the rule: ``birth once run forever''
until the parser is shutdown.
To do this a |Rule_s_reuse_entry| is kept per required
number of recurse / use count per rule.
This is determined by analysing the grammar and counting
the rhs of each rule for the rule's use patterns.
See |structure.w| of \O2{}library explaining this.
Each grammar locally contains its ``rules's reuse'' table.
The |reduce_rhs_of_rule| procedure reads
the recyled rules's table and returns the dupple containing
the rule and the address within
the recycle table containing the |Rule_s_reuse_entry|. Both components are pushed
onto the parse stack frame.
When the parse stack frame is popped due to a reduce of the rhs of a rule or due to an abort,
each stack frame being popped is inspected for its symbol context:
Rule or Terminal, or possibly nothing.
If the symbol context is of Rule, the |Rule_s_reuse_entry|'s
``in use'' indicator is reset for recycling.
\fbreak
\fbreak
Another subtlety is that of ``how to reset the rule's object''?.\fbreak
In c++ terms, as the rule's class only has ctor and possibly
a dtor that are implicitly called
by the generated code,
``how do u reset the object for reuse as this is not a copy situation?''.
Not to blame c++, this situation was not thought of until now by me.
This requires an inspection of the grammar rule's definition for a grammar's
``constructor'' directive that
usually does specific initializations at time of rule creation.
If it does not exist, then there is nothing to be done
unless the grammar writer has defaulted to the compiler's
initialization code for the class's
locally defined variables --- as they say in French d\'esol\'e.
For me this unspoken initialization is not good as it is implicit
and i prefer being forthright to my coding intentions.
Given this, a ``reuse type'' ctor must be defined within the rule's class containing
the constructor directive's
code if required and called
inside the preliminaries of |reduce_rhs_of_rule| procedure for the specific rule.
@*2 Parse record.\fbreak
|Cparse_record| defines the record of the parse stack.
Due to my way of |cweb| source code ordering, type definitions come before
structure definitions.
In this case,the structure definition is outputted as a type definition
instead of as a structure.\fbreak
\fbreak
``abort\_\_'' adjusted to ``void*'' from ``bool'' as my optimization
on stack frame of individual
structures being multiples got slack bytes generated when porting to a HP Aplha.
So make sure all are of same size.
Put back to bool.
@<Type...@>+=
struct Cparse_record{
void set_aborted(bool X);
bool aborted()const;
yacco2::CAbs_lr1_sym* symbol();
void set_symbol(yacco2::CAbs_lr1_sym* Symbol);
yacco2::State* state();
void set_state(yacco2::State* State_no);
void set_rule_s_reuse_entry(yacco2::Rule_s_reuse_entry* Rule_s_reuse);
yacco2::Rule_s_reuse_entry* rule_s_reuse_entry();
yacco2::CAbs_lr1_sym* symbol__;
yacco2::State* state__;
bool aborted__;
yacco2::Rule_s_reuse_entry* rule_s_reuse_entry_ptr__;
};
@*2 Lr parse stack structure.\fbreak
Why the home grown stack --- SPEED. Templates are toooo slow
with to many generalities.
@<Type...@>+=
struct lr_stk{
lr_stk();
void lr_stk_init(yacco2::State& S1);
void push_state(yacco2::State& S1);
void push_symbol(yacco2::CAbs_lr1_sym& Sym);
bool empty();
void pop();
void clean_up();
Cparse_record* sf_by_sub(yacco2::UINT Sub);
Cparse_record* sf_by_top(yacco2::UINT No);
Cparse_record lr_stk__[C_MAX_LR_STK_ITEMS];
yacco2::UINT top_sub__;
Cparse_record* top__;
Cparse_record* first_sf__;
State* first_state__;
};
@*2 Parse stack implementation.
@<accrue yacco2 code@>=
lr_stk::lr_stk(){
top_sub__ = 1;
first_sf__ = &lr_stk__[1];
top__ = first_sf__;
first_state__ = 0;
top__->state__ = 0;
top__->symbol__ = 0;
top__->aborted__ = 0;
top__->rule_s_reuse_entry_ptr__ = 0;
}
void lr_stk::lr_stk_init(yacco2::State& S1){
top_sub__ = 1;
first_sf__ = &lr_stk__[1];
top__ = first_sf__;
first_state__ = &S1;
top__->state__ = first_state__;
top__->symbol__ = 0;
top__->aborted__ = 0;
top__->rule_s_reuse_entry_ptr__ = 0;
}
bool lr_stk::empty(){
if(top_sub__ < 1) return true;
return false;
}
void lr_stk::push_symbol(yacco2::CAbs_lr1_sym& Sym){
top__->symbol__ = &Sym;
}
void lr_stk::pop(){
--top_sub__;
--top__;
}
void lr_stk::clean_up(){
top_sub__ = 1;
first_sf__ = &lr_stk__[1];
top__ = first_sf__;
top__->symbol__ = 0;
top__->aborted__ = 0;
top__->state__ = first_state__;
top__->rule_s_reuse_entry_ptr__ = 0;
}
@ |lr_stk::clean_up()|. Speed demon.
@<|lr_stk::clean_up()|@>=
top_sub__ = 1;
top__ = first_sf__;
top__->symbol__ = 0;
top__->aborted__ = 0;
top__->state__ = first_state__;
top__->rule_s_reuse_entry_ptr__ = 0;
@ |lr_stk::empty()|. Speed demon.
@<|lr_stk::lr_stk::empty()|@>=
if(top_sub__ < 1) return true;
return false;
@ |lr_stk::pop()|. Speed demon.
@<|lr_stk::pop()|@>=
--top_sub__;
--top__;
@*2 Parse stack implementation.
@<accrue yacco2 code@>=
Cparse_record* lr_stk::sf_by_sub(yacco2::UINT Sub){
if((Sub < 1) || (Sub > MAX_LR_STK_ITEMS)){
char a[BUFFER_SIZE];
@.Err lr\_stk - sf\_by\_sub invali...@>
yacco2::KCHARP msg = "lr_stk - sf_by_sub invalid sub: %i not in range 1..%i";
sprintf(a,msg,Sub,MAX_LR_STK_ITEMS);
Yacco2_faulty_precondition(a,__FILE__,__LINE__);
exit(1);
}
return &lr_stk__[Sub];
}
Cparse_record* lr_stk::sf_by_top(yacco2::UINT No){
int s = top_sub__ - No;
if(s < 1){
@.Err lr\_stk - sf\_by\_top underf...@>
char a[BUFFER_SIZE];
yacco2::KCHARP msg = "lr_stk - sf_by_top underflow top sub: %i, requested sub: %i < 1";
sprintf(a,msg,top_sub__,No);
Yacco2_faulty_precondition(a,__FILE__,__LINE__);
exit(1);
}
return &lr_stk__[s];
}
@*2 Parse stack implementation.
@<accrue yacco2 code@>=
void lr_stk::push_state(yacco2::State& S1){
if(top_sub__ >= MAX_LR_STK_ITEMS){
char a[BUFFER_SIZE];
@.Err lr\_stk - push overflow stac...@>
yacco2::KCHARP msg = "lr_stk - push overflow stack max: %i";
sprintf(a,msg,MAX_LR_STK_ITEMS);
Yacco2_faulty_precondition(a,__FILE__,__LINE__);
exit(1);
}
++top__;
++top_sub__;
top__->state__ = &S1;
top__->symbol__ = 0;
top__->aborted__ = 0;
top__->rule_s_reuse_entry_ptr__ = 0;
}
@ |lr_stk::push_state| --- Speed demon.
@<|lr_stk::push_state|@>=
if(parse_stack__.top_sub__ >= MAX_LR_STK_ITEMS){
char a[BUFFER_SIZE];
@.Err lr\_stk - push overflow stac...@>
yacco2::KCHARP msg = "lr_stk - push overflow stack max: %i";
sprintf(a,msg,MAX_LR_STK_ITEMS);
Yacco2_faulty_precondition(a,__FILE__,__LINE__);
exit(1);
}
++parse_stack__.top__;
++parse_stack__.top_sub__;
parse_stack__.top__->state__ = Goto_state;
parse_stack__.top__->symbol__ = 0;
parse_stack__.top__->aborted__ = 0;
parse_stack__.top__->rule_s_reuse_entry_ptr__ = 0;
@*2 |set_aborted| and |aborted| implementation.\fbreak
The |set_aborted| tags the parse stack record. It is used in conjunction with
the symbol's |affected_by_abort| attribute. That is, the parallel parse aborted
and it is cleaning up the partial effects of the parse:
the symbol indirectly dictates the what's to be done.
@<accrue yacco2 code@>=
void
yacco2::
Cparse_record::
set_aborted(bool X){
aborted__ = X;
}
bool
yacco2::
Cparse_record::
aborted()const{
if(aborted__ == 0) return false;
return true;
}
@*2 |set_rule_s_reuse_entr| and |rule_s_reuse_entry| implementation.\fbreak
Used in the optimization of a rule's recycled symbol.
It is the rule's subscript into the fsm's |rules_reuse_table|.
@<accrue yacco2 code@>=
void
yacco2::
Cparse_record::
set_rule_s_reuse_entry(yacco2::Rule_s_reuse_entry* Rule_s_reuse){
rule_s_reuse_entry_ptr__ = Rule_s_reuse;
}
yacco2::Rule_s_reuse_entry*
yacco2::
Cparse_record::
rule_s_reuse_entry(){
return rule_s_reuse_entry_ptr__;
}
@*2 |set_state| and |state| implementation.
@<accrue yacco2 code@>=
void
yacco2::
Cparse_record::
set_state(yacco2::State* State_ptr){
state__ = State_ptr;
}
yacco2::
State*
yacco2::
Cparse_record::
state(){
return state__;
}
@*2 |set_symbol| and |symbol| implementation.
@<accrue yacco2 code@>=
yacco2::CAbs_lr1_sym*
yacco2::
Cparse_record::
symbol(){
return symbol__;
}
void
yacco2::
Cparse_record::
set_symbol(yacco2::CAbs_lr1_sym* Symbol){
symbol__ = Symbol;
}
|