|
|
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"
1.8 ! paf 15: #include "pa_value.h"
1.1 paf 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.8 ! paf 22: // local convinient inplace typecast & var
1.4 paf 23: #define PC ((parse_control *)pc)
1.8 ! paf 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.3 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.3 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.3 paf 72: P($$,$1); /* diving code; stack: current context */
1.1 paf 73: };
1.3 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 */
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 */
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.3 paf 116: P($$, $1);/* stack: ncontext name operator_or_fmt */
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 */
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.3 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.3 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.3 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);
170: AA($$,$2);
171: OP($$,OP_CREATE_JUNCTION);
172: OP($$,OP_STORE_PARAM);
1.1 paf 173: };
174:
175: /* name */
176:
1.3 paf 177: name_expr_dive: name_expr_value | name_path name_expr_value { $$=$1; P($$,$2) };
1.1 paf 178:
1.3 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.3 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.3 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.3 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);
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.3 paf 216: P($$,$1);
1.1 paf 217: };
1.3 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.3 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.3 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.3 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.3 paf 247: P($$,$2);
1.1 paf 248: }
249: ;
1.4 paf 250: write_str_literal: STRING {
1.1 paf 251: $$=$1;
1.3 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
264: $,^: push, =0
265: 1:( { break=pop
266: 2:( ) pop
267: 3:{ } pop
268:
269: 000^111(2222)4444{33333}4000
270: $,^: push, =0
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: char *start;
283: int start_line;
284:
285: if(PC->pending_state) {
286: result=PC->pending_state;
287: PC->pending_state=0;
288: return result;
289: }
290:
291: start=PC->source;
292: start_line=PC->line;
293: while(1) {
294: c=*PC->source++;
295:
1.4 paf 296: if(c=='\n') {
1.1 paf 297: PC->line++;
1.8 ! paf 298: PC->col=0;
1.4 paf 299: }
300: PC->col++;
1.1 paf 301:
302: /* escaping: ^^ ^$ ^; ^) ^} ^( ^{ */
303: if(c=='^') {
304: char pending_c=*PC->source;
305:
306: if(pending_c == '^' || pending_c == '$' || pending_c == ';' ||
307: pending_c == '(' || pending_c == ')' ||
308: pending_c == '{' || pending_c == '}') {
309: /* append piece till ^ */
1.3 paf 310: PC->string->APPEND(start, PC->source-start -1/*^*/, PC->file, start_line);
1.1 paf 311: /* reset piece 'start' position & line */
312: start=PC->source+1/*^*/;
313: start_line=PC->line;
314: /* skip over ^ and _ */
315: PC->source+=2;
316: /* skip analysis = forced literal */
317: continue;
318: }
319: }
320: switch(PC->ls) {
321: case LS_USER:
322: if(c=='$') {
323: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
324: result=c;
325: goto break2;
326: }
327: if(c=='^') {
328: push_LS(PC); PC->ls=LS_METHOD_NAME;
329: result=c;
330: goto break2;
331: }
332: break;
333:
334: /* VAR */
335: case LS_VAR_NAME_SIMPLE:
336: if(c==0 ||
337: c==' '|| c=='\t' || c=='\n' ||
338: c==')' || c=='}') {
339: pop_LS(PC);
1.4 paf 340: PC->source--; PC->col--;
341: result=END_OF_NAME;
1.1 paf 342: goto break2;
343: }
1.4 paf 344: if(PC->source==start && c=='{') { /* ${name}, no need of END_OF_NAME, switching LS */
1.1 paf 345: PC->ls=LS_VAR_NAME_CURLY;
346: result=c;
347: goto break2;
348: }
349: if(c=='(') {
350: PC->ls=LS_VAR_ROUND;
351: lexical_brackets_nestage=1;
352: result=c;
353: goto break2;
354: }
355: if(c=='{') {
356: PC->ls=LS_VAR_CURLY;
357: lexical_brackets_nestage=1;
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_NAME_CURLY:
367: if(c=='}') { /* ${name} finished, restoring LS */
368: pop_LS(PC);
369: result=c;
370: goto break2;
371: }
372: if(c=='.'/* name part delim */ || c=='$'/*name part subvar*/) {
373: result=c;
374: goto break2;
375: }
376: break;
377: case LS_VAR_ROUND:
378: if(c=='$') {
379: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
380: result=c;
381: goto break2;
382: }
383: if(c=='^') {
384: push_LS(PC); PC->ls=LS_METHOD_NAME;
385: result=c;
386: goto break2;
387: }
388: if(c==')') {
389: if(--lexical_brackets_nestage==0) {
390: pop_LS(PC);
391: result=c;
392: goto break2;
393: }
394: }
395: if(c==';'/* operator_or_fmt;value delim */) {
396: result=c;
397: goto break2;
398: }
399: if(c=='(')
400: lexical_brackets_nestage++;
401: break;
402: case LS_VAR_CURLY:
403: if(c=='$') {
404: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
405: result=c;
406: goto break2;
407: }
408: if(c=='^') {
409: push_LS(PC); PC->ls=LS_METHOD_NAME;
410: result=c;
411: goto break2;
412: }
413: if(c=='}')
414: if(--lexical_brackets_nestage==0) {
415: pop_LS(PC);
416: result=c;
417: goto break2;
418: }
419: if(c=='{')
420: lexical_brackets_nestage++;
421: break;
422:
423: /* METHOD */
424: case LS_METHOD_NAME:
425: if(c=='(') {
426: PC->ls=LS_METHOD_ROUND;
427: lexical_brackets_nestage=1;
428: result=c;
429: goto break2;
430: }
431: if(c=='{') {
432: PC->ls=LS_METHOD_CURLY;
433: lexical_brackets_nestage=1;
434: result=c;
435: goto break2;
436: }
437: if(c=='.'/* name part delim */ || c=='$'/* name part subvar */) {
438: result=c;
439: goto break2;
440: }
441: break;
442: case LS_METHOD_ROUND:
443: if(c=='$') {
444: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
445: result=c;
446: goto break2;
447: }
448: if(c=='^') {
449: push_LS(PC); PC->ls=LS_METHOD_NAME;
450: result=c;
451: goto break2;
452: }
453: if(c==';'/* param delim */) {
454: result=c;
455: goto break2;
456: }
457: if(c==')')
458: if(--lexical_brackets_nestage==0) {
459: PC->ls=LS_METHOD_AFTER;
460: result=c;
461: goto break2;
462: }
463: if(c=='(')
464: lexical_brackets_nestage++;
465: break;
466: case LS_METHOD_CURLY:
467: if(c=='$') {
468: push_LS(PC); PC->ls=LS_VAR_NAME_SIMPLE;
469: result=c;
470: goto break2;
471: }
472: if(c=='^') {
473: push_LS(PC); PC->ls=LS_METHOD_NAME;
474: result=c;
475: goto break2;
476: }
477: if(c=='}')
478: if(--lexical_brackets_nestage==0) {
479: PC->ls=LS_METHOD_AFTER;
480: result=c;
481: goto break2;
482: }
483: if(c=='{')
484: lexical_brackets_nestage++;
485: break;
486: case LS_METHOD_AFTER:
487: if(c=='(') {/* )( }( */
488: PC->ls=LS_METHOD_ROUND;
489: lexical_brackets_nestage=1;
490: result=c;
491: goto break2;
492: }
493: if(c=='{') {/* ){ }{ */
494: PC->ls=LS_METHOD_CURLY;
495: lexical_brackets_nestage=1;
496: result=c;
497: goto break2;
498: }
499: pop_LS(PC);
1.4 paf 500: PC->source--; PC->col--;
501: result=END_OF_NAME;
1.1 paf 502: goto break2;
503: }
504: if (c == 0) {
505: result=-1;
1.4 paf 506: PC->source--; PC->col--;
1.1 paf 507: break;
508: }
509: }
510:
511: break2:
1.5 paf 512: if(PC->source-1<=start)
1.1 paf 513: return result;
514: else {
515: PC->pending_state=result;
516: /* append last piece */
1.4 paf 517: PC->string->APPEND(start, PC->source-start-1, PC->file, start_line/*, start_col*/);
518: /* create STRING value: array of OP_STRING+string */
1.1 paf 519: *lvalp=L(PC->string);
520: /* new pieces storage */
1.8 ! paf 521: PC->string=new(pool) String(pool);
1.1 paf 522: /* go */
1.4 paf 523: return STRING;
1.1 paf 524: }
525: }
526:
1.4 paf 527: int real_yyerror (parse_control *pc, char *s) /* Called by yyparse on error */
1.1 paf 528: {
1.4 paf 529: fprintf (stderr, "[%s]\n", s);
1.6 paf 530:
531: s[MAX_STRING-1]=0; strcpy(pc->error, s);
1.1 paf 532: return 1;
533: }
534:
535: static void
536: yyprint (
537: FILE *file,
538: int type,
539: YYSTYPE value)
540: {
1.4 paf 541: if (type == STRING)
1.3 paf 542: fprintf (file, " \"%s\"", LA2S(value)->cstr());
1.1 paf 543: }
544: