Diff for /parser3/src/main/compile.y between versions 1.97 and 1.138

version 1.97, 2001/03/13 20:02:10 version 1.138, 2001/05/28 06:10:06
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> (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
 */  */
   
 %{  %{
Line 22 Line 24
 #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 "core.h"  #include "pa_globals.h"
   #include "pa_vnothing.h"
   
 #define SELF_ELEMENT_NAME "self"  #define SELF_ELEMENT_NAME "self"
 #define USE_CONTROL_METHOD_NAME "USE"  #define USE_CONTROL_METHOD_NAME "USE"
   #define END_CONTROL_METHOD_NAME "end"
   
 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
 %}  %}
   
 %pure_parser  %pure_parser
Line 59  int yylex(YYSTYPE *lvalp, void *pc); Line 60  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 81  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 */
Line 107  all: Line 109  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 120  one_big_piece: maybe_codes; Line 123  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(command==END_CONTROL_METHOD_NAME && strings_code->size()==0)
                   break;
         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_class) { // already changed from default?                  if(PC.cclass) { // 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_class);  
                         // 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(
                                 String file(*SLA2S(strings_code, i));                          PC.request->absolute(*LA2S(strings_code, i)));
                                 file.APPEND_CONST(".p");          } else if(command==BASE_NAME) {
                                 PC->request->use_file(file.cstr());                  if(PC.cclass->base()!=&PC.request->OP) { // already changed from default?
                         }                          strcpy(PC.error, "class already have a base '");
                 } else if(command==BASE_NAME) {                          strncat(PC.error, PC.cclass->base()->name().cstr(), 100);
                         if(PC->cclass->base()!=&PC->request->root_class) { // already changed from default?                          strcat(PC.error, "'");
                                 strcpy(PC->error, "class already have a base '");                          YYERROR;
                                 strncat(PC->error, PC->cclass->base()->name().cstr(), 100);                  }
                                 strcat(PC->error, "'");                  if(strings_code->size()==1*2) {
                           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 209  code_method: '@' STRING bracketed_maybe_ Line 213  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 239  action: get | put | with | call; Line 244  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 251  name_without_curly_rdive: Line 256  name_without_curly_rdive:
 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);
         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, 
Line 284  name_expr_wdive: Line 289  name_expr_wdive:
 name_expr_wdive_write: name_expr_dive_code {  name_expr_wdive_write: 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);
         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, 
Line 315  construct_by_expr: '(' expr_value ')' { Line 320  construct_by_expr: '(' expr_value ')' {
 }  }
 ;  ;
 any_constructor_code_value:   any_constructor_code_value: 
         empty_string_value /* optimized $var[] case */          unknown_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] */
 ;  ;
Line 332  codes__excluding_sole_str_literal: actio Line 337  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 */
         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=$3;
           if(params_code->size()==3) // probably [] case. [OP_VALUE + Nothing + STORE_PARAM]
                   if(Value *value=LA2V(params_code)) // it is OP_VALUE + value?
                           if(!value->is_defined()) // value is VNothing?
                                   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 364  store_curly_param_parts: Line 376  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); 
         PCA($$, $1);          PEA($$, $1);
 };  };
 store_curly_param_part: maybe_codes {  store_curly_param_part: maybe_codes {
         $$=N(POOL);           $$=N(POOL); 
         PCA($$, $1);          PCA($$, $1);
 };  };
   code_param_value:
           unknown_value /* optimized [;...] case */
   |       STRING /* optimized [STRING] case */
   |       constructor_code_value /* [something complex] */
   ;
 write_expr_value: expr_value {  write_expr_value: expr_value {
         $$=$1;          $$=$1;
         O($$, OP_WRITE);          O($$, OP_WRITE_EXPR_RESULT);
 };  };
   
 /* name */  /* name */
Line 419  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 448  class_prefix: STRING ':' { Line 458  class_prefix: STRING ':' {
   
 /* with */  /* with */
   
 with: '$' name_without_curly_rdive '{' codes '}' {  with: '$' name_without_curly_rdive '{' maybe_codes '}' {
         $$=$2;          $$=$2;
         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 */
Line 475  expr: Line 485  expr:
 |       "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) }
Line 512  string_inside_quotes_value: maybe_codes Line 523  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_string_value: /* empty */ { $$=VL(NEW VString(POOL)) };  unknown_value: /* empty */ { $$=VL(NEW VNothing(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 549  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;
         }          }
                   
         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++));
   
                 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 && PC.ls!=LS_DEF_COMMENT) 
                           switch(*PC.source) {
                 // escaping: ^^ ^$ ^; ^) ^} ^( ^{ ^"                          // escaping: ^^ & co
                 if(c=='^')   
                         switch(*PC->source) {  
                         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; // ^                                  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_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) {                  // #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);
                   }
                   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 644  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 652  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 683  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 696  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 710  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 727  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 742  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 757  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 ';':
                                 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 799  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
                                         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 766  int yylex(YYSTYPE *lvalp, void *pc) { Line 834  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 780  int yylex(YYSTYPE *lvalp, void *pc) { Line 848  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 789  int yylex(YYSTYPE *lvalp, void *pc) { Line 857  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 '-': 
                                         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 803  int yylex(YYSTYPE *lvalp, void *pc) { Line 871  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 '\'':
                         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 '%': 
                         case '&': case '|':                           case '&': case '|': 
                         case '=': case '!':                          case '=': case '!':
                           // common delimiters
                           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 894  int yylex(YYSTYPE *lvalp, void *pc) { Line 965  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 924  int yylex(YYSTYPE *lvalp, void *pc) { Line 995  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 946  int yylex(YYSTYPE *lvalp, void *pc) { Line 1017  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 958  int yylex(YYSTYPE *lvalp, void *pc) { Line 1029  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 988  break2: Line 1059  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);
        //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\"", LA2S(value)->cstr());
   }

Removed from v.1.97  
changed lines
  Added in v.1.138


E-mail: