--- parser3/src/main/compile.y 2001/03/09 08:19:50 1.81 +++ parser3/src/main/compile.y 2001/03/13 14:28:51 1.95 @@ -1,9 +1,24 @@ /* - $Id: compile.y,v 1.81 2001/03/09 08:19:50 paf Exp $ + Parser + Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) + Author: Alexander Petrosyan (http://design.ru/paf) + + $Id: compile.y,v 1.95 2001/03/13 14:28:51 paf Exp $ +*/ + +/* + TODO.parser4: + cache compiled code from request to request. to do that... + 1: make method definitions, @CLASS, @BASE, @USE instructions, + which would be executed afterwards, and actions + now performed at compile time would be delayed to run time. + 2: make cache expiration on time and on disk-change of class source + 3: in apache use subpools for compiled class storage + 4: in iis make up specialized Pool object for that */ %{ -#define YYSTYPE Array/**/ * +#define YYSTYPE Array/**/ * #define YYPARSE_PARAM pc #define YYLEX_PARAM pc #define YYDEBUG 1 @@ -20,9 +35,10 @@ #include "pa_request.h" #include "pa_vobject.h" #include "pa_vdouble.h" +#include "core.h" -#define SELF_NAME "self" -#define USE_NAME "USE" +#define SELF_ELEMENT_NAME "self" +#define USE_CONTROL_METHOD_NAME "use" int real_yyerror(parse_control *pc, char *s); static void yyprint(FILE *file, int type, YYSTYPE value); @@ -63,8 +79,10 @@ int yylex(YYSTYPE *lvalp, void *pc); %token DEF "def" %token IN "in" %token FEXISTS "-f" +%token IS "is" /* logical */ +%left "is" %left "lt" "gt" "le" "ge" %left "eq" "ne" %left '<' '>' "<=" ">=" "##" @@ -85,17 +103,14 @@ int yylex(YYSTYPE *lvalp, void *pc); %left NEG /* negation: unary - */ %% - -all: /* TODO: у ^execute непременно задать какой-то name, см. 'RUN' */ +all: one_big_piece { - String& MAIN=*NEW String(POOL); - MAIN.APPEND_CONST(MAIN_METHOD_NAME); Method& method=*NEW Method(POOL, - MAIN, + *main_method_name, 0, 0, /*min, max numbered_params_count*/ 0/*param_names*/, 0/*local_names*/, $1/*parser_code*/, 0/*native_code*/); - PC->vclass->add_method(MAIN, method); + PC->cclass->add_method(*main_method_name, method); } | methods; @@ -106,7 +121,7 @@ method: control_method | code_method; control_method: '@' STRING '\n' control_strings { - String& command=*SLA2S($2); + const String& command=*SLA2S($2); YYSTYPE strings_code=$4; if(strings_code->size()<1*2) { strcpy(PC->error, "@"); @@ -115,42 +130,44 @@ control_method: '@' STRING '\n' YYERROR; } if(command==CLASS_NAME) { - if(PC->vclass!=&PC->request->root_class) { // already changed from default? + if(PC->cclass!=&PC->request->root_class) { // already changed from default? strcpy(PC->error, "class already have a name '"); - strncat(PC->error, PC->vclass->name().cstr(), 100); + strncat(PC->error, PC->cclass->name().cstr(), 100); strcat(PC->error, "'"); YYERROR; } if(strings_code->size()==1*2) { // new class' name - String *name=SLA2S(strings_code); + const String *name=SLA2S(strings_code); // creating the class - PC->vclass=NEW VClass(POOL); - PC->vclass->set_name(*name); + PC->cclass=NEW VClass(POOL); + PC->cclass->set_name(*name); // defaulting base. may change with @BASE - PC->vclass->set_base(PC->request->root_class); + PC->cclass->set_base(PC->request->root_class); // append to request's classes - PC->request->classes_array()+=PC->vclass; - PC->request->classes().put(*name, PC->vclass); + PC->request->classes_array()+=PC->cclass; + PC->request->classes().put(*name, PC->cclass); } else { strcpy(PC->error, "@"CLASS_NAME" must contain sole name"); YYERROR; } } else { - if(command==USE_NAME) { + if(command==USE_CONTROL_METHOD_NAME) { for(int i=0; isize(); i+=2) { - String *file=SLA2S(strings_code, i); - file->APPEND_CONST(".p"); - PC->request->use(file->cstr(), 0); + String file(*SLA2S(strings_code, i)); + file.APPEND_CONST(".p"); + PC->request->use_file(file.cstr()); } } else if(command==BASE_NAME) { - if(PC->vclass->base()!=&PC->request->root_class) { // already changed from default? - strcpy(PC->error, "there must be only one @"BASE_NAME); + if(PC->cclass->base()!=&PC->request->root_class) { // already changed from default? + strcpy(PC->error, "class already have a base '"); + strncat(PC->error, PC->cclass->base()->name().cstr(), 100); + strcat(PC->error, "'"); YYERROR; } if(strings_code->size()==1*2) { // TODO: преодолеть self и циклические base - String& base_name=*SLA2S(strings_code); + const String& base_name=*SLA2S(strings_code); VClass *base=static_cast( PC->request->classes().get(base_name)); if(!base) { @@ -158,15 +175,16 @@ control_method: '@' STRING '\n' strcat(PC->error, ": undefined class in @"BASE_NAME); YYERROR; } - PC->vclass->set_base(*base); + PC->cclass->set_base(*base); } else { strcpy(PC->error, "@"BASE_NAME" must contain sole name"); YYERROR; } } else { - strcpy(PC->error, command.cstr()); - strcat(PC->error, ": invalid special name. valid names are " - CLASS_NAME", "USE_NAME" and "BASE_NAME); + strcpy(PC->error, "'"); + strncat(PC->error, command.cstr(), MAX_STRING/2); + strcat(PC->error, "' invalid special name. valid names are " + "'"CLASS_NAME"', '"USE_CONTROL_METHOD_NAME"' and '"BASE_NAME"'"); YYERROR; } } @@ -200,7 +218,7 @@ code_method: '@' STRING bracketed_maybe_ 0, 0/*min,max numbered_params_count*/, params_names, locals_names, $7, 0); - PC->vclass->add_method(*name, method); + PC->cclass->add_method(*name, method); }; maybe_bracketed_strings: empty | bracketed_maybe_strings; @@ -214,10 +232,7 @@ maybe_comment: empty | STRING; maybe_codes: empty | codes; -codes: code | codes code { - $$=$1; - P($$, $2); -}; +codes: code | codes code { $$=$1; P($$, $2) }; code: write_string | action; action: get | put | with | call; @@ -237,8 +252,8 @@ name_without_curly_rdive: name_without_curly_rdive_read: name_without_curly_rdive_code { $$=N(POOL); Array *diving_code=$1; - String *first_name=SLA2S(diving_code); - if(first_name && *first_name==SELF_NAME) { + const String *first_name=SLA2S(diving_code); + if(first_name && *first_name==SELF_ELEMENT_NAME) { O($$, OP_WITH_SELF); /* stack: starting context */ P($$, diving_code, /* skip over... */ @@ -270,8 +285,8 @@ name_expr_wdive: name_expr_wdive_write: name_expr_dive_code { $$=N(POOL); Array *diving_code=$1; - String *first_name=SLA2S(diving_code); - if(first_name && *first_name==SELF_NAME) { + const String *first_name=SLA2S(diving_code); + if(first_name && *first_name==SELF_ELEMENT_NAME) { O($$, OP_WITH_SELF); /* stack: starting context */ P($$, diving_code, /* skip over... */ @@ -295,7 +310,7 @@ construct_by_code: '[' any_constructor_c O($$, OP_CONSTRUCT_VALUE); /* value=pop; name=pop; context=pop; construct(context,name,value) */ } ; -construct_by_expr: '(' any_expr ')' { +construct_by_expr: '(' expr_value ')' { $$=$2; /* stack: context, name, value */ O($$, OP_CONSTRUCT_EXPR); /* value=pop; name=pop; context=pop; construct(context,name,value) */ } @@ -337,10 +352,7 @@ store_param: ; store_square_param: '[' store_code_param_parts ']' {$$=$2}; store_round_param: '(' store_expr_param_parts ')' {$$=$2}; -store_curly_param: '{' maybe_codes '}' { - $$=N(POOL); - PCA($$, $2); -}; +store_curly_param: '{' store_curly_param_parts '}' {$$=$2}; store_code_param_parts: store_code_param_part | store_code_param_parts ';' store_code_param_part { $$=$1; P($$, $3) } @@ -349,6 +361,10 @@ store_expr_param_parts: store_expr_param_part | store_expr_param_parts ';' store_expr_param_part { $$=$1; P($$, $3) } ; +store_curly_param_parts: + store_curly_param_part +| store_curly_param_parts ';' store_curly_param_part { $$=$1; P($$, $3) } +; store_code_param_part: empty /* optimized [] case */ | STRING { /* optimized [STRING] case */ @@ -364,7 +380,11 @@ store_expr_param_part: write_expr_value $$=N(POOL); PCA($$, $1); }; -write_expr_value: any_expr { +store_curly_param_part: maybe_codes { + $$=N(POOL); + PCA($$, $1); +}; +write_expr_value: expr_value { $$=$1; O($$, OP_WRITE); }; @@ -439,10 +459,6 @@ with: '$' name_without_curly_rdive '{' c /* expr */ -any_expr: - empty_double_value /* optimized $var() case */ -| expr_value /* $var(something) */ -; expr_value: expr { if(($$=$1)->size()==2) // only one string literal in there? change_string_literal_to_double_literal($$); // make that string literal Double @@ -484,6 +500,7 @@ expr: | expr "ge" expr { $$=$1; P($$, $3); O($$, OP_STR_GE) } | expr "eq" expr { $$=$1; P($$, $3); O($$, OP_STR_EQ) } | expr "ne" expr { $$=$1; P($$, $3); O($$, OP_STR_NE) } +| expr "is" expr { $$=$1; P($$, $3); O($$, OP_IS) } ; string_inside_quotes_value: maybe_codes { @@ -496,11 +513,10 @@ string_inside_quotes_value: maybe_codes /* basics */ write_string: STRING { - $$=$1; - O($$, OP_WRITE); + // optimized from OP_STRING+OP_WRITE to OP_STRING__WRITE + change_string_literal_to_write_string_literal($$=$1) }; -empty_double_value: /* empty */ { $$=VL(NEW VDouble(POOL, 0)) }; empty_string_value: /* empty */ { $$=VL(NEW VString(POOL)) }; empty: /* empty */ { $$=N(POOL) }; @@ -535,8 +551,8 @@ int yylex(YYSTYPE *lvalp, void *pc) { return result; } - char *begin=PC->source; - char *end; + const char *begin=PC->source; + const char *end; int begin_line=PC->line; int skip_analized=0; while(true) { @@ -734,10 +750,19 @@ int yylex(YYSTYPE *lvalp, void *pc) { break; case 'i': if(end==begin) // right after whitespace - if(PC->source[0]=='n') { // in - skip_analized=1; - result=IN; - goto break2; + switch(PC->source[0]) { + case 'n': + { // in + skip_analized=1; + result=IN; + goto break2; + } + case 's': + { // is + skip_analized=1; + result=IS; + goto break2; + } } break; case 'd': @@ -768,9 +793,7 @@ int yylex(YYSTYPE *lvalp, void *pc) { if(PC->ls==LS_EXPRESSION_VAR_NAME) { // name in expr ends also before binary operators switch(c) { - case '+': case '-': case '*': case '/': case '%': - case '&': case '|': - case '<': case '>': case '=': case '!': + case '-': pop_LS(PC); PC->source--; if(--PC->col<0) { PC->line--; PC->col=-1; } result=EON; @@ -782,6 +805,10 @@ int yylex(YYSTYPE *lvalp, void *pc) { case ' ': case '\t': case '\n': case ';': case ']': case '}': case ')': case '"': + case '<': case '>': // these stand for HTML brackets and expression binary ops + case '+': case '*': case '/': case '%': + case '&': case '|': + case '=': case '!': pop_LS(PC); PC->source--; if(--PC->col<0) { PC->line--; PC->col=-1; } result=EON; @@ -916,6 +943,8 @@ int yylex(YYSTYPE *lvalp, void *pc) { case '^': push_LS(PC, LS_METHOD_NAME); RC; + case ';': // param delim + RC; case '}': if(--lexical_brackets_nestage==0) { PC->ls=LS_METHOD_AFTER;