|
|
1.1 paf 1: %{
2: #define YYSTYPE void *
3: #define YYPARSE_PARAM pc
4: #define YYLEX_PARAM pc
5: #define YYDEBUG 1
6: #define YYERROR_VERBOSE
7: #define YYPRINT(file, type, value) yyprint (file, type, value)
8:
9: #include <stdio.h>
10: #include <string.h>
11: #include <stdlib.h>
12:
13: #include "compile_tools.h"
14:
15: int yyerror (char *s);
16: static void yyprint (FILE *file, int type, YYSTYPE value);
17: int yylex(YYSTYPE *lvalp, void *pc);
18:
19:
20: #define PC ((struct parse_control *)pc)
21: %}
22:
23: %pure_parser
24:
25: %token BREAK
26: %token STR_LITERAL
27: %token BOGUS
28:
29: %%
30:
31: result: input { PC->result=$1 };
32: input: empty | codes;
33:
34: /* codes */
35:
36: codes: code | codes code {
37: $$=$1;
38: P(&$$,$2);
39: };
40: code: write_str_literal | action;
41: action: get | put | with | call;
42:
43: /* get */
44:
45: get: '$' any_name {
46: $$=$2; /* stack: resulting value */
47: A(&$$,OP_WRITE); /* value=pop; write(value) */
48: };
49:
50: any_name: name_without_curly_rdive BREAK | name_in_curly_rdive;
51:
52: name_in_curly_rdive: '{' name_without_curly_rdive '}' { $$=$2 };
53: name_without_curly_rdive: name_rdive {
54: /*
55: TODO: подсмотреть в $1, и если там в первом элементе первая буква ":"
56: то выкинуть её и делать не OP_WITH_READ, а WITH_ROOT
57: TODO: подсмотреть в $1, и если там первым элементом self,
58: то выкинуть его и делать не OP_WITH_READ, а WITH_SELF
59: */
60: $$=N(PC->pool); A(&$$, OP_WITH_READ); /* stack: starting context */
61: P(&$$,$1); /* diving code; stack: current context */
62: };
63: name_rdive: name_advance2 | name_path name_advance2 { $$=$1; P(&$$,$2) }
64:
65: /* put */
66:
67: put: '$' name_expr_dive '(' constructor_value ')' {
68: /*
69: TODO: подсмотреть в $3, и если там в первом элементе первая буква ":"
70: то выкинуть её и делать не OP_WITH_OP_WRITE, а WITH_ROOT
71: TODO: подсмотреть в $3, и если там первым элементом self,
72: то выкинуть его и делать не OP_WITH_OP_WRITE, а WITH_SELF
73: если ничего не осталось - $self(xxx)
74: обругать
75: */
76: $$=N(PC->pool);
77: A(&$$, OP_WITH_WRITE); /* stack: starting context */
78: P(&$$,$2); /* diving code; stack: context,name */
79: P(&$$,$4); /* stack: context,name,constructor_value */
80: A(&$$,OP_CONSTRUCT); /* value=pop; name=pop; context=pop; construct(context,name,value) */
81: };
82: constructor_value:
83: constructor_one_param_value
84: | constructor_two_params_value /* $var(=;2*2) $var(%d;2*2) $var(+;1) */
85: ;
86: constructor_one_param_value:
87: empty_value /* optimized $var() case */
88: | STR_LITERAL /* optimized $var(STR_LITERAL) case */
89: | complex_constructor_param_value /* $var(something complex) */
90: ;
91: empty_value: empty;
92: complex_constructor_param_value: complex_constructor_param_body {
93: $$=N(PC->pool);
94: A(&$$, OP_CREATE_EWPOOL); /* stack: empty write context */
95: P(&$$,$1); /* some codes to that context */
96: A(&$$,OP_REDUCE_EWPOOL); /* context=pop; stack: context.value() */
97: };
98: complex_constructor_param_body:
99: codes__excluding_sole_str_literal
100: | codes__str__followed_by__excluding_sole_str_literal
101: ;
102: constructor_two_params_value: STR_LITERAL ';' constructor_one_param_value {
103: char *operator_or_fmt=string_cstr(LS($1));
104: $$=N(PC->pool);
1.2 ! paf 105: G(&$$, operator_or_fmt);/* stack: ncontext name char*operator_or_fmt */
1.1 paf 106: P(&$$, $3); /* stack: ncontext name char*operator_or_fmt expr */
107: switch(operator_or_fmt[0]) {
108: case '=': case '%':
109: A(&$$, OP_EXPRESSION_EVAL);
110: break;
111: case '+': case '-': case '*': case '/':
112: A(&$$, OP_MODIFY_EVAL);
113: break;
114: default:
115: exception(PC->pool, 0,0, LS($1), "invalid modification operator");
116: }
117: /* stack: ncontext name value */
118: };
119:
120:
121: /* call */
122:
123: call: '^' name_expr_dive store_params BREAK { /* ^field.$method{vasya} */
124: /*
125: TODO: подсмотреть в $3, и если там в первом элементе первая буква ":"
126: то выкинуть её и делать не OP_WITH_READ, а WITH_ROOT
127: TODO: подсмотреть в $3, и если там первым элементом self,
128: то выкинуть его и делать не OP_WITH_READ, а WITH_SELF
129: TODO:
130: если первым в $3 идёт result
131: то
132: выкинуть его
133: если там ещё что-то осталось,
134: то
135: не OP_WITH_READ, а WITH_RESULT
136: иначе // ^result(value)
137: обругать безобразие
138: */
139: $$=N(PC->pool);
140: A(&$$, OP_WITH_READ); /* stack: starting context */
141: P(&$$,$2); /* diving code; stack: context,method_name */
142: A(&$$,OP_GET_METHOD_FRAME); /* stack: context,method_frame */
143: P(&$$,$3); /* filling method_frame.store_params */
144: A(&$$,OP_CALL); /* method_frame=pop; ncontext=pop; call(ncontext,method_frame) */
145: };
146:
147: store_params: store_param | store_params store_param { $$=$1; P(&$$,$2) };
148: store_param: store_round_param | store_curly_param;
149: store_round_param: '(' store_param_parts ')' {$$=$2};
150: store_param_parts: store_param_part | store_param_parts ';' store_param_part { $$=$1; P(&$$,$3) };
151: store_param_part: constructor_one_param_value {
152: $$=$1;
153: A(&$$,OP_STORE_PARAM);
154: }
155: store_curly_param: '{' input '}' {
156: $$=N(PC->pool);
157: A(&$$, OP_CODE_ARRAY);
1.2 ! paf 158: G(&$$,$2);
1.1 paf 159: A(&$$,OP_CREATE_JUNCTION);
160: A(&$$,OP_STORE_PARAM);
161: };
162:
163: /* name */
164:
165: name_expr_dive: name_expr_value | name_path name_expr_value { $$=$1; P(&$$,$2) };
166:
167: name_path: name_step | name_path name_step { $$=$1; P(&$$,$2) };
168: name_step: name_advance1 '.';
169: name_advance1: name_expr_value {
170: /* stack: context */
171: $$=$1; /* stack: context,name */
172: A(&$$,OP_GET_ELEMENT); /* name=pop; context=pop; stack: context.get_element(name) */
173: };
174: name_advance2: name_expr_value {
175: /* stack: context */
176: $$=$1; /* stack: context,name */
177: A(&$$,OP_GET_ELEMENT); /* name=pop; context=pop; stack: context.get_element(name) */
178: }
179: | STR_LITERAL BOGUS
180: ;
181: name_expr_value:
182: STR_LITERAL /* subname_is_const */
183: | name_expr_subvar_value /* $subname_is_var_value */
184: | name_expr_with_subvar_value /* xxx$part_of_subname_is_var_value[$...] */
185: ;
186: name_expr_subvar_value: '$' subvar_ref_name_rdive {
187: $$=$2;
188: A(&$$,OP_GET_ELEMENT);
189: };
190: name_expr_with_subvar_value: STR_LITERAL subvar_get_writes {
191: $$=N(PC->pool);
192: A(&$$, OP_CREATE_EWPOOL);
193: P(&$$,$1);
194: A(&$$,OP_WRITE);
195: P(&$$,$2);
196: A(&$$,OP_REDUCE_EWPOOL);
197: };
198: subvar_ref_name_rdive: STR_LITERAL {
199: /*
200: TODO: подсмотреть в $1, и если там в первом элементе первая буква ":"
201: то выкинуть её и делать не OP_WITH_READ, а WITH_ROOT
202: */
203: $$=N(PC->pool); A(&$$, OP_WITH_READ);
204: P(&$$,$1);
205: };
206: subvar_get_writes: subvar__get_write | subvar_get_writes subvar__get_write { $$=$1; P(&$$,$2) };
207: subvar__get_write: '$' subvar_ref_name_rdive {
208: $$=$2;
209: A(&$$,OP_GET_ELEMENT__WRITE);
210: };
211:
212:
213: /* with */
214:
215: with: '$' name_without_curly_rdive '{' codes '}' {
216: $$=$2;
217: A(&$$,OP_CREATE_RWPOOL);
218: P(&$$,$4);
219: A(&$$,OP_REDUCE_RWPOOL);
220: A(&$$,OP_WRITE);
221: };
222:
223: /* codes_in_brackets */
224:
225: codes__str__followed_by__excluding_sole_str_literal:
226: write_str_literal codes__excluding_sole_str_literal {
227: $$=$1;
228: P(&$$,$2);
229: }
230: ;
231: codes__excluding_sole_str_literal:
232: action
233: | codes__excluding_sole_str_literal write_str_literal {
234: $$=$1;
235: P(&$$,$2);
236: }
237: ;
238: write_str_literal: STR_LITERAL {
239: $$=$1;
240: A(&$$,OP_WRITE);
241: };
242:
243: /* */
244:
245: empty: /* empty */ { $$=N(PC->pool) };
246:
247: %%
248:
249: /*
250: 000$111(2222)00
251: 000$111{3333}00
252: $,^: push, =0
253: 1:( { break=pop
254: 2:( ) pop
255: 3:{ } pop
256:
257: 000^111(2222)4444{33333}4000
258: $,^: push, =0
259: 1:( { break=pop
260: 2:( )=4
261: 3:{ }=4
262: 4:[^({]=pop
263: */
264:
265: int yylex(YYSTYPE *lvalp, void *pc) {
266: #define lexical_brackets_nestage PC->brackets_nestages[PC->sp]
267:
268: register int c;
269: int result;
270: char *start;
271: int start_line;
272:
273: if(PC->pending_state) {
274: result=PC->pending_state;
275: PC->pending_state=0;
276: return result;
277: }
278:
279: start=PC->source;
280: start_line=PC->line;
281: while(1) {
282: c=*PC->source++;
283:
284: if(c=='\n')
285: PC->line++;
286:
287: /* escaping: ^^ ^$ ^; ^) ^} ^( ^{ */
288: if(c=='^') {
289: char pending_c=*PC->source;
290:
291: if(pending_c == '^' || pending_c == '$' || pending_c == ';' ||
292: pending_c == '(' || pending_c == ')' ||
293: pending_c == '{' || pending_c == '}') {
294: /* append piece till ^ */
295: CSTRING_APPEND(PC->string, start, PC->source-start -1/*^*/, PC->file, start_line);
296: /* reset piece 'start' position & line */
297: start=PC->source+1/*^*/;
298: start_line=PC->line;
299: /* skip over ^ and _ */
300: PC->source+=2;
301: /* skip analysis = forced literal */
302: continue;
303: }
304: }
305: switch(PC->ls) {
306: case LS_USER:
307: if(c=='$') {
308: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
309: result=c;
310: goto break2;
311: }
312: if(c=='^') {
313: push_LS(PC); PC->ls=LS_METHOD_NAME;
314: result=c;
315: goto break2;
316: }
317: break;
318:
319: /* VAR */
320: case LS_VAR_NAME_SIMPLE:
321: if(c==0 ||
322: c==' '|| c=='\t' || c=='\n' ||
323: c==')' || c=='}') {
324: pop_LS(PC);
325: PC->source--;
326: result=BREAK;
327: goto break2;
328: }
329: if(PC->source==start && c=='{') { /* ${name}, no need of BREAK, switching LS */
330: PC->ls=LS_VAR_NAME_CURLY;
331: result=c;
332: goto break2;
333: }
334: if(c=='(') {
335: PC->ls=LS_VAR_ROUND;
336: lexical_brackets_nestage=1;
337: result=c;
338: goto break2;
339: }
340: if(c=='{') {
341: PC->ls=LS_VAR_CURLY;
342: lexical_brackets_nestage=1;
343: result=c;
344: goto break2;
345: }
346: if(c=='.'/* name part delim */ || c=='$'/* name part subvar */) {
347: result=c;
348: goto break2;
349: }
350: break;
351: case LS_VAR_NAME_CURLY:
352: if(c=='}') { /* ${name} finished, restoring LS */
353: pop_LS(PC);
354: result=c;
355: goto break2;
356: }
357: if(c=='.'/* name part delim */ || c=='$'/*name part subvar*/) {
358: result=c;
359: goto break2;
360: }
361: break;
362: case LS_VAR_ROUND:
363: if(c=='$') {
364: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
365: result=c;
366: goto break2;
367: }
368: if(c=='^') {
369: push_LS(PC); PC->ls=LS_METHOD_NAME;
370: result=c;
371: goto break2;
372: }
373: if(c==')') {
374: if(--lexical_brackets_nestage==0) {
375: pop_LS(PC);
376: result=c;
377: goto break2;
378: }
379: }
380: if(c==';'/* operator_or_fmt;value delim */) {
381: result=c;
382: goto break2;
383: }
384: if(c=='(')
385: lexical_brackets_nestage++;
386: break;
387: case LS_VAR_CURLY:
388: if(c=='$') {
389: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
390: result=c;
391: goto break2;
392: }
393: if(c=='^') {
394: push_LS(PC); PC->ls=LS_METHOD_NAME;
395: result=c;
396: goto break2;
397: }
398: if(c=='}')
399: if(--lexical_brackets_nestage==0) {
400: pop_LS(PC);
401: result=c;
402: goto break2;
403: }
404: if(c=='{')
405: lexical_brackets_nestage++;
406: break;
407:
408: /* METHOD */
409: case LS_METHOD_NAME:
410: if(c=='(') {
411: PC->ls=LS_METHOD_ROUND;
412: lexical_brackets_nestage=1;
413: result=c;
414: goto break2;
415: }
416: if(c=='{') {
417: PC->ls=LS_METHOD_CURLY;
418: lexical_brackets_nestage=1;
419: result=c;
420: goto break2;
421: }
422: if(c=='.'/* name part delim */ || c=='$'/* name part subvar */) {
423: result=c;
424: goto break2;
425: }
426: break;
427: case LS_METHOD_ROUND:
428: if(c=='$') {
429: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
430: result=c;
431: goto break2;
432: }
433: if(c=='^') {
434: push_LS(PC); PC->ls=LS_METHOD_NAME;
435: result=c;
436: goto break2;
437: }
438: if(c==';'/* param delim */) {
439: result=c;
440: goto break2;
441: }
442: if(c==')')
443: if(--lexical_brackets_nestage==0) {
444: PC->ls=LS_METHOD_AFTER;
445: result=c;
446: goto break2;
447: }
448: if(c=='(')
449: lexical_brackets_nestage++;
450: break;
451: case LS_METHOD_CURLY:
452: if(c=='$') {
453: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
454: result=c;
455: goto break2;
456: }
457: if(c=='^') {
458: push_LS(PC); PC->ls=LS_METHOD_NAME;
459: result=c;
460: goto break2;
461: }
462: if(c=='}')
463: if(--lexical_brackets_nestage==0) {
464: PC->ls=LS_METHOD_AFTER;
465: result=c;
466: goto break2;
467: }
468: if(c=='{')
469: lexical_brackets_nestage++;
470: break;
471: case LS_METHOD_AFTER:
472: if(c=='(') {/* )( }( */
473: PC->ls=LS_METHOD_ROUND;
474: lexical_brackets_nestage=1;
475: result=c;
476: goto break2;
477: }
478: if(c=='{') {/* ){ }{ */
479: PC->ls=LS_METHOD_CURLY;
480: lexical_brackets_nestage=1;
481: result=c;
482: goto break2;
483: }
484: pop_LS(PC);
485: PC->source--;
486: result=BREAK;
487: goto break2;
488: }
489: if (c == 0) {
490: result=-1;
491: break;
492: }
493: }
494:
495: break2:
1.2 ! paf 496: if(PC->source-1<=start)
1.1 paf 497: return result;
498: else {
499: PC->pending_state=result;
500: /* append last piece */
1.2 ! paf 501: CSTRING_APPEND(PC->string, start, PC->source-start-1, PC->file, start_line);
1.1 paf 502: /* create STR_LITERAL value: array of OP_STRING+string */
503: *lvalp=L(PC->string);
504: /* new pieces storage */
505: PC->string=string_create(PC->pool);
506: /* go */
507: return STR_LITERAL;
508: }
509: }
510:
511: int yyerror (char *s) /* Called by yyparse on error */
512: {
513: printf ("[%s]\n", s);
514: return 1;
515: }
516:
517: static void
518: yyprint (
519: FILE *file,
520: int type,
521: YYSTYPE value)
522: {
523: if (type == STR_LITERAL)
524: fprintf (file, " \"%s\"", string_cstr(LS(value)));
525: }
526: