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