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