|
|
| version 1.208, 2004/04/06 07:53:57 | version 1.213.10.7, 2005/12/16 14:08:10 |
|---|---|
| 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 47 | Line 47 |
| static int real_yyerror(Parse_control* pc, char* s); | static int real_yyerror(Parse_control* pc, char* s); |
| 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 int is_not_whitespace(char c, int); | |
| 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 67 static int is_not_whitespace(char c, int | Line 70 static int is_not_whitespace(char c, int |
| %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 94 static int is_not_whitespace(char c, int | Line 97 static int is_not_whitespace(char c, int |
| %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 263 maybe_codes: empty | codes; | Line 269 maybe_codes: empty | codes; |
| codes: code | codes code { $$=$1; P(*$$, *$2) }; | codes: code | codes code { $$=$1; P(*$$, *$2) }; |
| code: write_string | action; | code: write_string | action; |
| action: { | action: get | put | call; |
| *reinterpret_cast<bool*>(&$$)=PC.explicit_result; | |
| PC.explicit_result=false; | |
| } real_action { | |
| PC.explicit_result=reinterpret_cast<bool>($1); | |
| $$=$2; | |
| }; | |
| real_action: get | put | call; | |
| /* get */ | /* get */ |
| Line 351 construct: | Line 350 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 405 call_value: '^' { | Line 409 call_value: '^' { |
| YYSTYPE params_code=$5; | YYSTYPE params_code=$5; |
| if(params_code->count()==4) { // probably [] case. [OP_VALUE+origin+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+origin+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 420 store_param: | Line 424 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 439 store_code_param_part: code_param_value | Line 448 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 452 code_param_value: | Line 472 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 499 name_expr_with_subvar_value: STRING subv | Line 513 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 544 class_constructor_prefix: class_static_p | Line 563 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 595 expr: | Line 612 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 605 string_inside_quotes_value: maybe_codes | Line 627 string_inside_quotes_value: maybe_codes |
| /* basics */ | /* basics */ |
| write_string: STRING { | write_string: STRING { |
| // $1=OP_STRING+origin+OP_WRITE_VALUE | // optimized from OP_STRING+OP_WRITE_VALUE to OP_STRING__WRITE |
| if(PC.explicit_result) { // only allow decoration whitespaces, no byte code actually produced | change_string_literal_to_write_string_literal(*($$=$1)) |
| String::Body body=static_cast<VString*>($1->get(2).value)->string(); | |
| if(body.for_each/*first_that, actually*/(is_not_whitespace, 0)) { | |
| strcpy(PC.error, "only whitespaces are allowed here (explicit result mode), look before this point"); | |
| YYERROR; | |
| } | |
| $$=N(); | |
| } else { | |
| // optimized from OP_STRING+origin+OP_WRITE_VALUE to OP_STRING__WRITE | |
| 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 691 static int yylex(YYSTYPE *lvalp, void *a | Line 706 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 810 default: | Line 826 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 1052 default: | Line 1078 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 1310 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 1380 static void yyprint(FILE *file, int type | Line 1432 static void yyprint(FILE *file, int type |
| if(type==STRING) | if(type==STRING) |
| fprintf(file, " \"%s\"", LA2S(*value)->cstr()); | fprintf(file, " \"%s\"", LA2S(*value)->cstr()); |
| } | } |
| static int is_not_whitespace(char c, int) { | |
| return !isspace(c); | |
| } |