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