Diff for /parser3/src/main/compile.y between versions 1.105 and 1.184

version 1.105, 2001/03/19 16:44:01 version 1.184, 2002/04/15 08:13:09
Line 1 Line 1
   %{
 /** @file  /** @file
         Parser          Parser: compiler(lexical parser and grammar).
   
         Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001 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$
 */  */
   
 /*  /**
         TODO.parser4:           @todo parser4: 
                 cache compiled code from request to request. to do that...          - cache compiled code from request to request. to do that...
                 1:      make method definitions, @CLASS, @BASE, @USE instructions,                  -#:     make method definitions, @CLASS, @BASE, @USE instructions,
                         which would be executed afterwards, and actions                          which would be executed afterwards, and actions
                         now performed at compile time would be delayed to run time.                          now performed at compile time would be delayed to run time.
                 2:      make cache expiration on time and on disk-change of class source                  -#:     make cache expiration on time and on disk-change of class source
                 3:      in apache use subpools for compiled class storage                  -#:     in apache use subpools for compiled class storage
                 4:      in iis make up specialized Pool object for that                  -#:     in iis make up specialized Pool object for that
 */  */
   
 %{  
 #define YYSTYPE  Array/*<Operation>*/ *  #define YYSTYPE  Array/*<Operation>*/ *
 #define YYPARSE_PARAM  pc  #define YYPARSE_PARAM  pc
 #define YYLEX_PARAM  pc  #define YYLEX_PARAM  pc
 #define YYDEBUG  1  #define YYDEBUG  1
 #define YYERROR_VERBOSE  #define YYERROR_VERBOSE 1
 #define yyerror(msg)  real_yyerror((parse_control *)pc, msg)  #define yyerror(msg)  real_yyerror((parse_control *)pc, msg)
 #define YYPRINT(file, type, value)  yyprint(file, type, value)  #define YYPRINT(file, type, value)  yyprint(file, type, value)
   
 #include <stdio.h>  
 #include <string.h>  
 #include <stdlib.h>  
   
 #include "compile_tools.h"  #include "compile_tools.h"
 #include "pa_value.h"  #include "pa_value.h"
 #include "pa_request.h"  #include "pa_request.h"
 #include "pa_vobject.h"  #include "pa_vobject.h"
 #include "pa_vdouble.h"  #include "pa_vdouble.h"
 #include "pa_globals.h"  #include "pa_globals.h"
   #include "pa_vvoid.h"
   
 #define SELF_ELEMENT_NAME "self"  #define SELF_ELEMENT_NAME "self"
 #define USE_CONTROL_METHOD_NAME "USE"  #define USE_CONTROL_METHOD_NAME "USE"
   
 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);
 int yylex(YYSTYPE *lvalp, void *pc);  static int yylex(YYSTYPE *lvalp, void *pc);
   
   
 // local convinient inplace typecast & var  // local convinient inplace typecast & var
 #define PC  ((parse_control *)pc)  #define PC  (*(parse_control *)pc)
 #define POOL  *PC->pool  #define POOL  (*PC.pool)
 #undef NEW  #undef NEW
 #define NEW new(POOL)  #define NEW new(POOL)
 #ifndef DOXYGEN_SHOULD_SKIP_THIS  #ifndef DOXYGEN
 %}  %}
   
 %pure_parser  %pure_parser
Line 60  int yylex(YYSTYPE *lvalp, void *pc); Line 58  int yylex(YYSTYPE *lvalp, void *pc);
 %token BOGUS  %token BOGUS
   
 %token BAD_STRING_COMPARISON_OPERATOR  %token BAD_STRING_COMPARISON_OPERATOR
   %token BAD_HEX_LITERAL
   %token BAD_METHOD_DECL_START
   
 %token LAND "&&"  %token LAND "&&"
 %token LOR "||"  %token LOR "||"
Line 80  int yylex(YYSTYPE *lvalp, void *pc); Line 80  int yylex(YYSTYPE *lvalp, void *pc);
 %token DEF "def"  %token DEF "def"
 %token IN "in"  %token IN "in"
 %token FEXISTS "-f"  %token FEXISTS "-f"
   %token DEXISTS "-d"
 %token IS "is"  %token IS "is"
   
 /* logical */  /* logical */
 %left "is"  %left "##"
 %left "lt" "gt" "le" "ge"  
 %left "eq" "ne"  
 %left '<' '>' "<=" ">=" "##"  
 %left "==" "!="  
 %left "||"  %left "||"
 %left "&&"  %left "&&"
 %left "def" "in" "-f"  %left '<' '>' "<=" ">="   "lt" "gt" "le" "ge"
   %left "==" "!="  "eq" "ne"
   %left "is" "def" "in" "-f" "-d"
 %left '!'  %left '!'
   
 /* bitwise */  /* bitwise */
 %left '#'  %left '#'
 %left '&' '|'  %left '|'
   %left '&' 
 %left '~'  %left '~'
   
 /* numerical */  /* numerical */
 %left '-' '+'  %left '-' '+'
 %left '*' '/' '%'  %left '*' '/' '%' '\\'
 %left NEG     /* negation: unary - */  %left NEG     /* negation: unary - */
   
 %%  %%
 all:  all: 
         one_big_piece {          one_big_piece {
         Method& method=*NEW Method(POOL,           Method& method=*NEW Method(POOL, 
                 *main_method_name,                   *main_method_name, 
                   Method::CT_ANY,
                 0, 0, /*min, max numbered_params_count*/                  0, 0, /*min, max numbered_params_count*/
                 0/*param_names*/, 0/*local_names*/,                   0/*param_names*/, 0/*local_names*/, 
                 $1/*parser_code*/, 0/*native_code*/);                  $1/*parser_code*/, 0/*native_code*/);
         PC->cclass->add_method(*main_method_name, method);          PC.cclass->add_method(*main_method_name, method);
 }  }
 |       methods;  |       methods;
   
Line 121  one_big_piece: maybe_codes; Line 122  one_big_piece: maybe_codes;
 method: control_method | code_method;  method: control_method | code_method;
   
 control_method: '@' STRING '\n'   control_method: '@' STRING '\n' 
                                 control_strings {                                  maybe_control_strings {
         const String& command=*SLA2S($2);          const String& command=*LA2S($2);
         YYSTYPE strings_code=$4;          YYSTYPE strings_code=$4;
         if(strings_code->size()<1*2) {          if(strings_code->size()<1*2) {
                 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");
                 YYERROR;                  YYERROR;
         }          }
         if(command==CLASS_NAME) {          if(command==CLASS_NAME) {
                 if(PC->cclass!=&PC->request->ROOT) { // already changed from default?                  if(PC.cclass->base()) { // already changed from default?
                         strcpy(PC->error, "class already have a name '");                          strcpy(PC.error, "class already have a name '");
                         strncat(PC->error, PC->cclass->name().cstr(), 100);                          strncat(PC.error, PC.cclass->name().cstr(), 100);
                         strcat(PC->error, "'");                          strcat(PC.error, "'");
                         YYERROR;                          YYERROR;
                 }                  }
                 if(strings_code->size()==1*2) {                  if(strings_code->size()==1*2) {
                         // new class' name                          // new class' name
                         const String *name=SLA2S(strings_code);                          const String *name=LA2S(strings_code);
                         // creating the class                          // creating the class
                         PC->cclass=NEW VClass(POOL);                          PC.cclass=NEW VClass(POOL);
                         PC->cclass->set_name(*name);                          PC.cclass->set_name(*name);
                         // defaulting base. may change with @BASE  
                         PC->cclass->set_base(PC->request->ROOT);  
                         // append to request's classes                          // append to request's classes
                         PC->request->classes().put(*name, PC->cclass);                          PC.request->classes().put(*name, PC.cclass);
                 } else {                  } else {
                         strcpy(PC->error, "@"CLASS_NAME" must contain sole name");                          strcpy(PC.error, "@"CLASS_NAME" must contain sole name");
                         YYERROR;                          YYERROR;
                 }                  }
         } else {          } else if(command==USE_CONTROL_METHOD_NAME) {
                 if(command==USE_CONTROL_METHOD_NAME) {                  for(int i=0; i<strings_code->size(); i+=2) 
                         for(int i=0; i<strings_code->size(); i+=2) {                          PC.request->use_file(*LA2S(strings_code, i));
                                 String file(*SLA2S(strings_code, i));          } else if(command==BASE_NAME) {
                                 file.APPEND_CONST(".p");                  if(PC.cclass->base()) { // already changed from default?
                                 PC->request->use_file(file.cstr());                          strcpy(PC.error, "class already have a base '");
                         }                          strncat(PC.error, PC.cclass->base()->name().cstr(), 100);
                 } else if(command==BASE_NAME) {                          strcat(PC.error, "'");
                         if(PC->cclass->base()!=&PC->request->ROOT) { // already changed from default?                          YYERROR;
                                 strcpy(PC->error, "class already have a base '");                  }
                                 strncat(PC->error, PC->cclass->base()->name().cstr(), 100);                  if(strings_code->size()==1*2) {
                                 strcat(PC->error, "'");                          const String& base_name=*LA2S(strings_code);
                           VClass *base=static_cast<VClass *>(
                                   PC.request->classes().get(base_name));
                           if(!base) {
                                   strcpy(PC.error, base_name.cstr());
                                   strcat(PC.error, ": undefined class in @"BASE_NAME);
                                 YYERROR;                                  YYERROR;
                         }                          }
                         if(strings_code->size()==1*2) {                          // @CLASS == @BASE sanity check
                                 // TODO: преодолеть self и циклические base                          if(PC.cclass==base) {
                                 const String& base_name=*SLA2S(strings_code);                                  strcpy(PC.error, "@"CLASS_NAME" equals @"BASE_NAME);
                                 VClass *base=static_cast<VClass *>(  
                                         PC->request->classes().get(base_name));  
                                 if(!base) {  
                                         strcpy(PC->error, base_name.cstr());  
                                         strcat(PC->error, ": undefined class in @"BASE_NAME);  
                                         YYERROR;  
                                 }  
                                 PC->cclass->set_base(*base);  
                         } else {  
                                 strcpy(PC->error, "@"BASE_NAME" must contain sole name");  
                                 YYERROR;                                  YYERROR;
                         }                          }
                           PC.cclass->set_base(*base);
                 } else {                  } else {
                         strcpy(PC->error, "'");                          strcpy(PC.error, "@"BASE_NAME" must contain sole name");
                         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;                          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"'");
                   YYERROR;
         }          }
 };  };
   maybe_control_strings: empty | control_strings;
 control_strings: control_string | control_strings control_string { $$=$1; P($$, $2) };  control_strings: control_string | control_strings control_string { $$=$1; P($$, $2) };
 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 {
         const String *name=SLA2S($2);          const String *name=LA2S($2);
   
         YYSTYPE params_names_code=$3;          YYSTYPE params_names_code=$3;
         Array *params_names=0;          Array *params_names=0;
         if(int size=params_names_code->size()) {          if(int size=params_names_code->size()) {
                 params_names=NEW Array(POOL);                  params_names=NEW Array(POOL);
                 for(int i=0; i<size; i+=2)                  for(int i=0; i<size; i+=2)
                         *params_names+=SLA2S(params_names_code, i);                          *params_names+=LA2S(params_names_code, i);
         }          }
   
         YYSTYPE locals_names_code=$4;          YYSTYPE locals_names_code=$4;
Line 210  code_method: '@' STRING bracketed_maybe_ Line 209  code_method: '@' STRING bracketed_maybe_
         if(int size=locals_names_code->size()) {          if(int size=locals_names_code->size()) {
                 locals_names=NEW Array(POOL);                  locals_names=NEW Array(POOL);
                 for(int i=0; i<size; i+=2)                  for(int i=0; i<size; i+=2)
                         *locals_names+=SLA2S(locals_names_code, i);                          *locals_names+=LA2S(locals_names_code, i);
         }          }
   
         Method& method=*NEW Method(POOL,           Method& method=*NEW Method(POOL, 
                 *name,                   *name, 
                   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(*name, method);          PC.cclass->add_method(*name, method);
 };  };
   
 maybe_bracketed_strings: empty | bracketed_maybe_strings;  maybe_bracketed_strings: empty | bracketed_maybe_strings;
Line 234  maybe_codes: empty | codes; Line 234  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: get | put | with | call;  action: get | put | call;
   
 /* get */  /* get */
   
 get: get_value {  get: get_value {
         $$=$1; /* stack: resulting value */          $$=$1; /* stack: resulting value */ 
         O($$, OP_WRITE_VALUE); /* value=pop; wcontext.write(value) */          changetail_or_append($$, 
                   OP_GET_ELEMENT, OP_GET_ELEMENT__WRITE,
                   OP_WRITE_VALUE
                   ); /* value=pop; wcontext.write(value) */
 };  };
 get_value: '$' get_name_value { $$=$2 }  get_value: '$' get_name_value { $$=$2 };
 get_name_value: name_without_curly_rdive EON | name_in_curly_rdive;  get_name_value: name_without_curly_rdive EON | name_in_curly_rdive;
 name_in_curly_rdive: '{' name_without_curly_rdive '}' { $$=$2 };  name_in_curly_rdive: '{' name_without_curly_rdive '}' { $$=$2 };
 name_without_curly_rdive:   name_without_curly_rdive: 
         name_without_curly_rdive_read           name_without_curly_rdive_read 
 |       name_without_curly_rdive_root  
 |       name_without_curly_rdive_class;  |       name_without_curly_rdive_class;
 name_without_curly_rdive_read: name_without_curly_rdive_code {  name_without_curly_rdive_read: name_without_curly_rdive_code {
         $$=N(POOL);           $$=N(POOL); 
         Array *diving_code=$1;          Array *diving_code=$1;
         const String *first_name=SLA2S(diving_code);          const String *first_name=LA2S(diving_code);
           // self.xxx... -> xxx...
           // OP_VALUE+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->size()>2?3/*OP_+string+get_element*/:2/*OP_+string*/);                          diving_code->size()>=3?3/*OP_VALUE+string+OP_GET_ELEMENTx*/:2/*OP_+string*/);
         } else {          } else {
                 O($$, OP_WITH_READ); /* stack: starting context */                  O($$, OP_WITH_READ); /* stack: starting context */
   
                   // ^if ELEMENT -> ^if ELEMENT_OR_OPERATOR
                   // OP_VALUE+string+OP_GET_ELEMENT. -> OP_VALUE+string+OP_GET_ELEMENT_OR_OPERATOR.
                   if(PC.in_call_value && diving_code->size()==3)
                           diving_code->put_int(2, OP_GET_ELEMENT_OR_OPERATOR);
                 P($$, diving_code);                  P($$, diving_code);
         }          }
         /* diving code; stack: current context */          /* diving code; stack: current context */
 };  };
 name_without_curly_rdive_root: ':' name_without_curly_rdive_code {  
         $$=N(POOL);   
         O($$, OP_WITH_ROOT); /* stack: starting context */  
         P($$, $2); /* diving code; stack: current context */  
 };  
 name_without_curly_rdive_class: class_prefix name_without_curly_rdive_code { $$=$1; P($$, $2) };  name_without_curly_rdive_class: class_prefix name_without_curly_rdive_code { $$=$1; P($$, $2) };
 name_without_curly_rdive_code: name_advance2 | name_path name_advance2 { $$=$1; P($$, $2) };  name_without_curly_rdive_code: name_advance2 | name_path name_advance2 { $$=$1; P($$, $2) };
   
Line 279  put: '$' name_expr_wdive construct { Line 283  put: '$' name_expr_wdive construct {
         P($$, $3); /* stack: context,name,constructor_value */          P($$, $3); /* stack: context,name,constructor_value */
 };  };
 name_expr_wdive:   name_expr_wdive: 
         name_expr_wdive_write          name_expr_wdive_root
 |       name_expr_wdive_root  |       name_expr_wdive_write
 |       name_expr_wdive_class;  |       name_expr_wdive_class;
 name_expr_wdive_write: name_expr_dive_code {  name_expr_wdive_root: name_expr_dive_code {
         $$=N(POOL);          $$=N(POOL);
         Array *diving_code=$1;          Array *diving_code=$1;
         const String *first_name=SLA2S(diving_code);          const String *first_name=LA2S(diving_code);
           // $self.xxx... -> $xxx...
           // OP_VALUE+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->size()>2?3/*OP_+string+get_element*/:2/*OP_+string*/);                          diving_code->size()>=3?3/*OP_VALUE+string+OP_GET_ELEMENTx*/:2/*OP_+string*/);
         } else {          } else {
                 O($$, OP_WITH_WRITE); /* stack: starting context */                  O($$, OP_WITH_ROOT); /* stack: starting context */
                 P($$, diving_code);                  P($$, diving_code);
         }          }
         /* diving code; stack: current context */          /* diving code; stack: current context */
 };  };
 name_expr_wdive_root: ':' name_expr_dive_code {  name_expr_wdive_write: '.' name_expr_dive_code {
         $$=N(POOL);           $$=N(POOL); 
         O($$, OP_WITH_ROOT); /* stack: starting context */          O($$, OP_WITH_WRITE); /* stack: starting context */
         P($$, $2); /* diving code; stack: context,name */          P($$, $2); /* diving code; stack: context,name */
 };  };
 name_expr_wdive_class: class_prefix name_expr_dive_code { $$=$1; P($$, $2) };  name_expr_wdive_class: class_prefix name_expr_dive_code { $$=$1; P($$, $2) };
   
 construct: construct_by_code | construct_by_expr;  construct: 
 construct_by_code: '[' any_constructor_code_value ']' {          construct_square
         $$=$2; /* stack: context, name, value */  |       construct_round
   |       construct_curly
   ;
   construct_square: '[' any_constructor_code_value ']' {
           // stack: context, name
           $$=$2; // 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) */
 }  }
 ;  ;
 construct_by_expr: '(' expr_value ')' {   construct_round: '(' expr_value ')' { 
         $$=$2; /* stack: context, name, value */          $$=N(POOL); 
         O($$, OP_CONSTRUCT_EXPR); /* value=pop; name=pop; context=pop; construct(context,name,value) */          O($$, OP_PREPARE_TO_EXPRESSION);
           // stack: context, name
           P($$, $2); // stack: context, name, value
           O($$, OP_CONSTRUCT_EXPR); /* value=pop->as_expr_result; name=pop; context=pop; construct(context,name,value) */
 }  }
 ;  ;
   construct_curly: '{' maybe_codes '}' {
           // stack: context, name
           $$=N(POOL); 
           CCA($$, $2); /* code=pop; name=pop; context=pop; construct(context,name,junction(code)) */
   };
   
 any_constructor_code_value:   any_constructor_code_value: 
         empty_string_value /* optimized $var[] case */          void_value /* optimized $var[] case */
 |       STRING /* optimized $var[STRING] case */  |       STRING /* optimized $var[STRING] case */
 |       constructor_code_value /* $var[something complex] */  |       constructor_code_value /* $var[something complex] */
 ;  ;
 constructor_code_value: constructor_code {  constructor_code_value: constructor_code {
         $$=N(POOL);           $$=N(POOL); 
         O($$, OP_CREATE_EWPOOL); /* stack: empty write context */          PJP($$, $1); /* stack: empty write context */
         P($$, $1); /* some code that writes to that context */          /* some code that writes to that context */
         O($$, OP_REDUCE_EWPOOL); /* context=pop; stack: context.value() */          /* context=pop; stack: context.value() */
 };  };
 constructor_code: codes__excluding_sole_str_literal;  constructor_code: codes__excluding_sole_str_literal;
 codes__excluding_sole_str_literal: action | code codes { $$=$1; P($$, $2) };  codes__excluding_sole_str_literal: action | code codes { $$=$1; P($$, $2) };
Line 335  call: call_value { Line 355  call: call_value {
         $$=$1; /* stack: value */          $$=$1; /* stack: value */
         O($$, OP_WRITE_VALUE); /* value=pop; wcontext.write(value) */          O($$, OP_WRITE_VALUE); /* value=pop; wcontext.write(value) */
 };  };
 call_value: '^' call_name store_params EON { /* ^field.$method{vasya} */  call_value: '^' { 
         $$=$2; /* with_xxx,diving code; stack: context,method_junction */                                          PC.in_call_value=true; 
                           }
                           call_name {
                                   PC.in_call_value=false;
                           } 
                           store_params EON { /* ^field.$method{vasya} */
           $$=$3; /* with_xxx,diving code; stack: context,method_junction */
         O($$, OP_GET_METHOD_FRAME); /* stack: context,method_frame */          O($$, OP_GET_METHOD_FRAME); /* stack: context,method_frame */
         P($$, $3); /* filling method_frame.store_params */  
         O($$, OP_CALL); /* method_frame=pop; ncontext=pop; call(ncontext,method_frame) stack: value */          YYSTYPE params_code=$5;
           if(params_code->size()==3) // probably [] case. [OP_VALUE + Void + STORE_PARAM]
                   if(Value *value=LA2V(params_code)) // it is OP_VALUE + value?
                           if(!value->is_defined()) // value is VVoid?
                                   params_code=0; // ^zzz[] case. don't append lone empty param.
           if(params_code)
                   P($$, params_code); // filling method_frame.store_params
           O($$, OP_CALL); // method_frame=pop; ncontext=pop; call(ncontext,method_frame) stack: value
 };  };
   
 call_name: name_without_curly_rdive;  call_name: name_without_curly_rdive;
Line 365  store_curly_param_parts: Line 398  store_curly_param_parts:
         store_curly_param_part          store_curly_param_part
 |       store_curly_param_parts ';' store_curly_param_part { $$=$1; P($$, $3) }  |       store_curly_param_parts ';' store_curly_param_part { $$=$1; P($$, $3) }
 ;  ;
 store_code_param_part:   store_code_param_part: code_param_value {
         empty /* optimized [] case */  
 |       STRING { /* optimized [STRING] case */  
         $$=$1;  
         O($$, OP_STORE_PARAM);  
 }  
 |       constructor_code_value { /* [something complex] */  
         $$=$1;          $$=$1;
         O($$, OP_STORE_PARAM);          O($$, OP_STORE_PARAM);
 }  };
 ;  
 store_expr_param_part: write_expr_value {  store_expr_param_part: write_expr_value {
         $$=N(POOL);           $$=N(POOL); 
         PEA($$, $1);          PEA($$, $1);
Line 384  store_curly_param_part: maybe_codes { Line 410  store_curly_param_part: maybe_codes {
         $$=N(POOL);           $$=N(POOL); 
         PCA($$, $1);          PCA($$, $1);
 };  };
   code_param_value:
           void_value /* optimized [;...] case */
   |       STRING /* optimized [STRING] case */
   |       constructor_code_value /* [something complex] */
   ;
 write_expr_value: expr_value {  write_expr_value: expr_value {
         $$=$1;          $$=N(POOL); 
           O($$, OP_PREPARE_TO_EXPRESSION);
           P($$, $1);
         O($$, OP_WRITE_EXPR_RESULT);          O($$, OP_WRITE_EXPR_RESULT);
 };  };
   
Line 396  name_expr_dive_code: name_expr_value | n Line 429  name_expr_dive_code: name_expr_value | n
 name_path: name_step | name_path name_step { $$=$1; P($$, $2) };  name_path: name_step | name_path name_step { $$=$1; P($$, $2) };
 name_step: name_advance1 '.';  name_step: name_advance1 '.';
 name_advance1: name_expr_value {  name_advance1: name_expr_value {
           // we know that name_advance1 not called from ^xxx context
           // so we'll not check for operator call possibility as we do in name_advance2
   
         /* stack: context */          /* stack: context */
         $$=$1; /* stack: context,name */          $$=$1; /* stack: context,name */
         O($$, OP_GET_ELEMENT); /* name=pop; context=pop; stack: context.get_element(name) */          O($$, OP_GET_ELEMENT); /* name=pop; context=pop; stack: context.get_element(name) */
Line 410  name_advance2: name_expr_value { Line 446  name_advance2: name_expr_value {
 name_expr_value:   name_expr_value: 
         STRING /* subname_is_const */          STRING /* subname_is_const */
 |       name_expr_subvar_value /* $subname_is_var_value */  |       name_expr_subvar_value /* $subname_is_var_value */
 |       name_expr_with_subvar_value /* xxx$part_of_subname_is_var_value[$...] */  |       name_expr_with_subvar_value /* xxx$part_of_subname_is_var_value */
   |       name_square_code_value /* [codes] */
 ;  ;
 name_expr_subvar_value: '$' subvar_ref_name_rdive {  name_expr_subvar_value: '$' subvar_ref_name_rdive {
         $$=$2;          $$=$2;
         O($$, OP_GET_ELEMENT);          O($$, OP_GET_ELEMENT);
 };  };
 name_expr_with_subvar_value: STRING subvar_get_writes {  name_expr_with_subvar_value: STRING subvar_get_writes {
           Array *code;
           {
                   change_string_literal_to_write_string_literal(code=$1);
                   P(code, $2);
           }
         $$=N(POOL);           $$=N(POOL); 
         O($$, OP_CREATE_EWPOOL);          PSP($$, code);
         P($$, $1);  
         O($$, OP_WRITE_VALUE);  
         P($$, $2);  
         O($$, OP_REDUCE_EWPOOL);  
 };  };
 subvar_ref_name_rdive: subvar_ref_name_rdive_read | subvar_ref_name_rdive_root;  name_square_code_value: '[' codes ']' {
 subvar_ref_name_rdive_read: STRING {  
         $$=N(POOL);           $$=N(POOL); 
         O($$, OP_WITH_READ);          PJP($$, $2); /* stack: empty write context */
         P($$, $1);          /* some code that writes to that context */
           /* context=pop; stack: context.value() */
 };  };
 subvar_ref_name_rdive_root: ':' STRING {  subvar_ref_name_rdive: STRING {
         $$=N(POOL);           $$=N(POOL); 
         O($$, OP_WITH_ROOT);          O($$, OP_WITH_READ);
         P($$, $2);          P($$, $1);
 };  };
 subvar_get_writes: subvar__get_write | subvar_get_writes subvar__get_write { $$=$1; P($$, $2) };  subvar_get_writes: subvar__get_write | subvar_get_writes subvar__get_write { $$=$1; P($$, $2) };
 subvar__get_write: '$' subvar_ref_name_rdive {  subvar__get_write: '$' subvar_ref_name_rdive {
Line 441  subvar__get_write: '$' subvar_ref_name_r Line 479  subvar__get_write: '$' subvar_ref_name_r
         O($$, OP_GET_ELEMENT__WRITE);          O($$, OP_GET_ELEMENT__WRITE);
 };  };
   
 class_prefix: STRING ':' {  class_prefix:
           class_static_prefix
   |       class_constructor_prefix
   ;
   class_static_prefix: STRING ':' {
         $$=$1; // stack: class name string          $$=$1; // stack: class name string
         O($$, OP_GET_CLASS);          O($$, OP_GET_CLASS);
 };  };
   class_constructor_prefix: class_static_prefix ':' {
           $$=$1;
 /* with */          if(!PC.in_call_value) {
                   strcpy(PC.error, ":: not allowed here");
 with: '$' name_without_curly_rdive '{' codes '}' {                  YYERROR;
         $$=$2;          }
         O($$, OP_CREATE_RWPOOL);          O($$, OP_PREPARE_TO_CONSTRUCT_OBJECT);
         P($$, $4);  
         O($$, OP_REDUCE_RWPOOL);  
         O($$, OP_WRITE_VALUE);  
 };  };
   
   
 /* expr */  /* expr */
   
 expr_value: expr {  expr_value: expr {
           // see OP_PREPARE_TO_EXPRESSION!!
         if(($$=$1)->size()==2) // only one string literal in there?          if(($$=$1)->size()==2) // only one string literal in there?
                 change_string_literal_to_double_literal($$); // make that string literal Double                  change_string_literal_to_double_literal($$); // make that string literal Double
 };  };
Line 468  expr: Line 509  expr:
 |       get_value  |       get_value
 |       call_value  |       call_value
 |       '"' 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 NEG { $$=$2;  O($$, OP_NEG) }  |       '-' expr %prec NEG { $$=$2;  O($$, OP_NEG) }
   |       '+' expr %prec NEG { $$=$2 }
 |       '~' expr { $$=$2;        O($$, OP_INV) }  |       '~' expr { $$=$2;        O($$, OP_INV) }
 |       '!' expr { $$=$2;  O($$, OP_NOT) }  |       '!' expr { $$=$2;  O($$, OP_NOT) }
 |       "def" expr { $$=$2;  O($$, OP_DEF) }  |       "def" expr { $$=$2;  O($$, OP_DEF) }
 |       "in" expr { $$=$2;  O($$, OP_IN) }  |       "in" expr { $$=$2;  O($$, OP_IN) }
 |       "-f" expr { $$=$2;  O($$, OP_FEXISTS) }  |       "-f" expr { $$=$2;  O($$, OP_FEXISTS) }
   |       "-d" expr { $$=$2;  O($$, OP_DEXISTS) }
 /* stack: a,b // stack: a@b */  /* stack: a,b // stack: a@b */
 |       expr '-' expr { $$=$1;  P($$, $3);  O($$, OP_SUB) }  |       expr '-' expr { $$=$1;  P($$, $3);  O($$, OP_SUB) }
 |       expr '+' expr { $$=$1;  P($$, $3);  O($$, OP_ADD) }  |       expr '+' expr { $$=$1;  P($$, $3);  O($$, OP_ADD) }
 |       expr '*' expr { $$=$1;  P($$, $3);  O($$, OP_MUL) }  |       expr '*' expr { $$=$1;  P($$, $3);  O($$, OP_MUL) }
 |       expr '/' expr { $$=$1;  P($$, $3);  O($$, OP_DIV) }  |       expr '/' expr { $$=$1;  P($$, $3);  O($$, OP_DIV) }
 |       expr '%' expr { $$=$1;  P($$, $3);  O($$, OP_MOD) }  |       expr '%' expr { $$=$1;  P($$, $3);  O($$, OP_MOD) }
   |       expr '\\' expr { $$=$1;  P($$, $3);  O($$, OP_INTDIV) }
 |       expr '&' expr { $$=$1;  P($$, $3);  O($$, OP_BIN_AND) }  |       expr '&' expr { $$=$1;  P($$, $3);  O($$, OP_BIN_AND) }
 |       expr '|' expr { $$=$1;  P($$, $3);  O($$, OP_BIN_OR) }  |       expr '|' expr { $$=$1;  P($$, $3);  O($$, OP_BIN_OR) }
 |       expr '#' expr { $$=$1;  P($$, $3);  O($$, OP_BIN_XOR) }  |       expr '#' expr { $$=$1;  P($$, $3);  O($$, OP_BIN_XOR) }
 |       expr "&&" expr { $$=$1;  P($$, $3);  O($$, OP_LOG_AND) }  |       expr "&&" expr { $$=$1;  PNC($$, $3);  O($$, OP_LOG_AND) }
 |       expr "||" expr { $$=$1;  P($$, $3);  O($$, OP_LOG_OR) }  |       expr "||" expr { $$=$1;  PNC($$, $3);  O($$, OP_LOG_OR) }
 |       expr "##" expr { $$=$1;  P($$, $3);  O($$, OP_LOG_XOR) }  |       expr "##" expr { $$=$1;  P($$, $3);  O($$, OP_LOG_XOR) }
 |       expr '<' expr { $$=$1;  P($$, $3);  O($$, OP_NUM_LT) }  |       expr '<' expr { $$=$1;  P($$, $3);  O($$, OP_NUM_LT) }
 |       expr '>' expr { $$=$1;  P($$, $3);  O($$, OP_NUM_GT) }  |       expr '>' expr { $$=$1;  P($$, $3);  O($$, OP_NUM_GT) }
Line 505  expr: Line 550  expr:
   
 string_inside_quotes_value: maybe_codes {  string_inside_quotes_value: maybe_codes {
         $$=N(POOL);          $$=N(POOL);
         O($$, OP_CREATE_SWPOOL); /* stack: empty write context */          PSP($$, $1); /* stack: empty write context */
         P($$, $1); /* some code that writes to that context */          /* some code that writes to that context */
         O($$, OP_REDUCE_SWPOOL); /* context=pop; stack: context.get_string() */          /* context=pop; stack: context.get_string() */
 };  };
   
 /* basics */  /* basics */
Line 517  write_string: STRING { Line 562  write_string: STRING {
         change_string_literal_to_write_string_literal($$=$1)          change_string_literal_to_write_string_literal($$=$1)
 };  };
   
 empty_string_value: /* empty */ { $$=VL(NEW VString(POOL)) };  void_value: /* empty */ { $$=VL(NEW VVoid(POOL)) };
 empty: /* empty */ { $$=N(POOL) };  empty: /* empty */ { $$=N(POOL) };
   
 %%  %%
Line 539  empty: /* empty */ { $$=N(POOL) }; Line 584  empty: /* empty */ { $$=N(POOL) };
                 4:[^({]=pop                  4:[^({]=pop
 */  */
   
 int yylex(YYSTYPE *lvalp, void *pc) {  static int yylex(YYSTYPE *lvalp, void *pc) {
         #define lexical_brackets_nestage PC->brackets_nestages[PC->sp]          #define lexical_brackets_nestage PC.brackets_nestages[PC.ls_sp]
         #define RC {result=c; goto break2; }          #define RC {result=c; goto break2; }
   
     register int c;      register int c;
     int result;      int result;
                   
         if(PC->pending_state) {          if(PC.pending_state) {
                 result=PC->pending_state;                  result=PC.pending_state;
                 PC->pending_state=0;                  PC.pending_state=0;
                 return result;                  return result;
         }          }
                   
         const char *begin=PC->source;          const char *begin=PC.source;
         const char *end;          const char *end;
         int begin_line=PC->line;          int begin_line=PC.line;
         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);
   
                 if(c=='\n') {                  if(c=='\n') {
                         PC->line++;                          PC.line++;
                         PC->col=0;                          PC.col=0;
                 } else                  } else
                         PC->col++;                          PC.col++;
   
                 // todo: # in 0+1 column comment                  if(c=='@' && PC.col==0+1) {
                           if(PC.ls==LS_DEF_SPECIAL_BODY) {
                 // escaping: ^^ ^$ ^; ^) ^} ^( ^{ ^"                                  // @SPECIAL
                 if(c=='^')                                   // ...
                         switch(*PC->source) {                                  // @<here = 
                                   pop_LS(PC); // exiting from LS_DEF_SPECIAL_BODY state
                           } // continuing checks
                           if(PC.ls==LS_USER) {
                                   push_LS(PC, LS_DEF_NAME);
                                   RC;
                           } else // @ in first column inside some code [when could that be?]
                                   result=BAD_METHOD_DECL_START;
                           goto break2;
                   } else if(c=='^')
                           switch(PC.ls) {
   case LS_EXPRESSION_VAR_NAME_WITH_COLON:
   case LS_EXPRESSION_VAR_NAME_WITHOUT_COLON:
   case LS_VAR_NAME_SIMPLE_WITH_COLON:
   case LS_VAR_NAME_SIMPLE_WITHOUT_COLON:
   case LS_VAR_NAME_CURLY:
   case LS_METHOD_NAME:
   case LS_COMMENT:
   case LS_DEF_COMMENT:
           // no literals in names, please
           break;
   default:
                           switch(*PC.source) {
                           // ^escaping some punctuators
                         case '^': case '$': case ';':                          case '^': case '$': case ';':
                           case '(': case ')':
                         case '[': case ']':                          case '[': case ']':
                         case '{': case '}':                          case '{': case '}':
                         case '"':                          case '"':  case ':':
                                 if(end!=begin) {                                  if(end!=begin) {
                                         // append piece till ^                                          // append piece till ^
                                         PC->string->APPEND(begin, end-begin, PC->file, begin_line);                                          PC.string->APPEND_CLEAN(begin, end-begin, PC.file, begin_line);
                                 }                                  }
                                 // reset piece 'begin' position & line                                  // reset piece 'begin' position & line
                                 begin=PC->source; // ^                                  end=begin=PC.source; // ^
                                 begin_line=PC->line;                                  begin_line=PC.line;
                                 // skip over ^ and _                                  if(PC.ls==LS_METHOD_AFTER) {
                                 PC->source++;  PC->col++;                                          pop_LS(PC);
                                 // skip analysis = forced literal                                          result=EON;
                                 continue;                                          skip_analized=-1; // return to ^ afterwards to assure it's literality
                                           goto break2;
                                   } else {
                                           // skip over _ after ^
                                           PC.source++;  PC.col++;
                                           // skip analysis = forced literal
                                           continue;
                                   }
   
                           // converting ^#HH into char(hex(HH))
                           case '#':
                                   if(end!=begin) {
                                           // append piece till ^
                                           PC.string->APPEND_CLEAN(begin, end-begin, PC.file, begin_line);
                                   }
                                   // #HH ?
                                   if(PC.source[0]=='#' && PC.source[1] && PC.source[2]) {
                                           char *hex=(char *)POOL.malloc(1);
                                           hex[0]=
                                                   hex_value[(unsigned char)PC.source[1]]*0x10+
                                                   hex_value[(unsigned char)PC.source[2]];
                                           if(hex[0]==0) {
                                                   result=BAD_HEX_LITERAL;
                                                   goto break2; // wrong hex value[no ^#00 chars allowed]: bail out
                                           }
                                           // append char(hex(HH))
                                           PC.string->APPEND_CLEAN(hex, 1, PC.file, begin_line);
                                           // skip over ^#HH
                                           PC.source+=3;
                                           PC.col+=3;
                                           // reset piece 'begin' position & line
                                           begin=PC.source; // ^
                                           begin_line=PC.line;
                                           continue;
                                   }
                                   break;
                         }                          }
                 switch(PC->ls) {                          break;
                   }
                   // #comment  start skipping
                   if(c=='#' && PC.col==1) {
                           if(end!=begin) {
                                   // append piece till #
                                   PC.string->APPEND_CLEAN(begin, end-begin, PC.file, begin_line);
                           }
                           // fall into COMMENT lexical state [wait for \n]
                           push_LS(PC, LS_COMMENT);
                           continue;
                   }
                   switch(PC.ls) {
   
                 // USER'S = NOT OURS                  // USER'S = NOT OURS
                 case LS_USER:                  case LS_USER:
           case LS_NAME_SQUARE_PART: // name.[here].xxx
                           if(PC.trim_bof)
                                   switch(c) {
                                   case '\n': case ' ': case '\t':
                                           begin=PC.source;
                                           begin_line=PC.line;
                                           continue; // skip it
                                   default:
                                           PC.trim_bof=false;
                                   }
                         switch(c) {                          switch(c) {
                         case '$':                          case '$':
                                 push_LS(PC, LS_VAR_NAME_SIMPLE);                                  push_LS(PC, LS_VAR_NAME_SIMPLE_WITH_COLON);
                                 RC;                                  RC;
                         case '^':                          case '^':
                                 push_LS(PC, LS_METHOD_NAME);                                  push_LS(PC, LS_METHOD_NAME);
                                 RC;                                  RC;
                         case '@':                          case ']':
                                 if(PC->col==0+1) {                                  if(PC.ls==LS_NAME_SQUARE_PART)
                                         push_LS(PC, LS_DEF_NAME);                                          if(--lexical_brackets_nestage==0) {// $name.[co<]?>de<]?>
                                         RC;                                                  pop_LS(PC); // $name.[co<]>de<]!>
                                 }                                                  RC;
                                           }
                                   break;
                           case '[': // $name.[co<[>de]
                                   if(PC.ls==LS_NAME_SQUARE_PART)
                                           lexical_brackets_nestage++;
                                 break;                                  break;
                         }                          }
                         break;                          break;
                                                   
                   // #COMMENT
                   case LS_COMMENT:
                           if(c=='\n') {
                                   // skip comment
                                   begin=PC.source;
                                   begin_line=PC.line;
   
                                   pop_LS(PC);
                                   continue;
                           }
                           break;
                           
                 // STRING IN EXPRESSION                  // STRING IN EXPRESSION
                 case LS_EXPRESSION_STRING:                  case LS_EXPRESSION_STRING_QUOTED:
                   case LS_EXPRESSION_STRING_APOSTROFED:
                         switch(c) {                          switch(c) {
                         case '"':                          case '"':
                                 pop_LS(PC); //"abc".                          case '\'':
                                 RC;                                  if(
                                           PC.ls == LS_EXPRESSION_STRING_QUOTED && c=='"' ||
                                           PC.ls == LS_EXPRESSION_STRING_APOSTROFED && c=='\'') {
                                           pop_LS(PC); //"abc". | 'abc'.
                                           RC;
                                   }
                                   break;
                         case '$':                          case '$':
                                 push_LS(PC, LS_VAR_NAME_SIMPLE);                                  push_LS(PC, LS_VAR_NAME_SIMPLE_WITH_COLON);
                                 RC;                                  RC;
                         case '^':                          case '^':
                                 push_LS(PC, LS_METHOD_NAME);                                  push_LS(PC, LS_METHOD_NAME);
Line 625  int yylex(YYSTYPE *lvalp, void *pc) { Line 776  int yylex(YYSTYPE *lvalp, void *pc) {
                 case LS_DEF_NAME:                  case LS_DEF_NAME:
                         switch(c) {                          switch(c) {
                         case '[':                          case '[':
                                 PC->ls=LS_DEF_PARAMS;                                  PC.ls=LS_DEF_PARAMS;
                                 RC;                                  RC;
                         case '\n':                          case '\n':
                                 PC->ls=LS_DEF_SPECIAL_BODY;                                  PC.ls=LS_DEF_SPECIAL_BODY;
                                 RC;                                  RC;
                         }                          }
                         break;                          break;
Line 638  int yylex(YYSTYPE *lvalp, void *pc) { Line 789  int yylex(YYSTYPE *lvalp, void *pc) {
                         case ';':                          case ';':
                                 RC;                                  RC;
                         case ']':                          case ']':
                                 PC->ls=*PC->source=='['?LS_DEF_LOCALS:LS_DEF_COMMENT;                                  PC.ls=*PC.source=='['?LS_DEF_LOCALS:LS_DEF_COMMENT;
                                 RC;                                  RC;
                         case '\n': // wrong. bailing out                          case '\n': // wrong. bailing out
                                 pop_LS(PC);                                  pop_LS(PC);
Line 652  int yylex(YYSTYPE *lvalp, void *pc) { Line 803  int yylex(YYSTYPE *lvalp, void *pc) {
                         case ';':                          case ';':
                                 RC;                                  RC;
                         case ']':                          case ']':
                                 PC->ls=LS_DEF_COMMENT;                                  PC.ls=LS_DEF_COMMENT;
                                 RC;                                  RC;
                         case '\n': // wrong. bailing out                          case '\n': // wrong. bailing out
                                 pop_LS(PC);                                  pop_LS(PC);
Line 668  int yylex(YYSTYPE *lvalp, void *pc) { Line 819  int yylex(YYSTYPE *lvalp, void *pc) {
                         break;                          break;
   
                 case LS_DEF_SPECIAL_BODY:                  case LS_DEF_SPECIAL_BODY:
                         if(c=='\n') {                          if(c=='\n')
                                 switch(*PC->source) {  
                                 case '@': case 0: // end of special_code  
                                         pop_LS(PC);  
                                         break;  
                                 }  
                                 RC;                                  RC;
                         }  
                         break;                          break;
   
                 // (EXPRESSION)                  // (EXPRESSION)
Line 684  int yylex(YYSTYPE *lvalp, void *pc) { Line 829  int yylex(YYSTYPE *lvalp, void *pc) {
                         switch(c) {                          switch(c) {
                         case ')':                          case ')':
                                 if(--lexical_brackets_nestage==0)                                  if(--lexical_brackets_nestage==0)
                                         if(PC->ls==LS_METHOD_ROUND) // method round param ended                                          if(PC.ls==LS_METHOD_ROUND) // method round param ended
                                                 PC->ls=LS_METHOD_AFTER; // look for method end                                                  PC.ls=LS_METHOD_AFTER; // look for method end
                                         else // PC->ls==LS_VAR_ROUND // variable constructor ended                                          else // PC.ls==LS_VAR_ROUND // variable constructor ended
                                                 pop_LS(PC); // return to normal life                                                  pop_LS(PC); // return to normal life
                                 RC;                                  RC;
                         case '$':                          case '$':
                                 push_LS(PC, LS_EXPRESSION_VAR_NAME);                                                              push_LS(PC, LS_EXPRESSION_VAR_NAME_WITH_COLON);                         
                                 RC;                                  RC;
                         case '^':                          case '^':
                                 push_LS(PC, LS_METHOD_NAME);                                  push_LS(PC, LS_METHOD_NAME);
Line 699  int yylex(YYSTYPE *lvalp, void *pc) { Line 844  int yylex(YYSTYPE *lvalp, void *pc) {
                                 lexical_brackets_nestage++;                                  lexical_brackets_nestage++;
                                 RC;                                  RC;
                         case '-':                          case '-':
                                 if(*PC->source=='f') { // -f                                  switch(*PC.source) {
                                   case 'f': // -f
                                         skip_analized=1;                                          skip_analized=1;
                                         result=FEXISTS;                                          result=FEXISTS;
                                 } else                                          goto break2;
                                   case 'd': // -d
                                           skip_analized=1;
                                           result=DEXISTS;
                                           goto break2;
                                   default:
                                         result=c;                                          result=c;
                                           goto break2;
                                   }
                                 goto break2;                                  goto break2;
                         case '+': case '*': case '/': case '%':                           case '+': case '*': case '/': case '%': case '\\':
                         case '~':                          case '~':
                         case ';':                          case ';':
                                 RC;                                  RC;
                         case '&': case '|':  case '#':                          case '&': case '|':  case '#':
                                 if(*PC->source==c) { // && ||                                  if(*PC.source==c) { // && ||
                                         result=c=='#'?LXOR:c=='&'?LAND:LOR;                                          result=c=='#'?LXOR:c=='&'?LAND:LOR;
                                         skip_analized=1;                                          skip_analized=1;
                                 } else                                  } else
                                         result=c;                                          result=c;
                                 goto break2;                                  goto break2;
                         case '<': case '>': case '=': case '!':                           case '<': case '>': case '=': case '!': 
                                 if(*PC->source=='=') { // <= >= == !=                                  if(*PC.source=='=') { // <= >= == !=
                                         skip_analized=1;                                          skip_analized=1;
                                         switch(c) {                                          switch(c) {
                                         case '<': result=NLE; break;                                          case '<': result=NLE; break;
Line 729  int yylex(YYSTYPE *lvalp, void *pc) { Line 882  int yylex(YYSTYPE *lvalp, void *pc) {
                                         result=c;                                          result=c;
                                 goto break2;                                  goto break2;
                         case '"':                          case '"':
                                 push_LS(PC, LS_EXPRESSION_STRING);                                  push_LS(PC, LS_EXPRESSION_STRING_QUOTED);
                                   RC;
                           case '\'':
                                   push_LS(PC, LS_EXPRESSION_STRING_APOSTROFED);
                                 RC;                                  RC;
                         case 'l': case 'g': case 'e': case 'n':                          case 'l': case 'g': case 'e': case 'n':
                                 if(end==begin) // right after whitespace                                  if(end==begin) // right after whitespace
                                         switch(*PC->source) {                                          if(isspace(PC.source[1])) {
 //                                      case '?': // ok [and bad cases, yacc would bark at them]                                                  switch(*PC.source) {
                                         case 't': // lt gt [et nt]                                                          //                                      case '?': // ok [and bad cases, yacc would bark at them]
                                                 result=c=='l'?SLT:c=='g'?SGT:BAD_STRING_COMPARISON_OPERATOR;                                                  case 't': // lt gt [et nt]
                                                 skip_analized=1;                                                          result=c=='l'?SLT:c=='g'?SGT:BAD_STRING_COMPARISON_OPERATOR;
                                                 goto break2;                                                          skip_analized=1;
                                         case 'e': // le ge ne [ee]                                                          goto break2;
                                                 result=c=='l'?SLE:c=='g'?SGE:c=='n'?SNE:BAD_STRING_COMPARISON_OPERATOR;                                                  case 'e': // le ge ne [ee]
                                                 skip_analized=1;                                                          result=c=='l'?SLE:c=='g'?SGE:c=='n'?SNE:BAD_STRING_COMPARISON_OPERATOR;
                                                 goto break2;                                                          skip_analized=1;
                                         case 'q': // eq [lq gq nq]                                                          goto break2;
                                                 result=c=='e'?SEQ:BAD_STRING_COMPARISON_OPERATOR;                                                  case 'q': // eq [lq gq nq]
                                                 skip_analized=1;                                                          result=c=='e'?SEQ:BAD_STRING_COMPARISON_OPERATOR;
                                                 goto break2;                                                          skip_analized=1;
                                                           goto break2;
                                                   }
                                         }                                          }
                                 break;                                  break;
                         case 'i':                          case 'i':
                                 if(end==begin) // right after whitespace                                  if(end==begin) // right after whitespace
                                         switch(PC->source[0]) {                                          if(isspace(PC.source[1])) {
                                         case 'n':                                                   switch(PC.source[0]) {
                                                 { // in                                                  case 'n': // in
                                                         skip_analized=1;                                                          skip_analized=1;
                                                         result=IN;                                                          result=IN;
                                                         goto break2;                                                          goto break2;
                                                 }                                                  case 's': // is
                                         case 's':   
                                                 { // is  
                                                         skip_analized=1;                                                          skip_analized=1;
                                                         result=IS;                                                          result=IS;
                                                         goto break2;                                                          goto break2;
Line 768  int yylex(YYSTYPE *lvalp, void *pc) { Line 924  int yylex(YYSTYPE *lvalp, void *pc) {
                                 break;                                  break;
                         case 'd':                          case 'd':
                                 if(end==begin) // right after whitespace                                  if(end==begin) // right after whitespace
                                         if(PC->source[0]=='e' && PC->source[1]=='f') { // def                                          if(PC.source[0]=='e' && PC.source[1]=='f') { // def
                                                 skip_analized=2;                                                  skip_analized=2;
                                                 result=DEF;                                                  result=DEF;
                                                 goto break2;                                                  goto break2;
Line 782  int yylex(YYSTYPE *lvalp, void *pc) { Line 938  int yylex(YYSTYPE *lvalp, void *pc) {
                                 // that's a leading|traling space or after-operator-space                                  // that's a leading|traling space or after-operator-space
                                 // ignoring it                                  // ignoring it
                                 // reset piece 'begin' position & line                                  // reset piece 'begin' position & line
                                 begin=PC->source; // after whitespace char                                  begin=PC.source; // after whitespace char
                                 begin_line=PC->line;                                  begin_line=PC.line;
                                 continue;                                  continue;
                         }                          }
                         break;                          break;
   
                 // VARIABLE GET/PUT/WITH                  // VARIABLE GET/PUT/WITH
                 case LS_VAR_NAME_SIMPLE:                  case LS_VAR_NAME_SIMPLE_WITH_COLON: 
                 case LS_EXPRESSION_VAR_NAME:                  case LS_VAR_NAME_SIMPLE_WITHOUT_COLON:
                         if(PC->ls==LS_EXPRESSION_VAR_NAME) {                  case LS_EXPRESSION_VAR_NAME_WITH_COLON: 
                                 // name in expr ends also before binary operators                   case LS_EXPRESSION_VAR_NAME_WITHOUT_COLON:
                           if(
                                   PC.ls==LS_EXPRESSION_VAR_NAME_WITH_COLON ||
                                   PC.ls==LS_EXPRESSION_VAR_NAME_WITHOUT_COLON) {
                                   // name in expr ends also before 
                                 switch(c) {                                  switch(c) {
                                   // expression minus
                                 case '-':                                   case '-': 
                                   // expression integer division
                                   case '\\':
                                           pop_LS(PC);
                                           PC.source--;  if(--PC.col<0) { PC.line--;  PC.col=-1; }
                                           result=EON;
                                           goto break2;
                                   }
                           }
                           if(
                                   PC.ls==LS_VAR_NAME_SIMPLE_WITHOUT_COLON ||
                                   PC.ls==LS_EXPRESSION_VAR_NAME_WITHOUT_COLON) {
                                   // name already has ':', stop before next 
                                   switch(c) {
                                   case ':': 
                                         pop_LS(PC);                                          pop_LS(PC);
                                         PC->source--;  if(--PC->col<0) { PC->line--;  PC->col=-1; }                                          PC.source--;  if(--PC.col<0) { PC.line--;  PC.col=-1; }
                                         result=EON;                                          result=EON;
                                         goto break2;                                          goto break2;
                                 }                                  }
Line 805  int yylex(YYSTYPE *lvalp, void *pc) { Line 980  int yylex(YYSTYPE *lvalp, void *pc) {
                         case 0:                          case 0:
                         case ' ': case '\t': case '\n':                          case ' ': case '\t': case '\n':
                         case ';':                          case ';':
                         case ']': case '}': case ')': case '"':                          case ']': case '}': case ')': 
                         case '<': case '>':  // these stand for HTML brackets and expression binary ops                          case '"': case '\'':
                           case '<': case '>':  // these stand for HTML brackets AND expression binary ops
                         case '+': case '*': case '/': case '%':                           case '+': case '*': case '/': case '%': 
                         case '&': case '|':                           case '&': case '|': 
                         case '=': case '!':                          case '=': case '!':
                         // common delimiters                          // common delimiters
                         case '\'': case ',':                          case ',': case '?':
                           // before call
                           case '^': 
                                 pop_LS(PC);                                  pop_LS(PC);
                                 PC->source--;  if(--PC->col<0) { PC->line--;  PC->col=-1; }                                  PC.source--;  if(--PC.col<0) { PC.line--;  PC.col=-1; }
                                 result=EON;                                  result=EON;
                                 goto break2;                                  goto break2;
                         case '[':                          case '[':
                                 PC->ls=LS_VAR_SQUARE;                                  // $name.<[>code]
                                   if(PC.col>1/*not first column*/ && (
                                           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;
                                   }
                                   PC.ls=LS_VAR_SQUARE;
                                 lexical_brackets_nestage=1;                                  lexical_brackets_nestage=1;
                                 RC;                                  RC;
                         case '{':                          case '{':
                                 if(begin==end) { // ${name}, no need of EON, switching LS                                  if(begin==end) { // ${name}, no need of EON, switching LS
                                         PC->ls=LS_VAR_NAME_CURLY;                                           PC.ls=LS_VAR_NAME_CURLY; 
                                 } else {                                  } else {
                                         PC->ls=LS_VAR_CURLY;                                          PC.ls=LS_VAR_CURLY;
                                         lexical_brackets_nestage=1;                                          lexical_brackets_nestage=1;
                                 }                                  }
   
                                 RC;                                  RC;
                         case '(':                          case '(':
                                 PC->ls=LS_VAR_ROUND;                                  PC.ls=LS_VAR_ROUND;
                                 lexical_brackets_nestage=1;                                  lexical_brackets_nestage=1;
                                 RC;                                  RC;
                         case '.': // name part delim                          case '.': // name part delim
                         case '$': // name part subvar                          case '$': // name part subvar
                         case ':': // ':name' or 'class:name'                          case ':': // class<:>name
                                   // go to _WITHOUT_COLON state variant...
                                   if(PC.ls==LS_VAR_NAME_SIMPLE_WITH_COLON)
                                           PC.ls=LS_VAR_NAME_SIMPLE_WITHOUT_COLON;
                                   else if(PC.ls==LS_EXPRESSION_VAR_NAME_WITH_COLON)
                                           PC.ls=LS_EXPRESSION_VAR_NAME_WITHOUT_COLON;
                                   // ...stop before next ':'
                                 RC;                                  RC;
                         }                          }
                         break;                          break;
   
                 case LS_VAR_NAME_CURLY:                  case LS_VAR_NAME_CURLY:
                         switch(c) {                          switch(c) {
                           case '[':
                                   // ${name.<[>code]}
                                   push_LS(PC, LS_NAME_SQUARE_PART);
                                   lexical_brackets_nestage=1;
                                   RC;
                         case '}': // ${name} finished, restoring LS                          case '}': // ${name} finished, restoring LS
                                 pop_LS(PC);                                  pop_LS(PC);
                                 RC;                                  RC;
Line 855  int yylex(YYSTYPE *lvalp, void *pc) { Line 1054  int yylex(YYSTYPE *lvalp, void *pc) {
                 case LS_VAR_SQUARE:                  case LS_VAR_SQUARE:
                         switch(c) {                          switch(c) {
                         case '$':                          case '$':
                                 push_LS(PC, LS_VAR_NAME_SIMPLE);                                  push_LS(PC, LS_VAR_NAME_SIMPLE_WITH_COLON);
                                 RC;                                  RC;
                         case '^':                          case '^':
                                 push_LS(PC, LS_METHOD_NAME);                                  push_LS(PC, LS_METHOD_NAME);
Line 877  int yylex(YYSTYPE *lvalp, void *pc) { Line 1076  int yylex(YYSTYPE *lvalp, void *pc) {
                 case LS_VAR_CURLY:                  case LS_VAR_CURLY:
                         switch(c) {                          switch(c) {
                         case '$':                          case '$':
                                 push_LS(PC, LS_VAR_NAME_SIMPLE);                                  push_LS(PC, LS_VAR_NAME_SIMPLE_WITH_COLON);
                                 RC;                                  RC;
                         case '^':                          case '^':
                                 push_LS(PC, LS_METHOD_NAME);                                  push_LS(PC, LS_METHOD_NAME);
Line 898  int yylex(YYSTYPE *lvalp, void *pc) { Line 1097  int yylex(YYSTYPE *lvalp, void *pc) {
                 case LS_METHOD_NAME:                  case LS_METHOD_NAME:
                         switch(c) {                          switch(c) {
                         case '[':                          case '[':
                                 PC->ls=LS_METHOD_SQUARE;                                  // ^name.<[>code].xxx
                                   if(PC.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 */
                                           )) {
                                           push_LS(PC, LS_NAME_SQUARE_PART);
                                           lexical_brackets_nestage=1;
                                           RC;
                                   }
                                   PC.ls=LS_METHOD_SQUARE;
                                 lexical_brackets_nestage=1;                                  lexical_brackets_nestage=1;
                                 RC;                                  RC;
                         case '{':                          case '{':
                                 PC->ls=LS_METHOD_CURLY;                                  PC.ls=LS_METHOD_CURLY;
                                 lexical_brackets_nestage=1;                                  lexical_brackets_nestage=1;
                                 RC;                                  RC;
                         case '(':                          case '(':
                                 PC->ls=LS_METHOD_ROUND;                                  PC.ls=LS_METHOD_ROUND;
                                 lexical_brackets_nestage=1;                                  lexical_brackets_nestage=1;
                                 RC;                                  RC;
                         case '.': // name part delim                           case '.': // name part delim 
                         case '$': // name part subvar                          case '$': // name part subvar
                         case ':': // ':name' or 'class:name'                          case ':': // ':name' or 'class:name'
                           case '^': // ^abc^xxx wrong. bailing out
                           case ']': case '}': case ')': // ^abc]}) wrong. bailing out
                                 RC;                                  RC;
                         }                          }
                         break;                          break;
Line 919  int yylex(YYSTYPE *lvalp, void *pc) { Line 1130  int yylex(YYSTYPE *lvalp, void *pc) {
                 case LS_METHOD_SQUARE:                  case LS_METHOD_SQUARE:
                         switch(c) {                          switch(c) {
                         case '$':                          case '$':
                                 push_LS(PC, LS_VAR_NAME_SIMPLE);                                  push_LS(PC, LS_VAR_NAME_SIMPLE_WITH_COLON);
                                 RC;                                  RC;
                         case '^':                          case '^':
                                 push_LS(PC, LS_METHOD_NAME);                                  push_LS(PC, LS_METHOD_NAME);
Line 928  int yylex(YYSTYPE *lvalp, void *pc) { Line 1139  int yylex(YYSTYPE *lvalp, void *pc) {
                                 RC;                                  RC;
                         case ']':                          case ']':
                                 if(--lexical_brackets_nestage==0) {                                  if(--lexical_brackets_nestage==0) {
                                         PC->ls=LS_METHOD_AFTER;                                          PC.ls=LS_METHOD_AFTER;
                                         RC;                                          RC;
                                 }                                  }
                                 break;                                  break;
Line 941  int yylex(YYSTYPE *lvalp, void *pc) { Line 1152  int yylex(YYSTYPE *lvalp, void *pc) {
                 case LS_METHOD_CURLY:                  case LS_METHOD_CURLY:
                         switch(c) {                          switch(c) {
                         case '$':                          case '$':
                                 push_LS(PC, LS_VAR_NAME_SIMPLE);                                  push_LS(PC, LS_VAR_NAME_SIMPLE_WITH_COLON);
                                 RC;                                  RC;
                         case '^':                          case '^':
                                 push_LS(PC, LS_METHOD_NAME);                                  push_LS(PC, LS_METHOD_NAME);
Line 950  int yylex(YYSTYPE *lvalp, void *pc) { Line 1161  int yylex(YYSTYPE *lvalp, void *pc) {
                                 RC;                                  RC;
                         case '}':                          case '}':
                                 if(--lexical_brackets_nestage==0) {                                  if(--lexical_brackets_nestage==0) {
                                         PC->ls=LS_METHOD_AFTER;                                          PC.ls=LS_METHOD_AFTER;
                                         RC;                                          RC;
                                 }                                  }
                                 break;                                  break;
Line 962  int yylex(YYSTYPE *lvalp, void *pc) { Line 1173  int yylex(YYSTYPE *lvalp, void *pc) {
   
                 case LS_METHOD_AFTER:                  case LS_METHOD_AFTER:
                         if(c=='[') {/* ][ }[ )[ */                          if(c=='[') {/* ][ }[ )[ */
                                 PC->ls=LS_METHOD_SQUARE;                                  PC.ls=LS_METHOD_SQUARE;
                                 lexical_brackets_nestage=1;                                  lexical_brackets_nestage=1;
                                 RC;                                  RC;
                         }                                                                    }                                          
                         if(c=='{') {/* ]{ }{ ){ */                          if(c=='{') {/* ]{ }{ ){ */
                                 PC->ls=LS_METHOD_CURLY;                                  PC.ls=LS_METHOD_CURLY;
                                 lexical_brackets_nestage=1;                                  lexical_brackets_nestage=1;
                                 RC;                                  RC;
                         }                                                                    }                                          
                         if(c=='(') {/* ]( }( )( */                          if(c=='(') {/* ]( }( )( */
                                 PC->ls=LS_METHOD_ROUND;                                  PC.ls=LS_METHOD_ROUND;
                                 lexical_brackets_nestage=1;                                  lexical_brackets_nestage=1;
                                 RC;                                  RC;
                         }                                                                    }                                          
                         pop_LS(PC);                          pop_LS(PC);
                         PC->source--;  if(--PC->col<0) { PC->line--;  PC->col=-1; }                          PC.source--;  if(--PC.col<0) { PC.line--;  PC.col=-1; }
                         result=EON;                          result=EON;
                         goto break2;                          goto break2;
                 }                  }
Line 992  break2: Line 1203  break2:
                 if((c=='@' || c==0) && end[-1]=='\n') { // we are before LS_DEF_NAME or EOF?                  if((c=='@' || c==0) && end[-1]=='\n') { // we are before LS_DEF_NAME or EOF?
                         // strip last \n                          // strip last \n
                         end--;                          end--;
                           if(end!=begin && end[-1]=='\n') // allow one empty line before LS_DEF_NAME
                                   end--;
                 }                  }
                 if(end!=begin) { // last piece still alive?                  if(end!=begin && PC.ls!=LS_COMMENT) { // last piece still alive and not comment?
                         // append it                          // append it
                         PC->string->APPEND(begin, end-begin, PC->file, begin_line/*, start_col*/);                          PC.string->APPEND_CLEAN(begin, end-begin, PC.file, begin_line/*, start_col*/);
                 }                  }
         }          }
         if(PC->string->size()) { // something accumulated?          if(PC.string->size()) { // something accumulated?
                 // create STRING value: array of OP_VALUE+vstring                  // create STRING value: array of OP_VALUE+vstring
                 *lvalp=VL(NEW VString(*PC->string));                  *lvalp=VL(NEW VString(*PC.string));
                 // new pieces storage                  // new pieces storage
                 PC->string=NEW String(POOL);                  PC.string=NEW String(POOL);
                 // make current result be pending for next call, return STRING for now                  // make current result be pending for next call, return STRING for now
                 PC->pending_state=result;  result=STRING;                  PC.pending_state=result;  result=STRING;
         }          }
         if(skip_analized) {          if(skip_analized) {
                 PC->source+=skip_analized;  PC->col+=skip_analized;                  PC.source+=skip_analized;  PC.col+=skip_analized;
         }          }
         return result;          return result;
 }  }
   
 int real_yyerror(parse_control *pc, char *s)  /* Called by yyparse on error */  static int real_yyerror(parse_control *pc, char *s) {  // Called by yyparse on error
      {             strncpy(PC.error, s, MAX_STRING);
            strncpy(pc->error, s, MAX_STRING); // TODO: перепроверить с треклятым последним байтом  
            return 1;             return 1;
      }  }
   
 static void  
      yyprint(  
           FILE *file,  
           int type,  
           YYSTYPE value)  
      {  
        if(type==STRING)  
          fprintf(file, " \"%s\"", SLA2S(value)->cstr());  
      }  
   
   static void yyprint(FILE *file, int type, YYSTYPE value) {
           if(type==STRING)
                   fprintf(file, " \"%s\"", LA2S(value)->cstr());
   }

Removed from v.1.105  
changed lines
  Added in v.1.184


E-mail: