--- parser3/src/main/compile.y 2001/03/07 10:27:10 1.64 +++ parser3/src/main/compile.y 2001/03/24 15:58:00 1.111 @@ -1,18 +1,35 @@ -/* - $Id: compile.y,v 1.64 2001/03/07 10:27:10 paf Exp $ +/** @file + Parser: compiler(lexical parser and grammar). + + Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) + + Author: Alexander Petrosyan (http://design.ru/paf) + + $Id: compile.y,v 1.111 2001/03/24 15:58:00 paf Exp $ +*/ + +/** + @todo parser4: + - cache compiled code from request to request. to do that... + -#: make method definitions, @CLASS, @BASE, @USE instructions, + which would be executed afterwards, and actions + now performed at compile time would be delayed to run time. + -#: make cache expiration on time and on disk-change of class source + -#: in apache use subpools for compiled class storage + -#: in iis make up specialized Pool object for that */ %{ -#define YYSTYPE Array/**/ * +#define YYSTYPE Array/**/ * #define YYPARSE_PARAM pc #define YYLEX_PARAM pc #define YYDEBUG 1 -#define YYERROR_VERBOSE +#define YYERROR_VERBOSE 1 #define yyerror(msg) real_yyerror((parse_control *)pc, msg) #define YYPRINT(file, type, value) yyprint(file, type, value) +#include "pa_config_includes.h" #include -#include #include #include "compile_tools.h" @@ -20,9 +37,10 @@ #include "pa_request.h" #include "pa_vobject.h" #include "pa_vdouble.h" +#include "pa_globals.h" -#define SELF_NAME "self" -#define USES_NAME "USES" +#define SELF_ELEMENT_NAME "self" +#define USE_CONTROL_METHOD_NAME "USE" int real_yyerror(parse_control *pc, char *s); static void yyprint(FILE *file, int type, YYSTYPE value); @@ -34,6 +52,7 @@ int yylex(YYSTYPE *lvalp, void *pc); #define POOL *PC->pool #undef NEW #define NEW new(POOL) +#ifndef DOXYGEN %} %pure_parser @@ -60,19 +79,26 @@ int yylex(YYSTYPE *lvalp, void *pc); %token SEQ "eq" %token SNE "ne" +%token DEF "def" +%token IN "in" +%token FEXISTS "-f" +%token IS "is" + /* logical */ +%left "is" %left "lt" "gt" "le" "ge" %left "eq" "ne" %left '<' '>' "<=" ">=" "##" %left "==" "!=" %left "||" %left "&&" -%left NOT /* not: unary ! */ +%left "def" "in" "-f" +%left '!' /* bitwise */ %left '#' %left '&' '|' -%left INV /* invertion: unary ~ */ +%left '~' /* numerical */ %left '-' '+' @@ -80,15 +106,14 @@ int yylex(YYSTYPE *lvalp, void *pc); %left NEG /* negation: unary - */ %% - all: one_big_piece { - String& name_main=*NEW String(POOL); - name_main.APPEND_CONST(MAIN_METHOD_NAME); - Array& param_names=*NEW Array(POOL); - Array& local_names=*NEW Array(POOL); - Method& method=*NEW Method(POOL, name_main, param_names, local_names, *$1); - PC->vclass->add_method(name_main, method); + Method& method=*NEW Method(POOL, + *main_method_name, + 0, 0, /*min, max numbered_params_count*/ + 0/*param_names*/, 0/*local_names*/, + $1/*parser_code*/, 0/*native_code*/); + PC->cclass->add_method(*main_method_name, method); } | methods; @@ -99,31 +124,49 @@ method: control_method | code_method; control_method: '@' STRING '\n' control_strings { - String& name=*SLA2S($2); + const String& command=*SLA2S($2); YYSTYPE strings_code=$4; if(strings_code->size()<1*2) { strcpy(PC->error, "@"); - strcat(PC->error, name.cstr()); + strcat(PC->error, command.cstr()); strcat(PC->error, " is empty"); YYERROR; } - if(name==CLASS_NAME) { - if(strings_code->size()==1*2) - PC->vclass->set_name(*SLA2S(strings_code)); - else { + if(command==CLASS_NAME) { + if(PC->cclass!=&PC->request->ROOT) { // already changed from default? + strcpy(PC->error, "class already have a name '"); + strncat(PC->error, PC->cclass->name().cstr(), 100); + strcat(PC->error, "'"); + YYERROR; + } + if(strings_code->size()==1*2) { + // new class' name + const String *name=SLA2S(strings_code); + // creating the class + PC->cclass=NEW VClass(POOL); + PC->cclass->set_name(*name); + // defaulting base. may change with @BASE + PC->cclass->set_base(PC->request->ROOT); + // append to request's classes + PC->request->classes().put(*name, PC->cclass); + } else { strcpy(PC->error, "@"CLASS_NAME" must contain sole name"); YYERROR; } } else { - if(name==USES_NAME) { - for(int i=0; isize(); i+=2) { - String *file=SLA2S(strings_code, i); - file->APPEND_CONST(".p"); - PC->request->use(file->cstr(), 0); + if(command==USE_CONTROL_METHOD_NAME) { + for(int i=0; isize(); i+=2) + PC->request->use_file( + PC->request->absolute(*SLA2S(strings_code, i))); + } else if(command==BASE_NAME) { + if(PC->cclass->base()!=&PC->request->ROOT) { // already changed from default? + strcpy(PC->error, "class already have a base '"); + strncat(PC->error, PC->cclass->base()->name().cstr(), 100); + strcat(PC->error, "'"); + YYERROR; } - } else if(name==BASE_NAME) { if(strings_code->size()==1*2) { - String& base_name=*SLA2S(strings_code); + const String& base_name=*SLA2S(strings_code); VClass *base=static_cast( PC->request->classes().get(base_name)); if(!base) { @@ -131,15 +174,21 @@ control_method: '@' STRING '\n' strcat(PC->error, ": undefined class in @"BASE_NAME); YYERROR; } - PC->vclass->set_base(*base); + // @CLASS == @BASE sanity check + if(PC->cclass==base) { + strcpy(PC->error, "@"CLASS_NAME" equals @"BASE_NAME); + YYERROR; + } + PC->cclass->set_base(*base); } else { strcpy(PC->error, "@"BASE_NAME" must contain sole name"); YYERROR; } } else { - strcpy(PC->error, name.cstr()); - strcat(PC->error, ": invalid special name. valid names are " - CLASS_NAME", "USES_NAME" and "BASE_NAME); + 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; } } @@ -153,17 +202,27 @@ code_method: '@' STRING bracketed_maybe_ const String *name=SLA2S($2); YYSTYPE params_names_code=$3; - Array& params_names=*NEW Array(POOL); - for(int i=0; isize(); i+=2) - params_names+=SLA2S(params_names_code, i); + Array *params_names=0; + if(int size=params_names_code->size()) { + params_names=NEW Array(POOL); + for(int i=0; isize(); i+=2) - locals_names+=SLA2S(locals_names_code, i); + Array *locals_names=0; + if(int size=locals_names_code->size()) { + locals_names=NEW Array(POOL); + for(int i=0; ivclass->add_method(*name, method); + Method& method=*NEW Method(POOL, + *name, + 0, 0/*min,max numbered_params_count*/, + params_names, locals_names, + $7, 0); + PC->cclass->add_method(*name, method); }; maybe_bracketed_strings: empty | bracketed_maybe_strings; @@ -177,18 +236,15 @@ maybe_comment: empty | STRING; maybe_codes: empty | codes; -codes: code | codes code { - $$=$1; - P($$, $2); -}; -code: write_str_literal | action; +codes: code | codes code { $$=$1; P($$, $2) }; +code: write_string | action; action: get | put | with | call; /* get */ get: get_value { $$=$1; /* stack: resulting value */ - O($$, OP_WRITE); /* value=pop; write(value) */ + O($$, OP_WRITE_VALUE); /* value=pop; wcontext.write(value) */ }; get_value: '$' get_name_value { $$=$2 } get_name_value: name_without_curly_rdive EON | name_in_curly_rdive; @@ -200,8 +256,8 @@ name_without_curly_rdive: name_without_curly_rdive_read: name_without_curly_rdive_code { $$=N(POOL); Array *diving_code=$1; - String *first_name=SLA2S(diving_code); - if(first_name && *first_name==SELF_NAME) { + const String *first_name=SLA2S(diving_code); + if(first_name && *first_name==SELF_ELEMENT_NAME) { O($$, OP_WITH_SELF); /* stack: starting context */ P($$, diving_code, /* skip over... */ @@ -222,10 +278,9 @@ name_without_curly_rdive_code: name_adva /* put */ -put: '$' name_expr_wdive constructor_value { +put: '$' name_expr_wdive construct { $$=$2; /* stack: context,name */ P($$, $3); /* stack: context,name,constructor_value */ - O($$, OP_CONSTRUCT); /* value=pop; name=pop; context=pop; construct(context,name,value) */ }; name_expr_wdive: name_expr_wdive_write @@ -234,8 +289,8 @@ name_expr_wdive: name_expr_wdive_write: name_expr_dive_code { $$=N(POOL); Array *diving_code=$1; - String *first_name=SLA2S(diving_code); - if(first_name && *first_name==SELF_NAME) { + const String *first_name=SLA2S(diving_code); + if(first_name && *first_name==SELF_ELEMENT_NAME) { O($$, OP_WITH_SELF); /* stack: starting context */ P($$, diving_code, /* skip over... */ @@ -253,9 +308,16 @@ name_expr_wdive_root: ':' name_expr_dive }; name_expr_wdive_class: class_prefix name_expr_dive_code { $$=$1; P($$, $2) }; -constructor_value: - '[' any_constructor_code_value ']' { $$=$2 } -| '(' any_expr ')' { $$=$2 } +construct: construct_by_code | construct_by_expr; +construct_by_code: '[' any_constructor_code_value ']' { + $$=$2; /* stack: context, name, value */ + O($$, OP_CONSTRUCT_VALUE); /* value=pop; name=pop; context=pop; construct(context,name,value) */ +} +; +construct_by_expr: '(' expr_value ')' { + $$=$2; /* stack: context, name, value */ + O($$, OP_CONSTRUCT_EXPR); /* value=pop; name=pop; context=pop; construct(context,name,value) */ +} ; any_constructor_code_value: empty_string_value /* optimized $var[] case */ @@ -265,7 +327,7 @@ any_constructor_code_value: constructor_code_value: constructor_code { $$=N(POOL); O($$, OP_CREATE_EWPOOL); /* stack: empty write context */ - P($$, $1); /* some codes to that context */ + P($$, $1); /* some code that writes to that context */ O($$, OP_REDUCE_EWPOOL); /* context=pop; stack: context.value() */ }; constructor_code: codes__excluding_sole_str_literal; @@ -273,38 +335,63 @@ codes__excluding_sole_str_literal: actio /* call */ -call: '^' call_name store_params EON { /* ^field.$method{vasya} */ +call: call_value { + $$=$1; /* stack: value */ + O($$, OP_WRITE_VALUE); /* value=pop; wcontext.write(value) */ +}; +call_value: '^' call_name store_params EON { /* ^field.$method{vasya} */ $$=$2; /* with_xxx,diving code; stack: context,method_junction */ 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) */ + O($$, OP_CALL); /* method_frame=pop; ncontext=pop; call(ncontext,method_frame) stack: value */ }; call_name: name_without_curly_rdive; store_params: store_param | store_params store_param { $$=$1; P($$, $2) }; -store_param: store_round_param | store_curly_param; -store_round_param: '[' store_param_parts ']' {$$=$2}; -store_param_parts: - store_param_part -| store_param_parts ';' store_param_part { $$=$1; P($$, $3) } +store_param: + store_square_param +| store_round_param +| store_curly_param ; -store_curly_param: '{' maybe_codes '}' { - $$=N(POOL); - PCA($$, $2); - O($$, OP_STORE_PARAM); -}; -store_param_part: - empty /* optimized () case */ -| STRING { /* optimized (STRING) case */ +store_square_param: '[' store_code_param_parts ']' {$$=$2}; +store_round_param: '(' store_expr_param_parts ')' {$$=$2}; +store_curly_param: '{' store_curly_param_parts '}' {$$=$2}; +store_code_param_parts: + store_code_param_part +| store_code_param_parts ';' store_code_param_part { $$=$1; P($$, $3) } +; +store_expr_param_parts: + store_expr_param_part +| 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: + empty /* optimized [] case */ +| STRING { /* optimized [STRING] case */ $$=$1; O($$, OP_STORE_PARAM); } -| constructor_code_value { /* (something complex) */ +| constructor_code_value { /* [something complex] */ $$=$1; O($$, OP_STORE_PARAM); } ; +store_expr_param_part: write_expr_value { + $$=N(POOL); + PEA($$, $1); +}; +store_curly_param_part: maybe_codes { + $$=N(POOL); + PCA($$, $1); +}; +write_expr_value: expr_value { + $$=$1; + O($$, OP_WRITE_EXPR_RESULT); +}; /* name */ @@ -337,7 +424,7 @@ name_expr_with_subvar_value: STRING subv $$=N(POOL); O($$, OP_CREATE_EWPOOL); P($$, $1); - O($$, OP_WRITE); + O($$, OP_WRITE_VALUE); P($$, $2); O($$, OP_REDUCE_EWPOOL); }; @@ -359,16 +446,8 @@ subvar__get_write: '$' subvar_ref_name_r }; class_prefix: STRING ':' { - String& name=*SLA2S($1); - VClass *vclass=static_cast(PC->request->classes().get(name)); - if(!vclass) { - strcpy(PC->error, "'"); - strcat(PC->error, name.cstr()); - strcat(PC->error, "' class is undefined in call"); - YYERROR; - } - //TODO: убрать зависимость от статических @USE, сделать имя, а не ссылку - $$=CL(vclass); // vclass + $$=$1; // stack: class name string + O($$, OP_GET_CLASS); }; @@ -379,30 +458,28 @@ with: '$' name_without_curly_rdive '{' c O($$, OP_CREATE_RWPOOL); P($$, $4); O($$, OP_REDUCE_RWPOOL); - O($$, OP_WRITE); + O($$, OP_WRITE_VALUE); }; /* expr */ -any_expr: - empty_double_value /* optimized $var() case */ -| optimized_expr /* $var(something) */ -; -optimized_expr: expr { - if(($$=$1)->size()==2) { // only one string literal in there? +expr_value: expr { + if(($$=$1)->size()==2) // only one string literal in there? change_string_literal_to_double_literal($$); // make that string literal Double - } }; expr: STRING | get_value +| call_value | '"' string_inside_quotes_value '"' { $$ = $2; } | '(' expr ')' { $$ = $2; } /* stack: operand // stack: @operand */ | '-' expr %prec NEG { $$=$2; O($$, OP_NEG) } -| '~' expr %prec INV { $$=$2; O($$, OP_INV) } -| '!' expr %prec NOT { $$=$2; O($$, OP_NOT) } -/*todo: def in fexists*/ +| '~' expr { $$=$2; O($$, OP_INV) } +| '!' expr { $$=$2; O($$, OP_NOT) } +| "def" expr { $$=$2; O($$, OP_DEF) } +| "in" expr { $$=$2; O($$, OP_IN) } +| "-f" expr { $$=$2; O($$, OP_FEXISTS) } /* stack: a,b // stack: a@b */ | expr '-' expr { $$=$1; P($$, $3); O($$, OP_SUB) } | expr '+' expr { $$=$1; P($$, $3); O($$, OP_ADD) } @@ -427,35 +504,28 @@ expr: | expr "ge" expr { $$=$1; P($$, $3); O($$, OP_STR_GE) } | expr "eq" expr { $$=$1; P($$, $3); O($$, OP_STR_EQ) } | 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*/ { +string_inside_quotes_value: maybe_codes { $$=N(POOL); O($$, OP_CREATE_SWPOOL); /* stack: empty write context */ - P($$, $1); /* some codes to that context */ + P($$, $1); /* some code that writes to that context */ O($$, OP_REDUCE_SWPOOL); /* context=pop; stack: context.get_string() */ }; -/*string_inside_quotes: - string_inside_quotes_part -| string_inside_quotes string_inside_quotes_part { - $$=$1; P($$, $2) -} -; -string_inside_quotes_part: STRING | get_value; -*/ /* basics */ -write_str_literal: STRING { - $$=$1; - O($$, OP_WRITE); +write_string: STRING { + // optimized from OP_STRING+OP_WRITE_VALUE to OP_STRING__WRITE + change_string_literal_to_write_string_literal($$=$1) }; -empty_double_value: /* empty */ { $$=VL(NEW VDouble(POOL)) }; empty_string_value: /* empty */ { $$=VL(NEW VString(POOL)) }; empty: /* empty */ { $$=N(POOL) }; %% +#endif /* 000$111(2222)00 @@ -473,7 +543,7 @@ empty: /* empty */ { $$=N(POOL) }; 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 RC {result=c; goto break2; } @@ -486,10 +556,10 @@ int yylex(YYSTYPE *lvalp, void *pc) { return result; } - char *begin=PC->source; - char *end; + const char *begin=PC->source; + const char *end; int begin_line=PC->line; - bool skip_analized_char=false; + int skip_analized=0; while(true) { c=*(end=(PC->source++)); @@ -499,6 +569,8 @@ int yylex(YYSTYPE *lvalp, void *pc) { } else PC->col++; + // todo: # in 0+1 column comment + // escaping: ^^ ^$ ^; ^) ^} ^( ^{ ^" if(c=='^') switch(*PC->source) { @@ -611,14 +683,18 @@ int yylex(YYSTYPE *lvalp, void *pc) { break; // (EXPRESSION) - case LS_EXPRESSION_BODY: + case LS_VAR_ROUND: + case LS_METHOD_ROUND: switch(c) { case ')': if(--lexical_brackets_nestage==0) - pop_LS(PC); //(EXPRESSION). + if(PC->ls==LS_METHOD_ROUND) // method round param ended + PC->ls=LS_METHOD_AFTER; // look for method end + else // PC->ls==LS_VAR_ROUND // variable constructor ended + pop_LS(PC); // return to normal life RC; case '$': - push_LS(PC, LS_VAR_NAME_IN_EXPRESSION); + push_LS(PC, LS_EXPRESSION_VAR_NAME); RC; case '^': push_LS(PC, LS_METHOD_NAME); @@ -626,20 +702,27 @@ int yylex(YYSTYPE *lvalp, void *pc) { case '(': lexical_brackets_nestage++; RC; - case '+': case '-': case '*': case '/': case '%': + case '-': + if(*PC->source=='f') { // -f + skip_analized=1; + result=FEXISTS; + } else + result=c; + goto break2; + case '+': case '*': case '/': case '%': case '~': case ';': RC; case '&': case '|': case '#': if(*PC->source==c) { // && || result=c=='#'?LXOR:c=='&'?LAND:LOR; - skip_analized_char=true; + skip_analized=1; } else result=c; goto break2; case '<': case '>': case '=': case '!': if(*PC->source=='=') { // <= >= == != - skip_analized_char=true; + skip_analized=1; switch(c) { case '<': result=NLE; break; case '>': result=NGE; break; @@ -658,15 +741,40 @@ int yylex(YYSTYPE *lvalp, void *pc) { // case '?': // ok [and bad cases, yacc would bark at them] case 't': // lt gt [et nt] result=c=='l'?SLT:c=='g'?SGT:BAD_STRING_COMPARISON_OPERATOR; - skip_analized_char=true; + skip_analized=1; goto break2; case 'e': // le ge ne [ee] result=c=='l'?SLE:c=='g'?SGE:c=='n'?SNE:BAD_STRING_COMPARISON_OPERATOR; - skip_analized_char=true; + skip_analized=1; goto break2; case 'q': // eq [lq gq nq] result=c=='e'?SEQ:BAD_STRING_COMPARISON_OPERATOR; - skip_analized_char=true; + skip_analized=1; + goto break2; + } + break; + case 'i': + if(end==begin) // right after whitespace + switch(PC->source[0]) { + case 'n': + { // in + skip_analized=1; + result=IN; + goto break2; + } + case 's': + { // is + skip_analized=1; + result=IS; + goto break2; + } + } + break; + case 'd': + if(end==begin) // right after whitespace + if(PC->source[0]=='e' && PC->source[1]=='f') { // def + skip_analized=2; + result=DEF; goto break2; } break; @@ -686,13 +794,11 @@ int yylex(YYSTYPE *lvalp, void *pc) { // VARIABLE GET/PUT/WITH case LS_VAR_NAME_SIMPLE: - case LS_VAR_NAME_IN_EXPRESSION: - if(PC->ls==LS_VAR_NAME_IN_EXPRESSION) { + case LS_EXPRESSION_VAR_NAME: + if(PC->ls==LS_EXPRESSION_VAR_NAME) { // name in expr ends also before binary operators switch(c) { - case '+': case '-': case '*': case '/': case '%': - case '&': case '|': - case '<': case '>': case '=': case '!': + case '-': pop_LS(PC); PC->source--; if(--PC->col<0) { PC->line--; PC->col=-1; } result=EON; @@ -704,6 +810,12 @@ int yylex(YYSTYPE *lvalp, void *pc) { case ' ': case '\t': case '\n': case ';': case ']': case '}': case ')': case '"': + 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); PC->source--; if(--PC->col<0) { PC->line--; PC->col=-1; } result=EON; @@ -719,10 +831,10 @@ int yylex(YYSTYPE *lvalp, void *pc) { PC->ls=LS_VAR_CURLY; lexical_brackets_nestage=1; } - + RC; case '(': - PC->ls=LS_EXPRESSION_BODY; + PC->ls=LS_VAR_ROUND; lexical_brackets_nestage=1; RC; case '.': // name part delim @@ -797,6 +909,10 @@ int yylex(YYSTYPE *lvalp, void *pc) { PC->ls=LS_METHOD_CURLY; lexical_brackets_nestage=1; RC; + case '(': + PC->ls=LS_METHOD_ROUND; + lexical_brackets_nestage=1; + RC; case '.': // name part delim case '$': // name part subvar case ':': // ':name' or 'class:name' @@ -834,6 +950,8 @@ int yylex(YYSTYPE *lvalp, void *pc) { case '^': push_LS(PC, LS_METHOD_NAME); RC; + case ';': // param delim + RC; case '}': if(--lexical_brackets_nestage==0) { PC->ls=LS_METHOD_AFTER; @@ -847,16 +965,21 @@ int yylex(YYSTYPE *lvalp, void *pc) { break; case LS_METHOD_AFTER: - if(c=='[') {/* )( }( */ + if(c=='[') {/* ][ }[ )[ */ PC->ls=LS_METHOD_SQUARE; lexical_brackets_nestage=1; RC; } - if(c=='{') {/* ){ }{ */ + if(c=='{') {/* ]{ }{ ){ */ PC->ls=LS_METHOD_CURLY; lexical_brackets_nestage=1; RC; } + if(c=='(') {/* ]( }( )( */ + PC->ls=LS_METHOD_ROUND; + lexical_brackets_nestage=1; + RC; + } pop_LS(PC); PC->source--; if(--PC->col<0) { PC->line--; PC->col=-1; } result=EON; @@ -887,27 +1010,18 @@ break2: // make current result be pending for next call, return STRING for now PC->pending_state=result; result=STRING; } - if(skip_analized_char) { - PC->source++; PC->col++; + if(skip_analized) { + PC->source+=skip_analized; PC->col+=skip_analized; } return result; } -int real_yyerror(parse_control *pc, char *s) /* Called by yyparse on error */ - { - //fprintf(stderr, "[%s]\n", s); - - strncpy(pc->error, s, MAX_STRING); // TODO: перепроверить с треклятым последним байтом +static int real_yyerror(parse_control *pc, char *s) { // Called by yyparse on error + strncpy(pc->error, s, MAX_STRING); 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()); +}