Annotation of parser3/src/main/compile.y, revision 1.86
1.24 paf 1: /*
1.86 ! paf 2: $Id: compile.y,v 1.85 2001/03/10 15:56:16 paf Exp $
1.24 paf 3: */
4:
1.1 paf 5: %{
1.9 paf 6: #define YYSTYPE Array/*<op>*/ *
7: #define YYPARSE_PARAM pc
8: #define YYLEX_PARAM pc
9: #define YYDEBUG 1
1.1 paf 10: #define YYERROR_VERBOSE
1.9 paf 11: #define yyerror(msg) real_yyerror((parse_control *)pc, msg)
12: #define YYPRINT(file, type, value) yyprint(file, type, value)
1.1 paf 13:
14: #include <stdio.h>
15: #include <string.h>
16: #include <stdlib.h>
17:
18: #include "compile_tools.h"
1.8 paf 19: #include "pa_value.h"
1.12 paf 20: #include "pa_request.h"
1.39 paf 21: #include "pa_vobject.h"
1.52 paf 22: #include "pa_vdouble.h"
1.85 paf 23: #include "core.h"
1.39 paf 24:
1.85 paf 25: #define SELF_ELEMENT_NAME "self"
26: #define USE_CONTROL_METHOD_NAME "USE"
1.1 paf 27:
1.9 paf 28: int real_yyerror(parse_control *pc, char *s);
29: static void yyprint(FILE *file, int type, YYSTYPE value);
1.1 paf 30: int yylex(YYSTYPE *lvalp, void *pc);
31:
32:
1.8 paf 33: // local convinient inplace typecast & var
1.9 paf 34: #define PC ((parse_control *)pc)
1.25 paf 35: #define POOL *PC->pool
36: #undef NEW
37: #define NEW new(POOL)
1.1 paf 38: %}
39:
40: %pure_parser
41:
1.13 paf 42: %token EON
1.4 paf 43: %token STRING
1.1 paf 44: %token BOGUS
1.55 paf 45:
1.58 paf 46: %token BAD_STRING_COMPARISON_OPERATOR
47:
1.59 paf 48: %token LAND "&&"
1.58 paf 49: %token LOR "||"
1.59 paf 50: %token LXOR "##"
1.58 paf 51:
52: %token NLE "<="
53: %token NGE ">="
54: %token NEQ "=="
55: %token NNE "!="
56:
57: %token SLT "lt"
58: %token SGT "gt"
59: %token SLE "le"
60: %token SGE "ge"
61: %token SEQ "eq"
62: %token SNE "ne"
63:
1.67 paf 64: %token DEF "def"
65: %token IN "in"
66: %token FEXISTS "-f"
67:
1.57 paf 68: /* logical */
1.61 paf 69: %left "lt" "gt" "le" "ge"
70: %left "eq" "ne"
1.59 paf 71: %left '<' '>' "<=" ">=" "##"
1.57 paf 72: %left "==" "!="
73: %left "||"
74: %left "&&"
1.67 paf 75: %left "def" "in" "-f"
1.68 paf 76: %left '!'
1.57 paf 77:
78: /* bitwise */
1.59 paf 79: %left '#'
1.57 paf 80: %left '&' '|'
1.68 paf 81: %left '~'
1.57 paf 82:
1.56 paf 83: /* numerical */
1.55 paf 84: %left '-' '+'
1.57 paf 85: %left '*' '/' '%'
1.56 paf 86: %left NEG /* negation: unary - */
1.1 paf 87:
88: %%
89:
1.74 paf 90: all: /* TODO: у ^execute непременно задать какой-то name, см. 'RUN' */
1.10 paf 91: one_big_piece {
1.75 paf 92: Method& method=*NEW Method(POOL,
1.85 paf 93: *main_method_name,
1.81 paf 94: 0, 0, /*min, max numbered_params_count*/
1.75 paf 95: 0/*param_names*/, 0/*local_names*/,
96: $1/*parser_code*/, 0/*native_code*/);
1.85 paf 97: PC->vclass->add_method(*main_method_name, method);
1.10 paf 98: }
99: | methods;
100:
101: methods: method | methods method;
102: one_big_piece: maybe_codes;
103:
1.34 paf 104: method: control_method | code_method;
105:
106: control_method: '@' STRING '\n'
107: control_strings {
1.82 paf 108: const String& command=*SLA2S($2);
1.34 paf 109: YYSTYPE strings_code=$4;
1.37 paf 110: if(strings_code->size()<1*2) {
111: strcpy(PC->error, "@");
1.74 paf 112: strcat(PC->error, command.cstr());
1.37 paf 113: strcat(PC->error, " is empty");
114: YYERROR;
115: }
1.74 paf 116: if(command==CLASS_NAME) {
1.76 paf 117: if(PC->vclass!=&PC->request->root_class) { // already changed from default?
1.73 paf 118: strcpy(PC->error, "class already have a name '");
119: strncat(PC->error, PC->vclass->name().cstr(), 100);
120: strcat(PC->error, "'");
121: YYERROR;
122: }
123: if(strings_code->size()==1*2) {
124: // new class' name
1.82 paf 125: const String *name=SLA2S(strings_code);
1.73 paf 126: // creating the class
127: PC->vclass=NEW VClass(POOL);
128: PC->vclass->set_name(*name);
129: // defaulting base. may change with @BASE
1.76 paf 130: PC->vclass->set_base(PC->request->root_class);
1.73 paf 131: // append to request's classes
132: PC->request->classes_array()+=PC->vclass;
133: PC->request->classes().put(*name, PC->vclass);
134: } else {
1.34 paf 135: strcpy(PC->error, "@"CLASS_NAME" must contain sole name");
136: YYERROR;
137: }
138: } else {
1.85 paf 139: if(command==USE_CONTROL_METHOD_NAME) {
1.34 paf 140: for(int i=0; i<strings_code->size(); i+=2) {
1.82 paf 141: String file(*SLA2S(strings_code, i));
142: file.APPEND_CONST(".p");
1.86 ! paf 143: PC->request->use(file.cstr());
1.34 paf 144: }
1.74 paf 145: } else if(command==BASE_NAME) {
1.76 paf 146: if(PC->vclass->base()!=&PC->request->root_class) { // already changed from default?
1.86 ! paf 147: strcpy(PC->error, "class already have a base '");
! 148: strncat(PC->error, PC->vclass->base()->name().cstr(), 100);
! 149: strcat(PC->error, "'");
1.73 paf 150: YYERROR;
151: }
1.45 paf 152: if(strings_code->size()==1*2) {
1.73 paf 153: // TODO: преодолеть self и циклические base
1.82 paf 154: const String& base_name=*SLA2S(strings_code);
1.45 paf 155: VClass *base=static_cast<VClass *>(
156: PC->request->classes().get(base_name));
157: if(!base) {
158: strcpy(PC->error, base_name.cstr());
159: strcat(PC->error, ": undefined class in @"BASE_NAME);
1.34 paf 160: YYERROR;
161: }
1.45 paf 162: PC->vclass->set_base(*base);
163: } else {
164: strcpy(PC->error, "@"BASE_NAME" must contain sole name");
165: YYERROR;
1.34 paf 166: }
167: } else {
1.74 paf 168: strcpy(PC->error, command.cstr());
1.34 paf 169: strcat(PC->error, ": invalid special name. valid names are "
1.85 paf 170: CLASS_NAME", "USE_CONTROL_METHOD_NAME" and "BASE_NAME);
1.34 paf 171: YYERROR;
172: }
173: }
174: };
1.37 paf 175: control_strings: control_string | control_strings control_string { $$=$1; P($$, $2) };
176: control_string: maybe_string '\n';
177: maybe_string: empty | STRING;
1.34 paf 178:
179: code_method: '@' STRING bracketed_maybe_strings maybe_bracketed_strings maybe_comment '\n'
1.10 paf 180: maybe_codes {
1.38 paf 181: const String *name=SLA2S($2);
1.10 paf 182:
183: YYSTYPE params_names_code=$3;
1.75 paf 184: Array *params_names=0;
185: if(int size=params_names_code->size()) {
186: params_names=NEW Array(POOL);
187: for(int i=0; i<size; i+=2)
188: *params_names+=SLA2S(params_names_code, i);
189: }
1.10 paf 190:
191: YYSTYPE locals_names_code=$4;
1.75 paf 192: Array *locals_names=0;
193: if(int size=locals_names_code->size()) {
194: locals_names=NEW Array(POOL);
195: for(int i=0; i<size; i+=2)
196: *locals_names+=SLA2S(locals_names_code, i);
197: }
1.10 paf 198:
1.76 paf 199: Method& method=*NEW Method(POOL,
200: *name,
1.81 paf 201: 0, 0/*min,max numbered_params_count*/,
1.76 paf 202: params_names, locals_names,
203: $7, 0);
1.34 paf 204: PC->vclass->add_method(*name, method);
1.8 paf 205: };
1.10 paf 206:
207: maybe_bracketed_strings: empty | bracketed_maybe_strings;
208: bracketed_maybe_strings: '[' maybe_strings ']' {$$=$2};
209: maybe_strings: empty | strings;
210: strings: STRING | strings ';' STRING { $$=$1; P($$, $3) };
211:
212: maybe_comment: empty | STRING;
1.1 paf 213:
214: /* codes */
215:
1.10 paf 216: maybe_codes: empty | codes;
217:
1.1 paf 218: codes: code | codes code {
219: $$=$1;
1.9 paf 220: P($$, $2);
1.1 paf 221: };
1.81 paf 222: code: write_string | action;
1.1 paf 223: action: get | put | with | call;
224:
225: /* get */
226:
1.64 paf 227: get: get_value {
228: $$=$1; /* stack: resulting value */
1.66 paf 229: O($$, OP_WRITE); /* value=pop; wcontext.write(value) */
1.1 paf 230: };
1.64 paf 231: get_value: '$' get_name_value { $$=$2 }
232: get_name_value: name_without_curly_rdive EON | name_in_curly_rdive;
1.1 paf 233: name_in_curly_rdive: '{' name_without_curly_rdive '}' { $$=$2 };
1.44 paf 234: name_without_curly_rdive:
235: name_without_curly_rdive_read
236: | name_without_curly_rdive_root
237: | name_without_curly_rdive_class;
1.19 paf 238: name_without_curly_rdive_read: name_without_curly_rdive_code {
1.25 paf 239: $$=N(POOL);
1.22 paf 240: Array *diving_code=$1;
1.82 paf 241: const String *first_name=SLA2S(diving_code);
1.85 paf 242: if(first_name && *first_name==SELF_ELEMENT_NAME) {
1.54 paf 243: O($$, OP_WITH_SELF); /* stack: starting context */
1.22 paf 244: P($$, diving_code,
245: /* skip over... */
246: diving_code->size()>2?3/*OP_+string+get_element*/:2/*OP_+string*/);
247: } else {
1.54 paf 248: O($$, OP_WITH_READ); /* stack: starting context */
1.22 paf 249: P($$, diving_code);
250: }
251: /* diving code; stack: current context */
1.1 paf 252: };
1.19 paf 253: name_without_curly_rdive_root: ':' name_without_curly_rdive_code {
1.25 paf 254: $$=N(POOL);
1.54 paf 255: O($$, OP_WITH_ROOT); /* stack: starting context */
1.19 paf 256: P($$, $2); /* diving code; stack: current context */
257: };
1.44 paf 258: name_without_curly_rdive_class: class_prefix name_without_curly_rdive_code { $$=$1; P($$, $2) };
1.19 paf 259: name_without_curly_rdive_code: name_advance2 | name_path name_advance2 { $$=$1; P($$, $2) };
1.1 paf 260:
261: /* put */
262:
1.81 paf 263: put: '$' name_expr_wdive construct {
1.20 paf 264: $$=$2; /* stack: context,name */
1.52 paf 265: P($$, $3); /* stack: context,name,constructor_value */
1.20 paf 266: };
1.44 paf 267: name_expr_wdive:
268: name_expr_wdive_write
269: | name_expr_wdive_root
270: | name_expr_wdive_class;
1.28 paf 271: name_expr_wdive_write: name_expr_dive_code {
1.44 paf 272: $$=N(POOL);
1.23 paf 273: Array *diving_code=$1;
1.82 paf 274: const String *first_name=SLA2S(diving_code);
1.85 paf 275: if(first_name && *first_name==SELF_ELEMENT_NAME) {
1.54 paf 276: O($$, OP_WITH_SELF); /* stack: starting context */
1.23 paf 277: P($$, diving_code,
278: /* skip over... */
279: diving_code->size()>2?3/*OP_+string+get_element*/:2/*OP_+string*/);
280: } else {
1.54 paf 281: O($$, OP_WITH_WRITE); /* stack: starting context */
1.23 paf 282: P($$, diving_code);
283: }
284: /* diving code; stack: current context */
1.20 paf 285: };
1.28 paf 286: name_expr_wdive_root: ':' name_expr_dive_code {
1.25 paf 287: $$=N(POOL);
1.54 paf 288: O($$, OP_WITH_ROOT); /* stack: starting context */
1.9 paf 289: P($$, $2); /* diving code; stack: context,name */
1.1 paf 290: };
1.44 paf 291: name_expr_wdive_class: class_prefix name_expr_dive_code { $$=$1; P($$, $2) };
1.20 paf 292:
1.81 paf 293: construct: construct_by_code | construct_by_expr;
294: construct_by_code: '[' any_constructor_code_value ']' {
295: $$=$2; /* stack: context, name, value */
296: O($$, OP_CONSTRUCT_VALUE); /* value=pop; name=pop; context=pop; construct(context,name,value) */
297: }
298: ;
299: construct_by_expr: '(' any_expr ')' {
300: $$=$2; /* stack: context, name, value */
301: O($$, OP_CONSTRUCT_EXPR); /* value=pop; name=pop; context=pop; construct(context,name,value) */
302: }
1.52 paf 303: ;
1.55 paf 304: any_constructor_code_value:
305: empty_string_value /* optimized $var[] case */
1.52 paf 306: | STRING /* optimized $var[STRING] case */
1.55 paf 307: | constructor_code_value /* $var[something complex] */
1.1 paf 308: ;
1.55 paf 309: constructor_code_value: constructor_code {
1.25 paf 310: $$=N(POOL);
1.54 paf 311: O($$, OP_CREATE_EWPOOL); /* stack: empty write context */
1.69 paf 312: P($$, $1); /* some code that writes to that context */
1.54 paf 313: O($$, OP_REDUCE_EWPOOL); /* context=pop; stack: context.value() */
1.1 paf 314: };
1.55 paf 315: constructor_code: codes__excluding_sole_str_literal;
1.27 paf 316: codes__excluding_sole_str_literal: action | code codes { $$=$1; P($$, $2) };
317:
1.1 paf 318: /* call */
319:
1.66 paf 320: call: call_value {
321: $$=$1; /* stack: value */
322: O($$, OP_WRITE); /* value=pop; wcontext.write(value) */
323: };
324: call_value: '^' call_name store_params EON { /* ^field.$method{vasya} */
1.42 paf 325: $$=$2; /* with_xxx,diving code; stack: context,method_junction */
1.54 paf 326: O($$, OP_GET_METHOD_FRAME); /* stack: context,method_frame */
1.9 paf 327: P($$, $3); /* filling method_frame.store_params */
1.66 paf 328: O($$, OP_CALL); /* method_frame=pop; ncontext=pop; call(ncontext,method_frame) stack: value */
1.1 paf 329: };
330:
1.43 paf 331: call_name: name_without_curly_rdive;
1.38 paf 332:
1.9 paf 333: store_params: store_param | store_params store_param { $$=$1; P($$, $2) };
1.69 paf 334: store_param:
335: store_square_param
336: | store_round_param
337: | store_curly_param
1.31 paf 338: ;
1.69 paf 339: store_square_param: '[' store_code_param_parts ']' {$$=$2};
340: store_round_param: '(' store_expr_param_parts ')' {$$=$2};
1.10 paf 341: store_curly_param: '{' maybe_codes '}' {
1.25 paf 342: $$=N(POOL);
1.29 paf 343: PCA($$, $2);
1.1 paf 344: };
1.69 paf 345: store_code_param_parts:
346: store_code_param_part
347: | store_code_param_parts ';' store_code_param_part { $$=$1; P($$, $3) }
348: ;
349: store_expr_param_parts:
350: store_expr_param_part
351: | store_expr_param_parts ';' store_expr_param_part { $$=$1; P($$, $3) }
352: ;
353: store_code_param_part:
1.78 paf 354: empty /* optimized [] case */
355: | STRING { /* optimized [STRING] case */
1.32 paf 356: $$=$1;
1.54 paf 357: O($$, OP_STORE_PARAM);
1.32 paf 358: }
1.78 paf 359: | constructor_code_value { /* [something complex] */
1.32 paf 360: $$=$1;
1.77 paf 361: O($$, OP_STORE_PARAM);
1.32 paf 362: }
363: ;
1.69 paf 364: store_expr_param_part: write_expr_value {
365: $$=N(POOL);
366: PCA($$, $1);
367: };
368: write_expr_value: any_expr {
369: $$=$1;
370: O($$, OP_WRITE);
371: };
1.1 paf 372:
373: /* name */
374:
1.20 paf 375: name_expr_dive_code: name_expr_value | name_path name_expr_value { $$=$1; P($$, $2) };
1.1 paf 376:
1.9 paf 377: name_path: name_step | name_path name_step { $$=$1; P($$, $2) };
1.1 paf 378: name_step: name_advance1 '.';
379: name_advance1: name_expr_value {
380: /* stack: context */
381: $$=$1; /* stack: context,name */
1.54 paf 382: O($$, OP_GET_ELEMENT); /* name=pop; context=pop; stack: context.get_element(name) */
1.1 paf 383: };
384: name_advance2: name_expr_value {
385: /* stack: context */
386: $$=$1; /* stack: context,name */
1.54 paf 387: O($$, OP_GET_ELEMENT); /* name=pop; context=pop; stack: context.get_element(name) */
1.1 paf 388: }
1.4 paf 389: | STRING BOGUS
1.1 paf 390: ;
391: name_expr_value:
1.4 paf 392: STRING /* subname_is_const */
1.1 paf 393: | name_expr_subvar_value /* $subname_is_var_value */
394: | name_expr_with_subvar_value /* xxx$part_of_subname_is_var_value[$...] */
395: ;
396: name_expr_subvar_value: '$' subvar_ref_name_rdive {
397: $$=$2;
1.54 paf 398: O($$, OP_GET_ELEMENT);
1.1 paf 399: };
1.4 paf 400: name_expr_with_subvar_value: STRING subvar_get_writes {
1.25 paf 401: $$=N(POOL);
1.54 paf 402: O($$, OP_CREATE_EWPOOL);
1.9 paf 403: P($$, $1);
1.54 paf 404: O($$, OP_WRITE);
1.9 paf 405: P($$, $2);
1.54 paf 406: O($$, OP_REDUCE_EWPOOL);
1.1 paf 407: };
1.18 paf 408: subvar_ref_name_rdive: subvar_ref_name_rdive_read | subvar_ref_name_rdive_root;
409: subvar_ref_name_rdive_read: STRING {
1.25 paf 410: $$=N(POOL);
1.54 paf 411: O($$, OP_WITH_READ);
1.9 paf 412: P($$, $1);
1.1 paf 413: };
1.18 paf 414: subvar_ref_name_rdive_root: ':' STRING {
1.25 paf 415: $$=N(POOL);
1.54 paf 416: O($$, OP_WITH_ROOT);
1.18 paf 417: P($$, $2);
418: };
1.9 paf 419: subvar_get_writes: subvar__get_write | subvar_get_writes subvar__get_write { $$=$1; P($$, $2) };
1.1 paf 420: subvar__get_write: '$' subvar_ref_name_rdive {
421: $$=$2;
1.54 paf 422: O($$, OP_GET_ELEMENT__WRITE);
1.42 paf 423: };
424:
1.44 paf 425: class_prefix: STRING ':' {
1.72 paf 426: $$=$1; // stack: class name string
427: O($$, OP_GET_CLASS);
1.1 paf 428: };
429:
430:
431: /* with */
432:
433: with: '$' name_without_curly_rdive '{' codes '}' {
434: $$=$2;
1.54 paf 435: O($$, OP_CREATE_RWPOOL);
1.9 paf 436: P($$, $4);
1.54 paf 437: O($$, OP_REDUCE_RWPOOL);
438: O($$, OP_WRITE);
1.1 paf 439: };
1.53 paf 440:
1.56 paf 441: /* expr */
1.53 paf 442:
1.56 paf 443: any_expr:
1.55 paf 444: empty_double_value /* optimized $var() case */
1.81 paf 445: | expr_value /* $var(something) */
1.53 paf 446: ;
1.81 paf 447: expr_value: expr {
448: if(($$=$1)->size()==2) // only one string literal in there?
1.62 paf 449: change_string_literal_to_double_literal($$); // make that string literal Double
450: };
1.56 paf 451: expr:
1.62 paf 452: STRING
1.64 paf 453: | get_value
1.66 paf 454: | call_value
1.64 paf 455: | '"' string_inside_quotes_value '"' { $$ = $2; }
1.60 paf 456: | '(' expr ')' { $$ = $2; }
457: /* stack: operand // stack: @operand */
458: | '-' expr %prec NEG { $$=$2; O($$, OP_NEG) }
1.68 paf 459: | '~' expr { $$=$2; O($$, OP_INV) }
460: | '!' expr { $$=$2; O($$, OP_NOT) }
461: | "def" expr { $$=$2; O($$, OP_DEF) }
462: | "in" expr { $$=$2; O($$, OP_IN) }
463: | "-f" expr { $$=$2; O($$, OP_FEXISTS) }
1.60 paf 464: /* stack: a,b // stack: a@b */
465: | expr '-' expr { $$=$1; P($$, $3); O($$, OP_SUB) }
466: | expr '+' expr { $$=$1; P($$, $3); O($$, OP_ADD) }
467: | expr '*' expr { $$=$1; P($$, $3); O($$, OP_MUL) }
468: | expr '/' expr { $$=$1; P($$, $3); O($$, OP_DIV) }
469: | expr '%' expr { $$=$1; P($$, $3); O($$, OP_MOD) }
470: | expr '&' expr { $$=$1; P($$, $3); O($$, OP_BIN_AND) }
471: | expr '|' expr { $$=$1; P($$, $3); O($$, OP_BIN_OR) }
472: | expr '#' expr { $$=$1; P($$, $3); O($$, OP_BIN_XOR) }
473: | expr "&&" expr { $$=$1; P($$, $3); O($$, OP_LOG_AND) }
474: | expr "||" expr { $$=$1; P($$, $3); O($$, OP_LOG_OR) }
475: | expr "##" expr { $$=$1; P($$, $3); O($$, OP_LOG_XOR) }
476: | expr '<' expr { $$=$1; P($$, $3); O($$, OP_NUM_LT) }
477: | expr '>' expr { $$=$1; P($$, $3); O($$, OP_NUM_GT) }
478: | expr "<=" expr { $$=$1; P($$, $3); O($$, OP_NUM_LE) }
479: | expr ">=" expr { $$=$1; P($$, $3); O($$, OP_NUM_GE) }
480: | expr "==" expr { $$=$1; P($$, $3); O($$, OP_NUM_EQ) }
481: | expr "!=" expr { $$=$1; P($$, $3); O($$, OP_NUM_NE) }
1.61 paf 482: | expr "lt" expr { $$=$1; P($$, $3); O($$, OP_STR_LT) }
483: | expr "gt" expr { $$=$1; P($$, $3); O($$, OP_STR_GT) }
484: | expr "le" expr { $$=$1; P($$, $3); O($$, OP_STR_LE) }
485: | expr "ge" expr { $$=$1; P($$, $3); O($$, OP_STR_GE) }
486: | expr "eq" expr { $$=$1; P($$, $3); O($$, OP_STR_EQ) }
487: | expr "ne" expr { $$=$1; P($$, $3); O($$, OP_STR_NE) }
1.56 paf 488: ;
1.55 paf 489:
1.65 paf 490: string_inside_quotes_value: maybe_codes {
1.64 paf 491: $$=N(POOL);
492: O($$, OP_CREATE_SWPOOL); /* stack: empty write context */
1.69 paf 493: P($$, $1); /* some code that writes to that context */
1.64 paf 494: O($$, OP_REDUCE_SWPOOL); /* context=pop; stack: context.get_string() */
1.53 paf 495: };
1.1 paf 496:
1.27 paf 497: /* basics */
1.1 paf 498:
1.81 paf 499: write_string: STRING {
1.84 paf 500: // optimized from OP_STRING+OP_WRITE to OP_STRING__WRITE
501: change_string_literal_to_write_string_literal($$=$1)
1.54 paf 502: };
503:
1.79 paf 504: empty_double_value: /* empty */ { $$=VL(NEW VDouble(POOL, 0)) };
1.81 paf 505: empty_string_value: /* empty */ { $$=VL(NEW VString(POOL)) };
1.25 paf 506: empty: /* empty */ { $$=N(POOL) };
1.1 paf 507:
508: %%
509:
510: /*
511: 000$111(2222)00
512: 000$111{3333}00
1.9 paf 513: $,^: push,=0
1.1 paf 514: 1:( { break=pop
515: 2:( ) pop
516: 3:{ } pop
517:
518: 000^111(2222)4444{33333}4000
1.9 paf 519: $,^: push,=0
1.1 paf 520: 1:( { break=pop
521: 2:( )=4
522: 3:{ }=4
523: 4:[^({]=pop
524: */
525:
526: int yylex(YYSTYPE *lvalp, void *pc) {
527: #define lexical_brackets_nestage PC->brackets_nestages[PC->sp]
1.48 paf 528: #define RC {result=c; goto break2; }
1.1 paf 529:
530: register int c;
531: int result;
532:
533: if(PC->pending_state) {
534: result=PC->pending_state;
535: PC->pending_state=0;
536: return result;
537: }
538:
1.9 paf 539: char *begin=PC->source;
540: char *end;
541: int begin_line=PC->line;
1.67 paf 542: int skip_analized=0;
1.50 paf 543: while(true) {
1.9 paf 544: c=*(end=(PC->source++));
1.1 paf 545:
1.4 paf 546: if(c=='\n') {
1.1 paf 547: PC->line++;
1.8 paf 548: PC->col=0;
1.10 paf 549: } else
1.4 paf 550: PC->col++;
1.73 paf 551:
552: // todo: # in 0+1 column comment
1.1 paf 553:
1.48 paf 554: // escaping: ^^ ^$ ^; ^) ^} ^( ^{ ^"
555: if(c=='^')
556: switch(*PC->source) {
557: case '^': case '$': case ';':
558: case '[': case ']':
559: case '{': case '}':
560: case '"':
1.40 paf 561: if(end!=begin) {
562: // append piece till ^
563: PC->string->APPEND(begin, end-begin, PC->file, begin_line);
564: }
1.63 paf 565: // reset piece 'begin' position & line
1.40 paf 566: begin=PC->source; // ^
1.9 paf 567: begin_line=PC->line;
1.40 paf 568: // skip over ^ and _
1.50 paf 569: PC->source++; PC->col++;
1.40 paf 570: // skip analysis = forced literal
1.1 paf 571: continue;
572: }
573: switch(PC->ls) {
1.10 paf 574:
575: // USER'S = NOT OURS
1.1 paf 576: case LS_USER:
1.48 paf 577: switch(c) {
578: case '$':
1.10 paf 579: push_LS(PC, LS_VAR_NAME_SIMPLE);
1.48 paf 580: RC;
581: case '^':
582: push_LS(PC, LS_METHOD_NAME);
583: RC;
584: case '@':
585: if(PC->col==0+1) {
586: push_LS(PC, LS_DEF_NAME);
587: RC;
588: }
589: break;
1.1 paf 590: }
1.48 paf 591: break;
592:
593: // STRING IN EXPRESSION
594: case LS_EXPRESSION_STRING:
595: switch(c) {
596: case '"':
597: pop_LS(PC); //"abc".
598: RC;
599: case '$':
600: push_LS(PC, LS_VAR_NAME_SIMPLE);
601: RC;
602: case '^':
1.10 paf 603: push_LS(PC, LS_METHOD_NAME);
1.48 paf 604: RC;
1.10 paf 605: }
606: break;
607:
608: // METHOD DEFINITION
609: case LS_DEF_NAME:
1.48 paf 610: switch(c) {
611: case '[':
1.10 paf 612: PC->ls=LS_DEF_PARAMS;
1.48 paf 613: RC;
614: case '\n':
615: PC->ls=LS_DEF_SPECIAL_BODY;
616: RC;
1.10 paf 617: }
618: break;
1.48 paf 619:
1.10 paf 620: case LS_DEF_PARAMS:
1.48 paf 621: switch(c) {
622: case ';':
623: RC;
624: case ']':
1.10 paf 625: PC->ls=*PC->source=='['?LS_DEF_LOCALS:LS_DEF_COMMENT;
1.48 paf 626: RC;
1.49 paf 627: case '\n': // wrong. bailing out
1.10 paf 628: pop_LS(PC);
1.48 paf 629: RC;
1.10 paf 630: }
631: break;
1.48 paf 632:
1.10 paf 633: case LS_DEF_LOCALS:
1.48 paf 634: switch(c) {
635: case '[':
636: case ';':
637: RC;
638: case ']':
1.10 paf 639: PC->ls=LS_DEF_COMMENT;
1.48 paf 640: RC;
641: case '\n': // wrong. bailing out
1.10 paf 642: pop_LS(PC);
1.48 paf 643: RC;
1.10 paf 644: }
645: break;
1.48 paf 646:
1.10 paf 647: case LS_DEF_COMMENT:
648: if(c=='\n') {
649: pop_LS(PC);
1.48 paf 650: RC;
1.37 paf 651: }
652: break;
653:
1.48 paf 654: case LS_DEF_SPECIAL_BODY:
1.37 paf 655: if(c=='\n') {
1.48 paf 656: switch(*PC->source) {
657: case '@': case 0: // end of special_code
1.37 paf 658: pop_LS(PC);
1.48 paf 659: break;
660: }
661: RC;
662: }
663: break;
664:
665: // (EXPRESSION)
1.69 paf 666: case LS_VAR_ROUND:
667: case LS_METHOD_ROUND:
1.48 paf 668: switch(c) {
669: case ')':
670: if(--lexical_brackets_nestage==0)
1.69 paf 671: if(PC->ls==LS_METHOD_ROUND) // method round param ended
672: PC->ls=LS_METHOD_AFTER; // look for method end
673: else // PC->ls==LS_VAR_ROUND // variable constructor ended
674: pop_LS(PC); // return to normal life
1.48 paf 675: RC;
676: case '$':
1.69 paf 677: push_LS(PC, LS_EXPRESSION_VAR_NAME);
1.48 paf 678: RC;
679: case '^':
680: push_LS(PC, LS_METHOD_NAME);
681: RC;
682: case '(':
683: lexical_brackets_nestage++;
684: RC;
1.67 paf 685: case '-':
686: if(*PC->source=='f') { // -f
687: skip_analized=1;
688: result=FEXISTS;
689: } else
690: result=c;
691: goto break2;
692: case '+': case '*': case '/': case '%':
1.58 paf 693: case '~':
1.48 paf 694: case ';':
695: RC;
1.59 paf 696: case '&': case '|': case '#':
1.58 paf 697: if(*PC->source==c) { // && ||
1.59 paf 698: result=c=='#'?LXOR:c=='&'?LAND:LOR;
1.67 paf 699: skip_analized=1;
1.58 paf 700: } else
701: result=c;
702: goto break2;
703: case '<': case '>': case '=': case '!':
704: if(*PC->source=='=') { // <= >= == !=
1.67 paf 705: skip_analized=1;
1.58 paf 706: switch(c) {
707: case '<': result=NLE; break;
708: case '>': result=NGE; break;
709: case '=': result=NEQ; break;
710: case '!': result=NNE; break;
711: }
712: } else
713: result=c;
714: goto break2;
1.48 paf 715: case '"':
716: push_LS(PC, LS_EXPRESSION_STRING);
717: RC;
1.50 paf 718: case 'l': case 'g': case 'e': case 'n':
1.51 paf 719: if(end==begin) // right after whitespace
1.58 paf 720: switch(*PC->source) {
1.51 paf 721: // case '?': // ok [and bad cases, yacc would bark at them]
722: case 't': // lt gt [et nt]
1.62 paf 723: result=c=='l'?SLT:c=='g'?SGT:BAD_STRING_COMPARISON_OPERATOR;
1.67 paf 724: skip_analized=1;
1.58 paf 725: goto break2;
1.51 paf 726: case 'e': // le ge ne [ee]
1.58 paf 727: result=c=='l'?SLE:c=='g'?SGE:c=='n'?SNE:BAD_STRING_COMPARISON_OPERATOR;
1.67 paf 728: skip_analized=1;
1.58 paf 729: goto break2;
1.51 paf 730: case 'q': // eq [lq gq nq]
1.58 paf 731: result=c=='e'?SEQ:BAD_STRING_COMPARISON_OPERATOR;
1.67 paf 732: skip_analized=1;
733: goto break2;
734: }
735: break;
736: case 'i':
737: if(end==begin) // right after whitespace
738: if(PC->source[0]=='n') { // in
739: skip_analized=1;
740: result=IN;
741: goto break2;
742: }
743: break;
744: case 'd':
745: if(end==begin) // right after whitespace
746: if(PC->source[0]=='e' && PC->source[1]=='f') { // def
747: skip_analized=2;
748: result=DEF;
1.58 paf 749: goto break2;
1.50 paf 750: }
1.48 paf 751: break;
752: case ' ': case '\t': case '\n':
1.63 paf 753: if(end!=begin) { // there were a string after previous operator?
754: result=0; // return that string
755: goto break2;
1.48 paf 756: }
1.63 paf 757: // that's a leading|traling space or after-operator-space
758: // ignoring it
759: // reset piece 'begin' position & line
1.58 paf 760: begin=PC->source; // after whitespace char
1.48 paf 761: begin_line=PC->line;
762: continue;
1.1 paf 763: }
764: break;
765:
1.10 paf 766: // VARIABLE GET/PUT/WITH
1.1 paf 767: case LS_VAR_NAME_SIMPLE:
1.69 paf 768: case LS_EXPRESSION_VAR_NAME:
769: if(PC->ls==LS_EXPRESSION_VAR_NAME) {
1.56 paf 770: // name in expr ends also before binary operators
1.48 paf 771: switch(c) {
772: case '+': case '-': case '*': case '/': case '%':
773: case '&': case '|':
1.83 paf 774: case '=': case '!':
1.48 paf 775: pop_LS(PC);
776: PC->source--; if(--PC->col<0) { PC->line--; PC->col=-1; }
777: result=EON;
778: goto break2;
779: }
780: }
781: switch(c) {
782: case 0:
783: case ' ': case '\t': case '\n':
784: case ';':
1.64 paf 785: case ']': case '}': case ')': case '"':
1.83 paf 786: case '<': case '>': // these stand for HTML brackets and expression binary ops
1.1 paf 787: pop_LS(PC);
1.32 paf 788: PC->source--; if(--PC->col<0) { PC->line--; PC->col=-1; }
1.13 paf 789: result=EON;
1.1 paf 790: goto break2;
1.48 paf 791: case '[':
792: PC->ls=LS_VAR_SQUARE;
1.1 paf 793: lexical_brackets_nestage=1;
1.48 paf 794: RC;
795: case '{':
796: if(begin==end) { // ${name}, no need of EON, switching LS
797: PC->ls=LS_VAR_NAME_CURLY;
798: } else {
799: PC->ls=LS_VAR_CURLY;
800: lexical_brackets_nestage=1;
801: }
1.69 paf 802:
1.48 paf 803: RC;
804: case '(':
1.69 paf 805: PC->ls=LS_VAR_ROUND;
1.1 paf 806: lexical_brackets_nestage=1;
1.48 paf 807: RC;
808: case '.': // name part delim
809: case '$': // name part subvar
810: case ':': // ':name' or 'class:name'
811: RC;
1.1 paf 812: }
813: break;
1.48 paf 814:
1.1 paf 815: case LS_VAR_NAME_CURLY:
1.48 paf 816: switch(c) {
817: case '}': // ${name} finished, restoring LS
1.1 paf 818: pop_LS(PC);
1.48 paf 819: RC;
820: case '.': // name part delim
821: case '$': // name part subvar
822: case ':': // ':name' or 'class:name'
823: RC;
1.1 paf 824: }
825: break;
1.48 paf 826:
827: case LS_VAR_SQUARE:
828: switch(c) {
829: case '$':
1.10 paf 830: push_LS(PC, LS_VAR_NAME_SIMPLE);
1.48 paf 831: RC;
832: case '^':
1.10 paf 833: push_LS(PC, LS_METHOD_NAME);
1.48 paf 834: RC;
835: case ']':
1.1 paf 836: if(--lexical_brackets_nestage==0) {
837: pop_LS(PC);
1.48 paf 838: RC;
1.1 paf 839: }
1.48 paf 840: break;
841: case ';': // operator_or_fmt;value delim
842: RC;
843: case '[':
844: lexical_brackets_nestage++;
845: break;
1.1 paf 846: }
847: break;
1.48 paf 848:
1.1 paf 849: case LS_VAR_CURLY:
1.48 paf 850: switch(c) {
851: case '$':
1.10 paf 852: push_LS(PC, LS_VAR_NAME_SIMPLE);
1.48 paf 853: RC;
854: case '^':
1.10 paf 855: push_LS(PC, LS_METHOD_NAME);
1.48 paf 856: RC;
857: case '}':
1.1 paf 858: if(--lexical_brackets_nestage==0) {
859: pop_LS(PC);
1.48 paf 860: RC;
1.1 paf 861: }
1.48 paf 862: break;
863: case '{':
1.1 paf 864: lexical_brackets_nestage++;
1.48 paf 865: break;
866: }
1.1 paf 867: break;
868:
1.10 paf 869: // METHOD CALL
1.1 paf 870: case LS_METHOD_NAME:
1.48 paf 871: switch(c) {
872: case '[':
873: PC->ls=LS_METHOD_SQUARE;
1.1 paf 874: lexical_brackets_nestage=1;
1.48 paf 875: RC;
876: case '{':
1.1 paf 877: PC->ls=LS_METHOD_CURLY;
878: lexical_brackets_nestage=1;
1.48 paf 879: RC;
1.69 paf 880: case '(':
881: PC->ls=LS_METHOD_ROUND;
882: lexical_brackets_nestage=1;
883: RC;
1.48 paf 884: case '.': // name part delim
885: case '$': // name part subvar
886: case ':': // ':name' or 'class:name'
887: RC;
1.1 paf 888: }
889: break;
1.48 paf 890:
891: case LS_METHOD_SQUARE:
892: switch(c) {
893: case '$':
1.10 paf 894: push_LS(PC, LS_VAR_NAME_SIMPLE);
1.48 paf 895: RC;
896: case '^':
1.10 paf 897: push_LS(PC, LS_METHOD_NAME);
1.48 paf 898: RC;
899: case ';': // param delim
900: RC;
901: case ']':
1.1 paf 902: if(--lexical_brackets_nestage==0) {
903: PC->ls=LS_METHOD_AFTER;
1.48 paf 904: RC;
1.1 paf 905: }
1.48 paf 906: break;
907: case '[':
1.1 paf 908: lexical_brackets_nestage++;
1.48 paf 909: break;
910: }
1.1 paf 911: break;
1.48 paf 912:
1.1 paf 913: case LS_METHOD_CURLY:
1.48 paf 914: switch(c) {
915: case '$':
1.10 paf 916: push_LS(PC, LS_VAR_NAME_SIMPLE);
1.48 paf 917: RC;
918: case '^':
1.10 paf 919: push_LS(PC, LS_METHOD_NAME);
1.48 paf 920: RC;
921: case '}':
1.1 paf 922: if(--lexical_brackets_nestage==0) {
923: PC->ls=LS_METHOD_AFTER;
1.48 paf 924: RC;
1.1 paf 925: }
1.48 paf 926: break;
927: case '{':
1.1 paf 928: lexical_brackets_nestage++;
1.48 paf 929: break;
930: }
1.1 paf 931: break;
1.48 paf 932:
1.1 paf 933: case LS_METHOD_AFTER:
1.69 paf 934: if(c=='[') {/* ][ }[ )[ */
1.48 paf 935: PC->ls=LS_METHOD_SQUARE;
1.1 paf 936: lexical_brackets_nestage=1;
1.48 paf 937: RC;
1.1 paf 938: }
1.69 paf 939: if(c=='{') {/* ]{ }{ ){ */
1.1 paf 940: PC->ls=LS_METHOD_CURLY;
1.69 paf 941: lexical_brackets_nestage=1;
942: RC;
943: }
944: if(c=='(') {/* ]( }( )( */
945: PC->ls=LS_METHOD_ROUND;
1.1 paf 946: lexical_brackets_nestage=1;
1.48 paf 947: RC;
1.1 paf 948: }
949: pop_LS(PC);
1.32 paf 950: PC->source--; if(--PC->col<0) { PC->line--; PC->col=-1; }
1.13 paf 951: result=EON;
1.1 paf 952: goto break2;
953: }
1.9 paf 954: if(c==0) {
1.1 paf 955: result=-1;
956: break;
957: }
958: }
959:
960: break2:
1.59 paf 961: if(end!=begin) { // there is last piece?
962: if((c=='@' || c==0) && end[-1]=='\n') { // we are before LS_DEF_NAME or EOF?
963: // strip last \n
1.10 paf 964: end--;
1.59 paf 965: }
966: if(end!=begin) { // last piece still alive?
967: // append it
1.30 paf 968: PC->string->APPEND(begin, end-begin, PC->file, begin_line/*, start_col*/);
969: }
1.59 paf 970: }
971: if(PC->string->size()) { // something accumulated?
1.17 paf 972: // create STRING value: array of OP_VALUE+vstring
1.55 paf 973: *lvalp=VL(NEW VString(*PC->string));
1.10 paf 974: // new pieces storage
1.25 paf 975: PC->string=NEW String(POOL);
1.58 paf 976: // make current result be pending for next call, return STRING for now
977: PC->pending_state=result; result=STRING;
978: }
1.67 paf 979: if(skip_analized) {
980: PC->source+=skip_analized; PC->col+=skip_analized;
1.1 paf 981: }
1.58 paf 982: return result;
1.1 paf 983: }
984:
1.9 paf 985: int real_yyerror(parse_control *pc, char *s) /* Called by yyparse on error */
1.1 paf 986: {
1.16 paf 987: //fprintf(stderr, "[%s]\n", s);
1.6 paf 988:
1.46 paf 989: strncpy(pc->error, s, MAX_STRING); // TODO: перепроверить с треклятым последним байтом
1.1 paf 990: return 1;
991: }
992:
993: static void
1.9 paf 994: yyprint(
1.1 paf 995: FILE *file,
996: int type,
997: YYSTYPE value)
998: {
1.9 paf 999: if(type==STRING)
1.38 paf 1000: fprintf(file, " \"%s\"", SLA2S(value)->cstr());
1.1 paf 1001: }
1002:
E-mail: