--- parser3/src/main/compile.y 2003/10/07 14:29:03 1.207 +++ parser3/src/main/compile.y 2008/05/30 12:27:44 1.223 @@ -2,10 +2,10 @@ /** @file Parser: compiler(lexical parser and grammar). - Copyright (c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com) Author: Alexander Petrosyan (http://design.ru/paf) - $Id: compile.y,v 1.207 2003/10/07 14:29:03 paf Exp $ + $Id: compile.y,v 1.223 2008/05/30 12:27:44 misha Exp $ */ /** @@ -41,6 +41,7 @@ // defines #define USE_CONTROL_METHOD_NAME "USE" +#define OPTIONS_CONTROL_METHOD_NAME "OPTION" // forwards @@ -48,6 +49,9 @@ static int real_yyerror(Parse_control* p static void yyprint(FILE* file, int type, YYSTYPE value); static int yylex(YYSTYPE* lvalp, void* pc); +static const VBool vfalse(false); +static const VBool vtrue(true); +static const VVoid vvoid; // local convinient inplace typecast & var #undef PC @@ -67,7 +71,7 @@ static int yylex(YYSTYPE* lvalp, void* p %token BAD_HEX_LITERAL %token BAD_METHOD_DECL_START %token BAD_METHOD_PARAMETER_NAME_CHARACTER -%token BAD_MATH_OPERATOR_CHARACTER +%token BAD_NONWHITESPACE_CHARACTER_IN_EXPLICIT_RESULT_MODE %token LAND "&&" %token LOR "||" @@ -94,6 +98,9 @@ static int yylex(YYSTYPE* lvalp, void* p %token DEXISTS "-d" %token IS "is" +%token LITERAL_TRUE "true" +%token LITERAL_FALSE "false" + /* logical */ %left "!||" %left "||" @@ -197,11 +204,22 @@ control_method: '@' STRING '\n' strcpy(PC.error, "@"BASE_NAME" must contain sole name"); YYERROR; } + } else if(command==OPTIONS_CONTROL_METHOD_NAME) { + for(size_t i=0; icount(); i+=OPERATIONS_PER_OPVALUE) { + const String& option=*LA2S(*strings_code, i); + if(option==ALL_VARS_LOCAL_NAME){ + PC.cclass->all_vars_local(); + } else { + strcpy(PC.error, option.cstr()); + strcat(PC.error, ": unknown option in @"OPTIONS_CONTROL_METHOD_NAME" was specified."); + YYERROR; + } + } } else { 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"'"); + "'"CLASS_NAME"', '"USE_CONTROL_METHOD_NAME"', '"BASE_NAME"' and '"OPTIONS_CONTROL_METHOD_NAME"'."); YYERROR; } }; @@ -210,9 +228,8 @@ control_strings: control_string | contro control_string: maybe_string '\n'; maybe_string: empty | STRING; -code_method: '@' STRING bracketed_maybe_strings maybe_bracketed_strings maybe_comment '\n' - maybe_codes { - const String& name=*LA2S(*$2); +code_method: '@' STRING bracketed_maybe_strings maybe_bracketed_strings maybe_comment '\n' { + PC.explicit_result=false; YYSTYPE params_names_code=$3; ArrayString* params_names=0; @@ -224,19 +241,40 @@ code_method: '@' STRING bracketed_maybe_ YYSTYPE locals_names_code=$4; ArrayString* locals_names=0; + bool all_vars_local=false; if(int size=locals_names_code->count()) { locals_names=new ArrayString; - for(int i=0; iis_vars_local()){ + all_vars_local=true; } - Method& method=*new Method( + Method* method=new Method( //name, Method::CT_ANY, 0, 0/*min,max numbered_params_count*/, params_names, locals_names, - $7, 0); - PC.cclass->add_method(PC.alias_method(name), method); + 0/*to be filled later in next {} */, 0, all_vars_local); + + *reinterpret_cast(&$$)=method; + + // todo: check [][;result;] +} maybe_codes { + Method& method=*reinterpret_cast($7); + // fill in the code + method.parser_code=$8; + // register in class + const String& name=*LA2S(*$2); + PC.cclass->add_method(PC.alias_method(name), method); }; maybe_bracketed_strings: empty | bracketed_maybe_strings; @@ -333,9 +371,14 @@ construct: | construct_round | construct_curly ; -construct_square: '[' any_constructor_code_value ']' { +construct_square: '[' { + // allow $result_or_other_variable[ letters here any time ] + *reinterpret_cast(&$$)=PC.explicit_result; PC.explicit_result=false; +} any_constructor_code_value { + PC.explicit_result=*reinterpret_cast(&$2); +} ']' { // stack: context, name - $$=$2; // stack: context, name, value + $$=$3; // stack: context, name, value O(*$$, OP_CONSTRUCT_VALUE); /* value=pop; name=pop; context=pop; construct(context,name,value) */ } ; @@ -387,7 +430,7 @@ call_value: '^' { YYSTYPE params_code=$5; if(params_code->count()==4) { // probably [] case. [OP_VALUE+origin+Void+STORE_PARAM] if(Value* value=LA2V(*params_code)) // it is OP_VALUE+origin+value? - if(!value->is_defined()) // value is VVoid? + if(value->is_void()) // value is VVoid? params_code=0; // ^zzz[] case. don't append lone empty param. } /* stack: context, method_junction */ @@ -402,7 +445,12 @@ store_param: | store_round_param | store_curly_param ; -store_square_param: '[' store_code_param_parts ']' {$$=$2}; +store_square_param: '[' { + // allow ^call[ letters here any time ] + *reinterpret_cast(&$$)=PC.explicit_result; PC.explicit_result=false; +} store_code_param_parts { + PC.explicit_result=*reinterpret_cast(&$2); +} ']' {$$=$3}; store_round_param: '(' store_expr_param_parts ')' {$$=$2}; store_curly_param: '{' store_curly_param_parts '}' {$$=$2}; store_code_param_parts: @@ -421,9 +469,20 @@ store_code_param_part: code_param_value $$=$1; O(*$$, OP_STORE_PARAM); }; -store_expr_param_part: write_expr_value { - $$=N(); - OA(*$$, OP_EXPR_CODE__STORE_PARAM, $1); +store_expr_param_part: expr_value { + YYSTYPE expr_code=$1; + if(expr_code->count()==3 + && (*expr_code)[0].code==OP_VALUE) { // optimizing (double/bool/incidently 'string' too) case. [OP_VALUE+origin+Double] + $$=expr_code; + O(*$$, OP_STORE_PARAM); // no evaluating + } else { + ArrayOperation* code=N(); + O(*code, OP_PREPARE_TO_EXPRESSION); + P(*code, *expr_code); + O(*code, OP_WRITE_EXPR_RESULT); + $$=N(); + OA(*$$, OP_EXPR_CODE__STORE_PARAM, code); + } }; store_curly_param_part: maybe_codes { $$=N(); @@ -434,12 +493,6 @@ code_param_value: | STRING /* optimized [STRING] case */ | constructor_code_value /* [something complex] */ ; -write_expr_value: expr_value { - $$=N(); - O(*$$, OP_PREPARE_TO_EXPRESSION); - P(*$$, *$1); - O(*$$, OP_WRITE_EXPR_RESULT); -}; /* name */ @@ -481,9 +534,14 @@ name_expr_with_subvar_value: STRING subv $$=N(); OA(*$$, OP_STRING_POOL, code); }; -name_square_code_value: '[' codes ']' { +name_square_code_value: '[' { + // allow $result_or_other_variable[ letters here any time ] + *reinterpret_cast(&$$)=PC.explicit_result; PC.explicit_result=false; +} codes { + PC.explicit_result=*reinterpret_cast(&$2); +} ']' { $$=N(); - OA(*$$, OP_OBJECT_POOL, $2); /* stack: empty write context */ + OA(*$$, OP_OBJECT_POOL, $3); /* stack: empty write context */ /* some code that writes to that context */ /* context=pop; stack: context.value() */ }; @@ -526,17 +584,15 @@ class_constructor_prefix: class_static_p /* expr */ -expr_value: expr { - // see OP_PREPARE_TO_EXPRESSION!! - if(($$=$1)->count()==2) // only one string literal in there? - change_string_literal_to_double_literal(*$$); // make that string literal Double -}; +expr_value: expr; expr: - STRING + double_or_STRING +| true_value +| false_value | get_value | call_value -| '"' string_inside_quotes_value '"' { $$ = $2; } -| '\'' string_inside_quotes_value '\'' { $$ = $2; } +| '"' string_inside_quotes_value '"' { $$ = $2 } +| '\'' string_inside_quotes_value '\'' { $$ = $2 } | '(' expr ')' { $$ = $2; } /* stack: operand // stack: @operand */ | '-' expr %prec NUNARY { $$=$2; O(*$$, OP_NEG) } @@ -577,6 +633,11 @@ expr: | expr "is" expr { $$=$1; P(*$$, *$3); O(*$$, OP_IS) } ; +double_or_STRING: STRING { + // optimized from OP_STRING->OP_VALUE for doubles + maybe_change_string_literal_to_double_literal(*($$=$1)); +}; + string_inside_quotes_value: maybe_codes { $$=N(); OA(*$$, OP_STRING_POOL, $1); /* stack: empty write context */ @@ -591,7 +652,10 @@ write_string: STRING { change_string_literal_to_write_string_literal(*($$=$1)) }; -void_value: /* empty */ { $$=VL(new VVoid(), 0, 0, 0) }; +void_value: /* empty */ { $$=VL(/*we know that we will not change it*/const_cast(&vvoid), 0, 0, 0) } +true_value: "true" { $$ = VL(/*we know that we will not change it*/const_cast(&vtrue), 0, 0, 0) } +false_value: "false" { $$ = VL(/*we know that we will not change it*/const_cast(&vfalse), 0, 0, 0) } + empty: /* empty */ { $$=N() }; %% @@ -644,12 +708,13 @@ static int yylex(YYSTYPE *lvalp, void *a c=*(end=(pc.source++)); // fprintf(stderr, "\nchar: %c %02X; nestage: %d, sp=%d", c, c, lexical_brackets_nestage, pc.sp); - if(c=='\n') { + if(c=='\n') pc.pos_next_line(); - } else + else pc.pos_next_c(c); +// fprintf(stderr, "\nchar: %c file(%d:%d)", c, pc.pos.line, pc.pos.col); - if(c=='@' && pc.pos.col==0+1) { + if(pc.pos.col==0+1 && c=='@') { if(pc.ls==LS_DEF_SPECIAL_BODY) { // @SPECIAL // ... @@ -662,7 +727,8 @@ static int yylex(YYSTYPE *lvalp, void *a } else // @ in first column inside some code [when could that be?] result=BAD_METHOD_DECL_START; goto break2; - } else if(c=='^') { + } + if(c=='^') { if(pc.ls==LS_METHOD_AFTER) { // handle after-method situation pop_LS(pc); @@ -713,9 +779,9 @@ default: } // #HH ? if(pc.source[0]=='#' && pc.source[1] && pc.source[2]) { - char c= + char c=(char)( hex_value[(unsigned char)pc.source[1]]*0x10+ - hex_value[(unsigned char)pc.source[2]]; + hex_value[(unsigned char)pc.source[2]]); if(c==0) { result=BAD_HEX_LITERAL; goto break2; // wrong hex value[no ^#00 chars allowed]: bail out @@ -781,6 +847,16 @@ default: lexical_brackets_nestage++; break; } + if(pc.explicit_result && c) + switch(c) { + case '\n': case ' ': case '\t': + begin=pc.source; + begin_pos=pc.pos; + continue; // skip it + default: + result=BAD_NONWHITESPACE_CHARACTER_IN_EXPLICIT_RESULT_MODE; + goto break2; + } break; // #COMMENT @@ -1023,6 +1099,22 @@ default: goto break2; } break; + case 't': + if(end==begin) // right after whitespace + if(pc.source[0]=='r' && pc.source[1]=='u' && pc.source[2]=='e') { // def + skip_analized=3; + result=LITERAL_TRUE; + goto break2; + } + break; + case 'f': + if(end==begin) // right after whitespace + if(pc.source[0]=='a' && pc.source[1]=='l' && pc.source[2]=='s' && pc.source[3]=='e') { // def + skip_analized=4; + result=LITERAL_FALSE; + goto break2; + } + break; case ' ': case '\t': case '\n': if(end!=begin) { // there were a string after previous operator? result=0; // return that string @@ -1099,6 +1191,8 @@ default: case '=': case '!': // common delimiters case ',': case '?': case '#': + // mysql column separators + case '`': // before call case '^': pop_LS(pc); @@ -1281,6 +1375,16 @@ default: lexical_brackets_nestage++; break; } + if(pc.explicit_result && c) + switch(c) { + case '\n': case ' ': case '\t': + begin=pc.source; + begin_pos=pc.pos; + continue; // skip it + default: + result=BAD_NONWHITESPACE_CHARACTER_IN_EXPLICIT_RESULT_MODE; + goto break2; + } break; case LS_METHOD_AFTER: