--- parser3/src/main/compile.y 2023/09/26 20:49:09 1.294 +++ parser3/src/main/compile.y 2026/04/23 18:50:11 1.302 @@ -2,13 +2,13 @@ /** @file Parser: compiler(lexical parser and grammar). - Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com) + Copyright (c) 2001-2024 Art. Lebedev Studio (http://www.artlebedev.com) Authors: Konstantin Morshnev , Alexandr Petrosian */ -volatile const char * IDENT_COMPILE_Y = "$Id: compile.y,v 1.294 2023/09/26 20:49:09 moko Exp $"; +volatile const char * IDENT_COMPILE_Y = "$Id: compile.y,v 1.302 2026/04/23 18:50:11 moko Exp $"; /** @todo parser4: @@ -62,7 +62,7 @@ static const VString vempty; #define POOL (*PC.pool) #ifndef DOXYGEN -#define CLASS_ADD if(PC.class_add()){ \ +#define CLASS_ADD if(!PC.class_add()){ \ PC.error=pa_strcat(PC.cclass->type(), " - class is already defined"); \ YYERROR; \ } @@ -172,7 +172,7 @@ control_method: '@' STRING '\n' PC.cclass_new=cclass; PC.append=false; } else { - YYERROR1("@" CLASS_NAME " must contain only one line with class name (contains more then one)"); + YYERROR1("@" CLASS_NAME " must contain only one line with class name (contains more than one)"); } } else if(command==USE_CONTROL_METHOD_NAME) { CLASS_ADD; @@ -440,14 +440,25 @@ construct: 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.array=false; // no need to save current value as if() is right after PC.array=true; +} any_constructor_code_values { PC.explicit_result=*reinterpret_cast(&$2); } ']' { // stack: context, name - $$=$3; // stack: context, name, value - O(*$$, OP::OP_CONSTRUCT_VALUE); /* value=pop; name=pop; context=pop; construct(context,name,value) */ + if(!PC.array){ + $$=$3; // stack: context, name, value + O(*$$, OP::OP_CONSTRUCT_VALUE); /* value=pop; name=pop; context=pop; construct(context,name,value) */ + } else { + $$ = N(); + OA(*$$, OP::OP_CONSTRUCT_ARRAY, $3); + PC.array=false; + } } ; +any_constructor_code_values: + any_constructor_code_value { $$ = $1; } + | any_constructor_code_values ';' any_constructor_code_value { $$ = $1; P(*$$, *$3); PC.array=true; }; +; construct_round: '(' expr_value ')' { $$=N(); // stack: context, name @@ -642,6 +653,7 @@ name_expr_value: | name_expr_subvar_value /* $subname_is_var_value */ | name_expr_with_subvar_value /* xxx$part_of_subname_is_var_value */ | name_square_code_value /* [codes] */ +| name_round_expr_value /* (expr) */ ; name_expr_subvar_value: '$' subvar_ref_name_rdive { $$=$2; @@ -662,16 +674,17 @@ name_square_code_value: '[' { } codes { PC.explicit_result=*reinterpret_cast(&$2); } ']' { - $$=N(); -#ifdef OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL - if(!maybe_append_simple_diving_code(*$$, *$3)) -#endif - { + $$=N(); + if(!maybe_append_simple_diving_code(*$$, *$3)) { OA(*$$, OP::OP_OBJECT_POOL, $3); /* stack: empty write context */ /* some code that writes to that context */ /* context=pop; stack: context.value() */ } }; +name_round_expr_value: '(' expr_value ')' { + $$ = N(); + P(*$$, *$2); +}; subvar_ref_name_rdive: STRING { $$=N(); O(*$$, OP::OP_WITH_READ); @@ -830,12 +843,12 @@ inline void ungetc(Parse_control& pc, ui } static int yylex(YYSTYPE *lvalp, void *apc) { - register Parse_control& pc=*static_cast(apc); + Parse_control& pc=*static_cast(apc); #define lexical_brackets_nestage pc.brackets_nestages[pc.ls_sp] #define RC {result=c; goto break2; } - register int c; + int c; int result; if(pc.pending_state) { @@ -1356,11 +1369,10 @@ default: goto break2; case '[': // $name.<[>code] - if(pc.pos.col>1/*not first column*/ && ( - end[-1]=='$'/*was start of get*/ || - end[-1]==':'/*was class name delim */ || - end[-1]=='.'/*was name delim */ - )) { + if( end[-1]=='$' /* was start of get */ || + end[-1]==':' /* was class name delim */ || + end[-1]=='.' /* was name delim */ + ) { push_LS(pc, LS_NAME_SQUARE_PART); lexical_brackets_nestage=1; RC; @@ -1369,7 +1381,7 @@ default: lexical_brackets_nestage=1; RC; case '{': - if(begin==end) { // ${name}, no need of EON, switching LS + if(end[-1]=='$') { // ${name}, no need of EON, switching LS, not begin==end as $[a]{$b} will fit pc.ls=LS_VAR_NAME_CURLY; } else { pc.ls=LS_VAR_CURLY; @@ -1378,6 +1390,15 @@ default: RC; case '(': + // $name.<(>expr) + if( // end[-1]=='$' /* $() excluded */ || + end[-1]==':' /* was class name delim */ || + end[-1]=='.' /* was name delim */ + ) { + push_LS(pc, LS_VAR_ROUND); + lexical_brackets_nestage=1; + RC; + } pc.ls=LS_VAR_ROUND; lexical_brackets_nestage=1; RC; @@ -1401,6 +1422,11 @@ default: push_LS(pc, LS_NAME_SQUARE_PART); lexical_brackets_nestage=1; RC; + case '(': + // ${name.<(>expr)} + push_LS(pc, LS_VAR_ROUND); + lexical_brackets_nestage=1; + RC; case '}': // ${name} finished, restoring LS pop_LS(pc); RC; @@ -1457,12 +1483,11 @@ default: case LS_METHOD_NAME: switch(c) { case '[': - // ^name.<[>code].xxx - if(pc.pos.col>1/*not first column*/ && ( - end[-1]=='^'/*was start of call*/ || // never, ^[ is literal... - end[-1]==':'/*was class name delim */ || - end[-1]=='.'/*was name delim */ - )) { + // ^name.<[>code] + if( // end[-1]=='^' /* never, ^[ is literal */ || + end[-1]==':' /* was class name delim */ || + end[-1]=='.' /* was name delim */ + ) { push_LS(pc, LS_NAME_SQUARE_PART); lexical_brackets_nestage=1; RC; @@ -1475,6 +1500,15 @@ default: lexical_brackets_nestage=1; RC; case '(': + // ^name.<(>expr) + if( // end[-1]=='^' /* never, ^( is literal */ || + end[-1]==':' /* was class name delim */ || + end[-1]=='.' /* was name delim */ + ) { + push_LS(pc, LS_VAR_ROUND); + lexical_brackets_nestage=1; + RC; + } pc.ls=LS_METHOD_ROUND; lexical_brackets_nestage=1; RC;