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