|
|
| version 1.204.2.8.2.12, 2003/04/03 12:25:33 | version 1.221, 2007/10/17 13:34:59 |
|---|---|
| Line 2 | Line 2 |
| /** @file | /** @file |
| Parser: compiler(lexical parser and grammar). | 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 <paf@design.ru> (http://design.ru/paf) | Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf) |
| $Id$ | $Id$ |
| Line 41 | Line 41 |
| // defines | // defines |
| #define USE_CONTROL_METHOD_NAME "USE" | #define USE_CONTROL_METHOD_NAME "USE" |
| #define TAB_SIZE 8 | |
| // forwards | // forwards |
| Line 49 static int real_yyerror(Parse_control* p | Line 48 static int real_yyerror(Parse_control* p |
| static void yyprint(FILE* file, int type, YYSTYPE value); | static void yyprint(FILE* file, int type, YYSTYPE value); |
| static int yylex(YYSTYPE* lvalp, void* pc); | 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 | // local convinient inplace typecast & var |
| #undef PC | #undef PC |
| Line 68 static int yylex(YYSTYPE* lvalp, void* p | Line 70 static int yylex(YYSTYPE* lvalp, void* p |
| %token BAD_HEX_LITERAL | %token BAD_HEX_LITERAL |
| %token BAD_METHOD_DECL_START | %token BAD_METHOD_DECL_START |
| %token BAD_METHOD_PARAMETER_NAME_CHARACTER | %token BAD_METHOD_PARAMETER_NAME_CHARACTER |
| %token BAD_MATH_OPERATOR_CHARACTER | %token BAD_NONWHITESPACE_CHARACTER_IN_EXPLICIT_RESULT_MODE |
| %token LAND "&&" | %token LAND "&&" |
| %token LOR "||" | %token LOR "||" |
| Line 95 static int yylex(YYSTYPE* lvalp, void* p | Line 97 static int yylex(YYSTYPE* lvalp, void* p |
| %token DEXISTS "-d" | %token DEXISTS "-d" |
| %token IS "is" | %token IS "is" |
| %token LITERAL_TRUE "true" | |
| %token LITERAL_FALSE "false" | |
| /* logical */ | /* logical */ |
| %left "!||" | %left "!||" |
| %left "||" | %left "||" |
| Line 138 control_method: '@' STRING '\n' | Line 143 control_method: '@' STRING '\n' |
| maybe_control_strings { | maybe_control_strings { |
| const String& command=*LA2S(*$2); | const String& command=*LA2S(*$2); |
| YYSTYPE strings_code=$4; | YYSTYPE strings_code=$4; |
| if(strings_code->count()<1*2) { | if(strings_code->count()<1*OPERATIONS_PER_OPVALUE) { |
| strcpy(PC.error, "@"); | strcpy(PC.error, "@"); |
| strcat(PC.error, command.cstr()); | strcat(PC.error, command.cstr()); |
| strcat(PC.error, " is empty"); | strcat(PC.error, " is empty"); |
| Line 151 control_method: '@' STRING '\n' | Line 156 control_method: '@' STRING '\n' |
| strcat(PC.error, "'"); | strcat(PC.error, "'"); |
| YYERROR; | YYERROR; |
| } | } |
| if(strings_code->count()==1*2) { | if(strings_code->count()==1*OPERATIONS_PER_OPVALUE) { |
| // new class' name | // new class' name |
| const String& name=*LA2S(*strings_code); | const String& name=*LA2S(*strings_code); |
| // creating the class | // creating the class |
| Line 161 control_method: '@' STRING '\n' | Line 166 control_method: '@' STRING '\n' |
| // append to request's classes | // append to request's classes |
| PC.request.classes().put(name, cclass); | PC.request.classes().put(name, cclass); |
| } else { | } else { |
| strcpy(PC.error, "@"CLASS_NAME" must contain sole name"); | strcpy(PC.error, "@"CLASS_NAME" must contain only one line with class name (contains more then one)"); |
| YYERROR; | YYERROR; |
| } | } |
| } else if(command==USE_CONTROL_METHOD_NAME) { | } else if(command==USE_CONTROL_METHOD_NAME) { |
| for(size_t i=0; i<strings_code->count(); i+=2) | for(size_t i=0; i<strings_code->count(); i+=OPERATIONS_PER_OPVALUE) |
| PC.request.use_file(PC.request.main_class, *LA2S(*strings_code, i)); | PC.request.use_file(PC.request.main_class, *LA2S(*strings_code, i)); |
| } else if(command==BASE_NAME) { | } else if(command==BASE_NAME) { |
| if(PC.cclass->base_class()) { // already changed from default? | if(PC.cclass->base_class()) { // already changed from default? |
| Line 174 control_method: '@' STRING '\n' | Line 179 control_method: '@' STRING '\n' |
| strcat(PC.error, "'"); | strcat(PC.error, "'"); |
| YYERROR; | YYERROR; |
| } | } |
| if(strings_code->count()==1*2) { | if(strings_code->count()==1*OPERATIONS_PER_OPVALUE) { |
| const String& base_name=*LA2S(*strings_code); | const String& base_name=*LA2S(*strings_code); |
| if(Value* base_class_value=PC.request.classes().get(base_name)) { | if(Value* base_class_value=PC.request.classes().get(base_name)) { |
| // @CLASS == @BASE sanity check | // @CLASS == @BASE sanity check |
| Line 211 control_strings: control_string | contro | Line 216 control_strings: control_string | contro |
| control_string: maybe_string '\n'; | control_string: maybe_string '\n'; |
| maybe_string: empty | STRING; | maybe_string: empty | STRING; |
| code_method: '@' STRING bracketed_maybe_strings maybe_bracketed_strings maybe_comment '\n' | code_method: '@' STRING bracketed_maybe_strings maybe_bracketed_strings maybe_comment '\n' maybe_codes { |
| maybe_codes { | PC.explicit_result=false; |
| const String& name=*LA2S(*$2); | const String& name=*LA2S(*$2); |
| YYSTYPE params_names_code=$3; | YYSTYPE params_names_code=$3; |
| ArrayString* params_names=0; | ArrayString* params_names=0; |
| if(int size=params_names_code->count()) { | if(int size=params_names_code->count()) { |
| params_names=new ArrayString; | params_names=new ArrayString; |
| for(int i=0; i<size; i+=2) | for(int i=0; i<size; i+=OPERATIONS_PER_OPVALUE) |
| *params_names+=LA2S(*params_names_code, i); | *params_names+=LA2S(*params_names_code, i); |
| } | } |
| Line 227 code_method: '@' STRING bracketed_maybe_ | Line 232 code_method: '@' STRING bracketed_maybe_ |
| ArrayString* locals_names=0; | ArrayString* locals_names=0; |
| if(int size=locals_names_code->count()) { | if(int size=locals_names_code->count()) { |
| locals_names=new ArrayString; | locals_names=new ArrayString; |
| for(int i=0; i<size; i+=2) | for(int i=0; i<size; i+=OPERATIONS_PER_OPVALUE) { |
| *locals_names+=LA2S(*locals_names_code, i); | const String* local_name=LA2S(*locals_names_code, i); |
| if(*local_name==RESULT_VAR_NAME) | |
| PC.explicit_result=true; | |
| else | |
| *locals_names+=local_name; | |
| } | |
| } | } |
| Method& method=*new Method( | Method* method=new Method( |
| //name, | //name, |
| Method::CT_ANY, | Method::CT_ANY, |
| 0, 0/*min,max numbered_params_count*/, | 0, 0/*min,max numbered_params_count*/, |
| params_names, locals_names, | params_names, locals_names, |
| $7, 0); | $7, 0); |
| PC.cclass->add_method(PC.alias_method(name), method); | |
| PC.cclass->add_method(PC.alias_method(name), *method); | |
| *reinterpret_cast<Method**>(&$$)=method; | |
| // todo: check [][;result;] | |
| }; | }; |
| maybe_bracketed_strings: empty | bracketed_maybe_strings; | maybe_bracketed_strings: empty | bracketed_maybe_strings; |
| Line 275 name_without_curly_rdive_read: name_with | Line 289 name_without_curly_rdive_read: name_with |
| ArrayOperation* diving_code=$1; | ArrayOperation* diving_code=$1; |
| const String* first_name=LA2S(*diving_code); | const String* first_name=LA2S(*diving_code); |
| // self.xxx... -> xxx... | // self.xxx... -> xxx... |
| // OP_VALUE+string+OP_GET_ELEMENT+... -> OP_WITH_SELF+... | // OP_VALUE+origin+string+OP_GET_ELEMENT+... -> OP_WITH_SELF+... |
| if(first_name && *first_name==SELF_ELEMENT_NAME) { | if(first_name && *first_name==SELF_ELEMENT_NAME) { |
| O(*$$, OP_WITH_SELF); /* stack: starting context */ | O(*yyval, OP_WITH_SELF); /* stack: starting context */ |
| P(*$$, *diving_code, | P(*yyval, *diving_code, |
| /* skip over... */ | /* skip over... */ |
| diving_code->count()>=3?3/*OP_VALUE+string+OP_GET_ELEMENTx*/:2/*OP_+string*/); | diving_code->count()>=4?4/*OP_VALUE+origin+string+OP_GET_ELEMENTx*/:3/*OP_+origin+string*/); |
| } else { | } else { |
| O(*$$, OP_WITH_READ); /* stack: starting context */ | O(*yyval, OP_WITH_READ); /* stack: starting context */ |
| // ^if ELEMENT -> ^if ELEMENT_OR_OPERATOR | // ^if ELEMENT -> ^if ELEMENT_OR_OPERATOR |
| // OP_VALUE+string+OP_GET_ELEMENT. -> OP_VALUE+string+OP_GET_ELEMENT_OR_OPERATOR. | // OP_VALUE+origin+string+OP_GET_ELEMENT. -> OP_VALUE+origin+string+OP_GET_ELEMENT_OR_OPERATOR. |
| if(PC.in_call_value && diving_code->count()==3) | if(PC.in_call_value && diving_code->count()==4) |
| diving_code->put(2, OP_GET_ELEMENT_OR_OPERATOR); | diving_code->put(4-1, OP_GET_ELEMENT_OR_OPERATOR); |
| P(*$$, *diving_code); | P(*$$, *diving_code); |
| } | } |
| /* diving code; stack: current context */ | /* diving code; stack: current context */ |
| Line 310 name_expr_wdive_root: name_expr_dive_cod | Line 324 name_expr_wdive_root: name_expr_dive_cod |
| ArrayOperation* diving_code=$1; | ArrayOperation* diving_code=$1; |
| const String* first_name=LA2S(*diving_code); | const String* first_name=LA2S(*diving_code); |
| // $self.xxx... -> $xxx... | // $self.xxx... -> $xxx... |
| // OP_VALUE+string+OP_GET_ELEMENT+... -> OP_WITH_SELF+... | // OP_VALUE+origin+string+OP_GET_ELEMENT+... -> OP_WITH_SELF+... |
| if(first_name && *first_name==SELF_ELEMENT_NAME) { | if(first_name && *first_name==SELF_ELEMENT_NAME) { |
| O(*$$, OP_WITH_SELF); /* stack: starting context */ | O(*$$, OP_WITH_SELF); /* stack: starting context */ |
| P(*$$, *diving_code, | P(*$$, *diving_code, |
| /* skip over... */ | /* skip over... */ |
| diving_code->count()>=3?3/*OP_VALUE+string+OP_GET_ELEMENTx*/:2/*OP_+string*/); | diving_code->count()>=4?4/*OP_VALUE+origin+string+OP_GET_ELEMENTx*/:3/*OP_+origin+string*/); |
| } else { | } else { |
| O(*$$, OP_WITH_ROOT); /* stack: starting context */ | O(*$$, OP_WITH_ROOT); /* stack: starting context */ |
| P(*$$, *diving_code); | P(*$$, *diving_code); |
| Line 334 construct: | Line 348 construct: |
| | construct_round | | construct_round |
| | construct_curly | | construct_curly |
| ; | ; |
| construct_square: '[' any_constructor_code_value ']' { | construct_square: '[' { |
| // allow $result_or_other_variable[ letters here any time ] | |
| *reinterpret_cast<bool*>(&$$)=PC.explicit_result; PC.explicit_result=false; | |
| } any_constructor_code_value { | |
| PC.explicit_result=*reinterpret_cast<bool*>(&$2); | |
| } ']' { | |
| // stack: context, name | // 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) */ | O(*$$, OP_CONSTRUCT_VALUE); /* value=pop; name=pop; context=pop; construct(context,name,value) */ |
| } | } |
| ; | ; |
| Line 386 call_value: '^' { | Line 405 call_value: '^' { |
| $$=$3; /* with_xxx,diving code; stack: context,method_junction */ | $$=$3; /* with_xxx,diving code; stack: context,method_junction */ |
| YYSTYPE params_code=$5; | YYSTYPE params_code=$5; |
| if(params_code->count()==3) { // probably [] case. [OP_VALUE + Void + STORE_PARAM] | if(params_code->count()==4) { // probably [] case. [OP_VALUE+origin+Void+STORE_PARAM] |
| if(Value* value=LA2V(*params_code)) // it is OP_VALUE + value? | 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. | params_code=0; // ^zzz[] case. don't append lone empty param. |
| } | } |
| /* stack: context, method_junction */ | /* stack: context, method_junction */ |
| Line 403 store_param: | Line 422 store_param: |
| | store_round_param | | store_round_param |
| | store_curly_param | | store_curly_param |
| ; | ; |
| store_square_param: '[' store_code_param_parts ']' {$$=$2}; | store_square_param: '[' { |
| // allow ^call[ letters here any time ] | |
| *reinterpret_cast<bool*>(&$$)=PC.explicit_result; PC.explicit_result=false; | |
| } store_code_param_parts { | |
| PC.explicit_result=*reinterpret_cast<bool*>(&$2); | |
| } ']' {$$=$3}; | |
| store_round_param: '(' store_expr_param_parts ')' {$$=$2}; | store_round_param: '(' store_expr_param_parts ')' {$$=$2}; |
| store_curly_param: '{' store_curly_param_parts '}' {$$=$2}; | store_curly_param: '{' store_curly_param_parts '}' {$$=$2}; |
| store_code_param_parts: | store_code_param_parts: |
| Line 422 store_code_param_part: code_param_value | Line 446 store_code_param_part: code_param_value |
| $$=$1; | $$=$1; |
| O(*$$, OP_STORE_PARAM); | O(*$$, OP_STORE_PARAM); |
| }; | }; |
| store_expr_param_part: write_expr_value { | store_expr_param_part: expr_value { |
| $$=N(); | YYSTYPE expr_code=$1; |
| OA(*$$, OP_EXPR_CODE__STORE_PARAM, $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 { | store_curly_param_part: maybe_codes { |
| $$=N(); | $$=N(); |
| Line 435 code_param_value: | Line 470 code_param_value: |
| | STRING /* optimized [STRING] case */ | | STRING /* optimized [STRING] case */ |
| | constructor_code_value /* [something complex] */ | | constructor_code_value /* [something complex] */ |
| ; | ; |
| write_expr_value: expr_value { | |
| $$=N(); | |
| O(*$$, OP_PREPARE_TO_EXPRESSION); | |
| P(*$$, *$1); | |
| O(*$$, OP_WRITE_EXPR_RESULT); | |
| }; | |
| /* name */ | /* name */ |
| Line 482 name_expr_with_subvar_value: STRING subv | Line 511 name_expr_with_subvar_value: STRING subv |
| $$=N(); | $$=N(); |
| OA(*$$, OP_STRING_POOL, code); | 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<bool*>(&$$)=PC.explicit_result; PC.explicit_result=false; | |
| } codes { | |
| PC.explicit_result=*reinterpret_cast<bool*>(&$2); | |
| } ']' { | |
| $$=N(); | $$=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 */ | /* some code that writes to that context */ |
| /* context=pop; stack: context.value() */ | /* context=pop; stack: context.value() */ |
| }; | }; |
| Line 527 class_constructor_prefix: class_static_p | Line 561 class_constructor_prefix: class_static_p |
| /* expr */ | /* expr */ |
| expr_value: 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: | expr: |
| STRING | double_or_STRING |
| | true_value | |
| | false_value | |
| | get_value | | get_value |
| | call_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; } | | '(' expr ')' { $$ = $2; } |
| /* stack: operand // stack: @operand */ | /* stack: operand // stack: @operand */ |
| | '-' expr %prec NUNARY { $$=$2; O(*$$, OP_NEG) } | | '-' expr %prec NUNARY { $$=$2; O(*$$, OP_NEG) } |
| Line 578 expr: | Line 610 expr: |
| | expr "is" expr { $$=$1; P(*$$, *$3); O(*$$, OP_IS) } | | 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 { | string_inside_quotes_value: maybe_codes { |
| $$=N(); | $$=N(); |
| OA(*$$, OP_STRING_POOL, $1); /* stack: empty write context */ | OA(*$$, OP_STRING_POOL, $1); /* stack: empty write context */ |
| Line 592 write_string: STRING { | Line 629 write_string: STRING { |
| change_string_literal_to_write_string_literal(*($$=$1)) | 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*>(&vvoid), 0, 0, 0) } |
| true_value: "true" { $$ = VL(/*we know that we will not change it*/const_cast<VBool*>(&vtrue), 0, 0, 0) } | |
| false_value: "false" { $$ = VL(/*we know that we will not change it*/const_cast<VBool*>(&vfalse), 0, 0, 0) } | |
| empty: /* empty */ { $$=N() }; | empty: /* empty */ { $$=N() }; |
| %% | %% |
| Line 639 static int yylex(YYSTYPE *lvalp, void *a | Line 679 static int yylex(YYSTYPE *lvalp, void *a |
| const char *begin=pc.source; | const char *begin=pc.source; |
| Pos begin_pos=pc.pos; | Pos begin_pos=pc.pos; |
| uint last_line_end_col=0; | |
| const char *end; | const char *end; |
| int skip_analized=0; | int skip_analized=0; |
| while(true) { | while(true) { |
| c=*(end=(pc.source++)); | c=*(end=(pc.source++)); |
| // fprintf(stderr, "\nchar: %c %02X; nestage: %d, sp=%d", c, c, lexical_brackets_nestage, pc.sp); | // fprintf(stderr, "\nchar: %c %02X; nestage: %d, sp=%d", c, c, lexical_brackets_nestage, pc.sp); |
| if(c=='\n') { | if(c=='\n') |
| pc.pos.line++; | pc.pos_next_line(); |
| last_line_end_col=pc.pos.col; | else |
| pc.pos.col=0; | pc.pos_next_c(c); |
| } else | // fprintf(stderr, "\nchar: %c file(%d:%d)", c, pc.pos.line, pc.pos.col); |
| pc.pos.col+=c=='\t'?TAB_SIZE:1; | |
| if(c=='@' && pc.pos.col==0+1) { | if(pc.pos.col==0+1 && c=='@') { |
| if(pc.ls==LS_DEF_SPECIAL_BODY) { | if(pc.ls==LS_DEF_SPECIAL_BODY) { |
| // @SPECIAL | // @SPECIAL |
| // ... | // ... |
| Line 666 static int yylex(YYSTYPE *lvalp, void *a | Line 704 static int yylex(YYSTYPE *lvalp, void *a |
| } else // @ in first column inside some code [when could that be?] | } else // @ in first column inside some code [when could that be?] |
| result=BAD_METHOD_DECL_START; | result=BAD_METHOD_DECL_START; |
| goto break2; | goto break2; |
| } else if(c=='^') { | } |
| if(c=='^') { | |
| if(pc.ls==LS_METHOD_AFTER) { | if(pc.ls==LS_METHOD_AFTER) { |
| // handle after-method situation | // handle after-method situation |
| pop_LS(pc); | pop_LS(pc); |
| Line 697 default: | Line 736 default: |
| if(!pc.string_start) | if(!pc.string_start) |
| pc.string_start=begin_pos; | pc.string_start=begin_pos; |
| // append piece till ^ | // append piece till ^ |
| pc.string.append_strdup(begin, end-begin); | pc.string.append_strdup_know_length(begin, end-begin); |
| } | } |
| // reset piece 'begin' position & line | // reset piece 'begin' position & line |
| begin=pc.source; // ->punctuation | begin=pc.source; // ->punctuation |
| Line 713 default: | Line 752 default: |
| if(!pc.string_start) | if(!pc.string_start) |
| pc.string_start=begin_pos; | pc.string_start=begin_pos; |
| // append piece till ^ | // append piece till ^ |
| pc.string.append_strdup(begin, end-begin); | pc.string.append_strdup_know_length(begin, end-begin); |
| } | } |
| // #HH ? | // #HH ? |
| if(pc.source[0]=='#' && pc.source[1] && pc.source[2]) { | 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[1]]*0x10+ |
| hex_value[(unsigned char)pc.source[2]]; | hex_value[(unsigned char)pc.source[2]]); |
| if(c==0) { | if(c==0) { |
| result=BAD_HEX_LITERAL; | result=BAD_HEX_LITERAL; |
| goto break2; // wrong hex value[no ^#00 chars allowed]: bail out | goto break2; // wrong hex value[no ^#00 chars allowed]: bail out |
| Line 746 default: | Line 785 default: |
| if(!pc.string_start) | if(!pc.string_start) |
| pc.string_start=begin_pos; | pc.string_start=begin_pos; |
| // append piece till # | // append piece till # |
| pc.string.append_strdup(begin, end-begin); | pc.string.append_strdup_know_length(begin, end-begin); |
| } | } |
| // fall into COMMENT lexical state [wait for \n] | // fall into COMMENT lexical state [wait for \n] |
| push_LS(pc, LS_USER_COMMENT); | push_LS(pc, LS_USER_COMMENT); |
| Line 785 default: | Line 824 default: |
| lexical_brackets_nestage++; | lexical_brackets_nestage++; |
| break; | 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; | break; |
| // #COMMENT | // #COMMENT |
| Line 891 default: | Line 940 default: |
| if(!pc.string_start) | if(!pc.string_start) |
| pc.string_start=begin_pos; | pc.string_start=begin_pos; |
| // append piece till # | // append piece till # |
| pc.string.append_strdup(begin, end-begin); | pc.string.append_strdup_know_length(begin, end-begin); |
| } | } |
| // fall into COMMENT lexical state [wait for \n] | // fall into COMMENT lexical state [wait for \n] |
| push_LS(pc, LS_EXPRESSION_COMMENT); | push_LS(pc, LS_EXPRESSION_COMMENT); |
| Line 1027 default: | Line 1076 default: |
| goto break2; | goto break2; |
| } | } |
| break; | 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': | case ' ': case '\t': case '\n': |
| if(end!=begin) { // there were a string after previous operator? | if(end!=begin) { // there were a string after previous operator? |
| result=0; // return that string | result=0; // return that string |
| Line 1074 default: | Line 1139 default: |
| // expression integer division | // expression integer division |
| case '\\': | case '\\': |
| pop_LS(pc); | pop_LS(pc); |
| ungetc(pc, last_line_end_col); | pc.ungetc(); |
| result=EON; | result=EON; |
| goto break2; | goto break2; |
| } | } |
| Line 1086 default: | Line 1151 default: |
| switch(c) { | switch(c) { |
| case ':': | case ':': |
| pop_LS(pc); | pop_LS(pc); |
| ungetc(pc, last_line_end_col); | pc.ungetc(); |
| result=EON; | result=EON; |
| goto break2; | goto break2; |
| } | } |
| Line 1103 default: | Line 1168 default: |
| case '=': case '!': | case '=': case '!': |
| // common delimiters | // common delimiters |
| case ',': case '?': case '#': | case ',': case '?': case '#': |
| // mysql column separators | |
| case '`': | |
| // before call | // before call |
| case '^': | case '^': |
| pop_LS(pc); | pop_LS(pc); |
| ungetc(pc, last_line_end_col); | pc.ungetc(); |
| result=EON; | result=EON; |
| goto break2; | goto break2; |
| case '[': | case '[': |
| Line 1238 default: | Line 1305 default: |
| case ':': // ':name' or 'class:name' | case ':': // ':name' or 'class:name' |
| case '^': // ^abc^xxx wrong. bailing out | case '^': // ^abc^xxx wrong. bailing out |
| case ']': case '}': case ')': // ^abc]}) wrong. bailing out | case ']': case '}': case ')': // ^abc]}) wrong. bailing out |
| case ' ': // ^if ( wrong. bailing out | |
| RC; | RC; |
| } | } |
| break; | break; |
| Line 1284 default: | Line 1352 default: |
| lexical_brackets_nestage++; | lexical_brackets_nestage++; |
| break; | 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; | break; |
| case LS_METHOD_AFTER: | case LS_METHOD_AFTER: |
| Line 1303 default: | Line 1381 default: |
| RC; | RC; |
| } | } |
| pop_LS(pc); | pop_LS(pc); |
| ungetc(pc, last_line_end_col); | pc.ungetc(); |
| result=EON; | result=EON; |
| goto break2; | goto break2; |
| } | } |
| Line 1325 break2: | Line 1403 break2: |
| if(!pc.string_start) | if(!pc.string_start) |
| pc.string_start=begin_pos; | pc.string_start=begin_pos; |
| // append it | // append it |
| pc.string.append_strdup(begin, end-begin); | pc.string.append_strdup_know_length(begin, end-begin); |
| } | } |
| } | } |
| if(!pc.string.is_empty()) { // something accumulated? | if(!pc.string.is_empty()) { // something accumulated? |
| // create STRING value: array of OP_VALUE+vstring | // create STRING value: array of OP_VALUE+origin+vstring |
| *lvalp=VL( | *lvalp=VL( |
| new VString(*new String(pc.string, String::L_CLEAN)), | new VString(*new String(pc.string, String::L_CLEAN)), |
| pc.file_no, pc.string_start.line, pc.string_start.col); | pc.file_no, pc.string_start.line, pc.string_start.col); |