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