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