Diff for /parser3/src/main/compile.y between versions 1.88 and 1.118

version 1.88, 2001/03/11 07:52:42 version 1.118, 2001/03/27 14:50:47
Line 1 Line 1
 /*  /** @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>  
           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/*<op>*/ *  #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 "pa_config_includes.h"
 #include <stdio.h>  #include <stdio.h>
 #include <string.h>  
 #include <stdlib.h>  #include <stdlib.h>
   #include <ctype.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 "core.h"  #include "pa_globals.h"
   
 #define SELF_ELEMENT_NAME "self"  #define SELF_ELEMENT_NAME "self"
 #define USE_CONTROL_METHOD_NAME "USE"  #define USE_CONTROL_METHOD_NAME "USE"
Line 46  int yylex(YYSTYPE *lvalp, void *pc); Line 49  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
 %}  %}
   
 %pure_parser  %pure_parser
Line 59  int yylex(YYSTYPE *lvalp, void *pc); Line 63  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 LAND "&&"  %token LAND "&&"
 %token LOR "||"  %token LOR "||"
Line 79  int yylex(YYSTYPE *lvalp, void *pc); Line 84  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 IS "is"
   
 /* logical */  /* logical */
   %left "is"
 %left "lt" "gt" "le" "ge"  %left "lt" "gt" "le" "ge"
 %left "eq" "ne"  %left "eq" "ne"
 %left '<' '>' "<=" ">=" "##"  %left '<' '>' "<=" ">=" "##"
Line 108  all: Line 115  all:
                 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->vclass->add_method(*main_method_name, method);          PC.cclass->add_method(*main_method_name, method);
 }  }
 |       methods;  |       methods;
   
Line 122  control_method: '@' STRING '\n' Line 129  control_method: '@' STRING '\n'
         const String& command=*SLA2S($2);          const String& command=*SLA2S($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->vclass!=&PC->request->root_class) { // already changed from default?                  if(PC.cclass!=&PC.request->ROOT) { // already changed from default?
                         strcpy(PC->error, "class already have a name '");                          strcpy(PC.error, "class already have a name '");
                         strncat(PC->error, PC->vclass->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=SLA2S(strings_code);
                         // creating the class                          // creating the class
                         PC->vclass=NEW VClass(POOL);                          PC.cclass=NEW VClass(POOL);
                         PC->vclass->set_name(*name);                          PC.cclass->set_name(*name);
                         // defaulting base. may change with @BASE                          // defaulting base. may change with @BASE
                         PC->vclass->set_base(PC->request->root_class);                          PC.cclass->set_base(PC.request->ROOT);
                         // append to request's classes                          // append to request's classes
                         PC->request->classes_array()+=PC->vclass;                          PC.request->classes().put(*name, PC.cclass);
                         PC->request->classes().put(*name, PC->vclass);  
                 } 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) 
                                 String file(*SLA2S(strings_code, i));                                  PC.request->use_file(
                                 file.APPEND_CONST(".p");                                          PC.request->absolute(*SLA2S(strings_code, i)));
                                 PC->request->use(file.cstr());  
                         }  
                 } else if(command==BASE_NAME) {                  } else if(command==BASE_NAME) {
                         if(PC->vclass->base()!=&PC->request->root_class) { // already changed from default?                          if(PC.cclass->base()!=&PC.request->ROOT) { // already changed from default?
                                 strcpy(PC->error, "class already have a base '");                                  strcpy(PC.error, "class already have a base '");
                                 strncat(PC->error, PC->vclass->base()->name().cstr(), 100);                                  strncat(PC.error, PC.cclass->base()->name().cstr(), 100);
                                 strcat(PC->error, "'");                                  strcat(PC.error, "'");
                                 YYERROR;                                  YYERROR;
                         }                          }
                         if(strings_code->size()==1*2) {                          if(strings_code->size()==1*2) {
                                 // TODO: преодолеть self и циклические base  
                                 const String& base_name=*SLA2S(strings_code);                                  const String& base_name=*SLA2S(strings_code);
                                 VClass *base=static_cast<VClass *>(                                  VClass *base=static_cast<VClass *>(
                                         PC->request->classes().get(base_name));                                          PC.request->classes().get(base_name));
                                 if(!base) {                                  if(!base) {
                                         strcpy(PC->error, base_name.cstr());                                          strcpy(PC.error, base_name.cstr());
                                         strcat(PC->error, ": undefined class in @"BASE_NAME);                                          strcat(PC.error, ": undefined class in @"BASE_NAME);
                                           YYERROR;
                                   }
                                   // @CLASS == @BASE sanity check
                                   if(PC.cclass==base) {
                                           strcpy(PC.error, "@"CLASS_NAME" equals @"BASE_NAME);
                                         YYERROR;                                          YYERROR;
                                 }                                  }
                                 PC->vclass->set_base(*base);                                  PC.cclass->set_base(*base);
                         } else {                          } else {
                                 strcpy(PC->error, "@"BASE_NAME" must contain sole name");                                  strcpy(PC.error, "@"BASE_NAME" must contain sole name");
                                 YYERROR;                                  YYERROR;
                         }                          }
                 } else {                  } else {
                         strcpy(PC->error, command.cstr());                          strcpy(PC.error, "'");
                         strcat(PC->error, ": invalid special name. valid names are "                          strncat(PC.error, command.cstr(), MAX_STRING/2);
                                 CLASS_NAME", "USE_CONTROL_METHOD_NAME" and "BASE_NAME);                          strcat(PC.error, "' invalid special name. valid names are "
                                   "'"CLASS_NAME"', '"USE_CONTROL_METHOD_NAME"' and '"BASE_NAME"'");
                         YYERROR;                          YYERROR;
                 }                  }
         }          }
Line 215  code_method: '@' STRING bracketed_maybe_ Line 224  code_method: '@' STRING bracketed_maybe_
                 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->vclass->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 229  maybe_comment: empty | STRING; Line 238  maybe_comment: empty | STRING;
   
 maybe_codes: empty | codes;  maybe_codes: empty | codes;
   
 codes: code | codes code {   codes: code | codes code { $$=$1; P($$, $2) };
         $$=$1;   
         P($$, $2);  
 };  
 code: write_string | action;  code: write_string | action;
 action: get | put | with | call;  action: get | put | with | call;
   
Line 240  action: get | put | with | call; Line 246  action: get | put | with | call;
   
 get: get_value {  get: get_value {
         $$=$1; /* stack: resulting value */          $$=$1; /* stack: resulting value */
         O($$, OP_WRITE); /* value=pop; wcontext.write(value) */          O($$, 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;
Line 310  construct_by_code: '[' any_constructor_c Line 316  construct_by_code: '[' any_constructor_c
         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: '(' any_expr ')' {   construct_by_expr: '(' expr_value ')' { 
         $$=$2; /* stack: context, name, value */          $$=$2; /* stack: context, name, value */
         O($$, OP_CONSTRUCT_EXPR); /* value=pop; name=pop; context=pop; construct(context,name,value) */          O($$, OP_CONSTRUCT_EXPR); /* value=pop; name=pop; context=pop; construct(context,name,value) */
 }  }
Line 333  codes__excluding_sole_str_literal: actio Line 339  codes__excluding_sole_str_literal: actio
   
 call: call_value {  call: call_value {
         $$=$1; /* stack: value */          $$=$1; /* stack: value */
         O($$, OP_WRITE); /* 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: '^' call_name store_params EON { /* ^field.$method{vasya} */
         $$=$2; /* with_xxx,diving code; stack: context,method_junction */          $$=$2; /* with_xxx,diving code; stack: context,method_junction */
Line 352  store_param: Line 358  store_param:
 ;  ;
 store_square_param: '[' store_code_param_parts ']' {$$=$2};  store_square_param: '[' store_code_param_parts ']' {$$=$2};
 store_round_param: '(' store_expr_param_parts ')' {$$=$2};  store_round_param: '(' store_expr_param_parts ')' {$$=$2};
 store_curly_param: '{' maybe_codes '}' {  store_curly_param: '{' store_curly_param_parts '}' {$$=$2};
         $$=N(POOL);   
         PCA($$, $2);  
 };  
 store_code_param_parts:  store_code_param_parts:
           empty /* optimized [] case */
   |       store_code_param_parts_not_empty
   ;
   store_code_param_parts_not_empty:
         store_code_param_part          store_code_param_part
 |       store_code_param_parts ';' store_code_param_part { $$=$1; P($$, $3) }  |       store_code_param_parts ';' store_code_param_part { $$=$1; P($$, $3) }
 ;  ;
Line 364  store_expr_param_parts: Line 371  store_expr_param_parts:
         store_expr_param_part          store_expr_param_part
 |       store_expr_param_parts ';' store_expr_param_part { $$=$1; P($$, $3) }  |       store_expr_param_parts ';' store_expr_param_part { $$=$1; P($$, $3) }
 ;  ;
   store_curly_param_parts:
           store_curly_param_part
   |       store_curly_param_parts ';' store_curly_param_part { $$=$1; P($$, $3) }
   ;
 store_code_param_part:   store_code_param_part: 
         empty /* optimized [] case */          STRING { /* optimized [STRING] case */
 |       STRING { /* optimized [STRING] case */  
         $$=$1;          $$=$1;
         O($$, OP_STORE_PARAM);          O($$, OP_STORE_PARAM);
 }  }
Line 377  store_code_param_part: Line 387  store_code_param_part:
 ;  ;
 store_expr_param_part: write_expr_value {  store_expr_param_part: write_expr_value {
         $$=N(POOL);           $$=N(POOL); 
           PEA($$, $1);
   };
   store_curly_param_part: maybe_codes {
           $$=N(POOL); 
         PCA($$, $1);          PCA($$, $1);
 };  };
 write_expr_value: any_expr {  write_expr_value: expr_value {
         $$=$1;          $$=$1;
         O($$, OP_WRITE);          O($$, OP_WRITE_EXPR_RESULT);
 };  };
   
 /* name */  /* name */
Line 415  name_expr_with_subvar_value: STRING subv Line 429  name_expr_with_subvar_value: STRING subv
         $$=N(POOL);           $$=N(POOL); 
         O($$, OP_CREATE_EWPOOL);          O($$, OP_CREATE_EWPOOL);
         P($$, $1);          P($$, $1);
         O($$, OP_WRITE);          O($$, OP_WRITE_VALUE);
         P($$, $2);          P($$, $2);
         O($$, OP_REDUCE_EWPOOL);          O($$, OP_REDUCE_EWPOOL);
 };  };
Line 449  with: '$' name_without_curly_rdive '{' c Line 463  with: '$' name_without_curly_rdive '{' c
         O($$, OP_CREATE_RWPOOL);          O($$, OP_CREATE_RWPOOL);
         P($$, $4);          P($$, $4);
         O($$, OP_REDUCE_RWPOOL);          O($$, OP_REDUCE_RWPOOL);
         O($$, OP_WRITE);          O($$, OP_WRITE_VALUE);
 };  };
   
 /* expr */  /* expr */
   
 any_expr:  
         empty_double_value /* optimized $var() case */  
 |       expr_value /* $var(something) */  
 ;  
 expr_value: expr {  expr_value: expr {
         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 499  expr: Line 509  expr:
 |       expr "ge" expr { $$=$1;  P($$, $3);  O($$, OP_STR_GE) }  |       expr "ge" expr { $$=$1;  P($$, $3);  O($$, OP_STR_GE) }
 |       expr "eq" expr { $$=$1;  P($$, $3);  O($$, OP_STR_EQ) }  |       expr "eq" expr { $$=$1;  P($$, $3);  O($$, OP_STR_EQ) }
 |       expr "ne" expr { $$=$1;  P($$, $3);  O($$, OP_STR_NE) }  |       expr "ne" expr { $$=$1;  P($$, $3);  O($$, OP_STR_NE) }
   |       expr "is" expr { $$=$1;  P($$, $3);  O($$, OP_IS) }
 ;  ;
   
 string_inside_quotes_value: maybe_codes {  string_inside_quotes_value: maybe_codes {
Line 511  string_inside_quotes_value: maybe_codes Line 522  string_inside_quotes_value: maybe_codes
 /* basics */  /* basics */
   
 write_string: STRING {  write_string: STRING {
         // optimized from OP_STRING+OP_WRITE to OP_STRING__WRITE          // optimized from OP_STRING+OP_WRITE_VALUE to OP_STRING__WRITE
         change_string_literal_to_write_string_literal($$=$1)          change_string_literal_to_write_string_literal($$=$1)
 };  };
   
 empty_double_value: /* empty */ { $$=VL(NEW VDouble(POOL, 0)) };  
 empty_string_value: /* empty */ { $$=VL(NEW VString(POOL)) };  empty_string_value: /* empty */ { $$=VL(NEW VString(POOL)) };
 empty: /* empty */ { $$=N(POOL) };  empty: /* empty */ { $$=N(POOL) };
   
 %%  %%
   #endif
   
 /*  /*
         000$111(2222)00           000$111(2222)00 
Line 537  empty: /* empty */ { $$=N(POOL) }; Line 548  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.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;
         }          }
                   
         char *begin=PC->source;          const char *begin=PC.source;
         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++));
   
                 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.ls!=LS_COMMENT) 
                           switch(*PC.source) {
                 // escaping: ^^ ^$ ^; ^) ^} ^( ^{ ^"                          // escaping: ^^ ^$ ^; ^) ^} ^( ^{ ^"
                 if(c=='^')   
                         switch(*PC->source) {  
                         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(begin, end-begin, PC.file, begin_line);
                                 }                                  }
                                 // reset piece 'begin' position & line                                  // reset piece 'begin' position & line
                                 begin=PC->source; // ^                                  begin=PC.source; // ^
                                 begin_line=PC->line;                                  begin_line=PC.line;
                                 // skip over ^ and _                                  // skip over ^ and _
                                 PC->source++;  PC->col++;                                  PC.source++;  PC.col++;
                                 // skip analysis = forced literal                                  // skip analysis = forced literal
                                 continue;                                  continue;
   
                           // converting ^#HH into char(hex(HH))
                           case '#':
                                   if(end!=begin) {
                                           // append piece till ^
                                           PC.string->APPEND(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(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) {                  // #comment  start skipping
                   if(c=='#' && PC.col==1) {
                           if(end!=begin) {
                                   // append piece till #
                                   PC.string->APPEND(begin, end-begin, PC.file, begin_line);
                           }
                           // fall into COMMENT lexical state [wait for \n]
                           push_LS(PC, LS_COMMENT);
                   }
                   switch(PC.ls) {
   
                 // USER'S = NOT OURS                  // USER'S = NOT OURS
                 case LS_USER:                  case LS_USER:
Line 596  int yylex(YYSTYPE *lvalp, void *pc) { Line 642  int yylex(YYSTYPE *lvalp, void *pc) {
                                 push_LS(PC, LS_METHOD_NAME);                                  push_LS(PC, LS_METHOD_NAME);
                                 RC;                                  RC;
                         case '@':                          case '@':
                                 if(PC->col==0+1) {                                  if(PC.col==0+1) {
                                         push_LS(PC, LS_DEF_NAME);                                          push_LS(PC, LS_DEF_NAME);
                                         RC;                                          RC;
                                 }                                  }
Line 604  int yylex(YYSTYPE *lvalp, void *pc) { Line 650  int yylex(YYSTYPE *lvalp, void *pc) {
                         }                          }
                         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:
                         switch(c) {                          switch(c) {
Line 623  int yylex(YYSTYPE *lvalp, void *pc) { Line 681  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 636  int yylex(YYSTYPE *lvalp, void *pc) { Line 694  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 650  int yylex(YYSTYPE *lvalp, void *pc) { Line 708  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 667  int yylex(YYSTYPE *lvalp, void *pc) { Line 725  int yylex(YYSTYPE *lvalp, void *pc) {
   
                 case LS_DEF_SPECIAL_BODY:                  case LS_DEF_SPECIAL_BODY:
                         if(c=='\n') {                          if(c=='\n') {
                                 switch(*PC->source) {                                  switch(*PC.source) {
                                 case '@': case 0: // end of special_code                                  case '@': case 0: // end of special_code
                                         pop_LS(PC);                                          pop_LS(PC);
                                         break;                                          break;
Line 682  int yylex(YYSTYPE *lvalp, void *pc) { Line 740  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 '$':
Line 697  int yylex(YYSTYPE *lvalp, void *pc) { Line 755  int yylex(YYSTYPE *lvalp, void *pc) {
                                 lexical_brackets_nestage++;                                  lexical_brackets_nestage++;
                                 RC;                                  RC;
                         case '-':                          case '-':
                                 if(*PC->source=='f') { // -f                                  if(*PC.source=='f') { // -f
                                         skip_analized=1;                                          skip_analized=1;
                                         result=FEXISTS;                                          result=FEXISTS;
                                 } else                                  } else
Line 708  int yylex(YYSTYPE *lvalp, void *pc) { Line 766  int yylex(YYSTYPE *lvalp, void *pc) {
                         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 731  int yylex(YYSTYPE *lvalp, void *pc) { Line 789  int yylex(YYSTYPE *lvalp, void *pc) {
                                 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
                                         if(PC->source[0]=='n') { // in                                          if(isspace(PC.source[1])) {
                                                 skip_analized=1;                                                  switch(PC.source[0]) {
                                                 result=IN;                                                  case 'n': // in
                                                 goto break2;                                                          skip_analized=1;
                                                           result=IN;
                                                           goto break2;
                                                   case 's': // is
                                                           skip_analized=1;
                                                           result=IS;
                                                           goto break2;
                                                   }
                                         }                                          }
                                 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 771  int yylex(YYSTYPE *lvalp, void *pc) { Line 838  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;
Line 780  int yylex(YYSTYPE *lvalp, void *pc) { Line 847  int yylex(YYSTYPE *lvalp, void *pc) {
                 // VARIABLE GET/PUT/WITH                  // VARIABLE GET/PUT/WITH
                 case LS_VAR_NAME_SIMPLE:                  case LS_VAR_NAME_SIMPLE:
                 case LS_EXPRESSION_VAR_NAME:                  case LS_EXPRESSION_VAR_NAME:
                         if(PC->ls==LS_EXPRESSION_VAR_NAME) {                          if(PC.ls==LS_EXPRESSION_VAR_NAME) {
                                 // name in expr ends also before binary operators                                   // name in expr ends also before binary operators 
                                 switch(c) {                                  switch(c) {
                                 case '+': case '-': case '*': case '/': case '%':                                   case '-': 
                                 case '&': case '|':   
                                 case '=': 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 798  int yylex(YYSTYPE *lvalp, void *pc) { Line 863  int yylex(YYSTYPE *lvalp, void *pc) {
                         case ';':                          case ';':
                         case ']': case '}': case ')': case '"':                          case ']': case '}': case ')': case '"':
                         case '<': case '>':  // these stand for HTML brackets and expression binary ops                          case '<': case '>':  // these stand for HTML brackets and expression binary ops
                           case '+': case '*': case '/': case '%': 
                           case '&': case '|': 
                           case '=': case '!':
                           // common delimiters
                           case '\'': 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;                                  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
Line 884  int yylex(YYSTYPE *lvalp, void *pc) { Line 954  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;                                  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 
Line 914  int yylex(YYSTYPE *lvalp, void *pc) { Line 984  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 932  int yylex(YYSTYPE *lvalp, void *pc) { Line 1002  int yylex(YYSTYPE *lvalp, void *pc) {
                         case '^':                          case '^':
                                 push_LS(PC, LS_METHOD_NAME);                                  push_LS(PC, LS_METHOD_NAME);
                                 RC;                                  RC;
                           case ';': // param delim
                                   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 946  int yylex(YYSTYPE *lvalp, void *pc) { Line 1018  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 979  break2: Line 1051  break2:
                 }                  }
                 if(end!=begin) { // last piece still alive?                  if(end!=begin) { // last piece still alive?
                         // append it                          // append it
                         PC->string->APPEND(begin, end-begin, PC->file, begin_line/*, start_col*/);                          PC.string->APPEND(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);
        //fprintf(stderr, "[%s]\n", s);  
   
            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\"", SLA2S(value)->cstr());
   }

Removed from v.1.88  
changed lines
  Added in v.1.118


E-mail: