%{
/*
 * This is the grammar definition of LPC. Expect one shift/reduce conflict,
 * because of if-then-else. The default, to shift this conflict, is the
 * correct solution.
 */
#include <string.h>
#include <stdio.h>
#include "lint.h"
#include "lnode.h"
#include "config.h"
#include "interpret.h"
#include "object.h"

#define YYMAXDEPTH	600

struct lnode *prog, *heart_beat;
int variable_count;
void yyerror(), free_all_local_names(), add_local_name(), smart_log();
extern int yylex(), check_deklared();
static void copy_variables();
int static_variable_flag;

char *argument_name;	/* The name of the current argument. */
char *xalloc(), *string_copy();

extern int current_line;
/*
 * 'inherit_file' is used as a flag. If it is set to a string
 * after yyparse(), this string should be loaded as an object,
 * and the original object must be loaded again.
 * 'inherit_ob' will point to the super class object. This value is saved
 * so that load_object() can set up pointers to it.
 */
extern char *current_file, *inherit_file;

extern struct object *find_object2();

struct object *inherit_ob;

char *local_names[MAX_LOCAL];
int current_number_of_locals = 0;
static int num_arg;
%}

%token F_THIS_PLAYER F_IF F_IDENTIFIER F_LAND F_LOR F_STATUS F_SET_TRUE
%token F_SET_FALSE F_CONS F_RETURN F_NOT F_WRITE F_STRING F_ADD_VERB
%token F_ADD_ADJ F_ADD_SUBST F_ADD_ACTION F_MOVE_OBJECT F_INC F_DEC
%token F_POST_INC F_POST_DEC F_COMMA F_COND F_QUERY_LOAD_AVERAGE F_THIS_VERB
%token F_NUMBER F_ASSIGN F_INT F_CALL_OTHER F_ADD F_SUBTRACT F_MULTIPLY
%token F_DIVIDE F_LT F_GT F_EQ F_GE F_LE F_ARGUMENT F_FUNCTION
%token F_CLONE_OBJECT F_THIS_OBJECT F_SAVE_OBJECT F_RESTORE_OBJECT F_NE
%token F_ENVIRONMENT F_ADD_EQ F_SUB_EQ F_DIV_EQ F_MULT_EQ F_PRESENT
%token F_COMMAND F_SET_LIGHT F_DESTRUCT F_CREATE_WIZARD F_NEGATE F_SAY
%token F_STRLEN F_SUBSCRIPT F_WHILE F_BREAK F_SHUTDOWN F_LOG_FILE
%token F_DO F_FOR F_ADD_XVERB F_FIND_CALL_OUT F_READ_FILE F_FILTER_OBJECTS
%token F_SSCANF F_SHOUT F_STRING_DECL F_LOCAL_NAME F_FIRST_INVENTORY
%token F_NEXT_INVENTORY F_ENABLE_COMMANDS F_RANDOM F_INPUT_TO F_CRYPT
%token F_LS F_CAT F_FIND_LIVING F_TELL_OBJECT F_PEOPLE F_ED F_LIVING
%token F_LOWER_CASE F_ELSE F_CAPITALIZE F_SET_HEART_BEAT F_SNOOP F_TELL_ROOM
%token F_FIND_OBJECT F_RM F_CONST0 F_CONST1 F_BLOCK F_TRANSFER
%token F_REGCOMP F_REGEXEC F_LOCALCMD F_SWAP F_CONTINUE F_ADD_WORTH F_TIME
%token F_MOD F_MOD_EQ F_QUERY_IP_NUMBER F_INHERIT F_COLON_COLON F_CREATOR
%token F_STATIC F_CALL_OUT F_REMOVE_CALL_OUT F_COMBINE_FREE_LIST F_ALLOCATE
%token F_SIZEOF F_DISABLE_COMMANDS F_CTIME F_INTP F_STRINGP F_OBJECTP
%token F_POINTERP F_USERS F_ARROW F_PREVIOUS_OBJECT F_AGGREGATE F_EXTRACT
%token F_FILE_NAME F_QUERY_VERB F_TAIL F_QUERY_HOST_NAME F_EXPLODE
%token F_COMPL F_AND F_AND_EQ F_OR F_OR_EQ F_XOR F_XOR_EQ F_CP F_RENAME
%token F_LSH F_LSH_EQ F_RSH F_RSH_EQ F_MKDIR F_RMDIR F_QUERY_SNOOP F_THROW
%token F_FIND_PLAYER F_WRITE_FILE F_FILE_SIZE F_PARSE_COMMAND F_IMPLODE
%token F_QUERY_IDLE F_REMOTE_COMMAND F_INTERACTIVE F_CALLER F_TYPEOF F_CATCH
%token F_NOTIFY_FAIL F_SET_LIVING_NAME F_SET_BIT F_CLEAR_BIT F_TEST_BIT
%token F_REALLOCATE F_INDEX F_SEARCHA F_CONTENTS F_IN_EDITOR F_GREP

%union
{
	struct lnode *lnode;
	int number;
	char *string;
}

%type <lnode> cond expr1 expr_list expr2 expr3 function_call variable expr11
%type <lnode> statements statement program def return expr4 expr31
%type <lnode> string expr0 F_NUMBER expr25 expr27 expr23 expr22 while do for
%type <lnode> expr24 expr211 expr212 expr213 comma_expr for_expr
%type <lnode> F_LOCAL_NAME block number F_CONST0 F_CONST1

%type <number> name F_SET_FALSE F_SET_TRUE F_THIS_PLAYER F_WRITE F_THIS_OBJECT
%type <number> assign static F_CATCH F_THROW

%type <string> F_IDENTIFIER F_STRING F_ARGUMENT function_name

%%

all: program { prog = $1; };

program: def possible_semi_colon program
	{ if ($1 != 0) {
	    struct lnode_def *p = (struct lnode_def *)$1;
	    p->next = (struct lnode_def *)$3;
	    $$ = (struct lnode *)p;
	  } else
	    $$ = $3;
        }
       |	 /* empty */ { $$ = 0; };

possible_semi_colon: /* empty */
                   | ';' { yyerror("Extra ';'. Ignored."); };

inheritance: F_INHERIT F_STRING ';'
		{
		    if (inherit_ob || inherit_file) {
			yyerror("Multiple inheritance not allowed.\n");
			free($2);
		    } else if (prog) {
			yyerror("inherit must come first.\n");
			free($2);
		    } else {
			inherit_ob = find_object2($2);
			if (inherit_ob == 0) {
			    inherit_file = $2;
			    return 0;
			}
			free($2);
			copy_variables(inherit_ob);
		    }
		}

number:  F_NUMBER | F_CONST0 | F_CONST1;

def: static F_IDENTIFIER '(' argument ')'
	{ num_arg = current_number_of_locals; }
    block
	{ struct lnode_def *p;
	  p = alloc_lnode_def(F_IDENTIFIER,$2,$7,
			      current_number_of_locals);
	  p->num_arg = num_arg;
	  if ($1)
	      p->is_static = 1;
	  $$ = (struct lnode *)p;
	  if (strcmp(p->name, "heart_beat") == 0) heart_beat = $$;
	  if (argument_name) free(argument_name);
	  argument_name = 0; free_all_local_names(); }
   | name '(' argument ')' block
	{ yyerror("Predefined function name.\n"); $$ = 0; }
   | static { static_variable_flag = $1; } type name_list ';'
            { $$ = 0; static_variable_flag = 0; }
   | inheritance { $$ = 0; } ;

static:  F_STATIC { $$ = 1; }
      |  /* empty */ { $$ = 0; }
      ;

req_semi: ';'
    	       | /* empty */ { yyerror("Missing ';'"); };

argument: /* empty */
        | local_list ;

type: F_STATUS | F_INT | F_STRING_DECL;

name_list: new_name
	 | new_name ',' name_list;

new_name: optional_star F_IDENTIFIER
	{ alloc_lnode_var_def(F_STATUS, $2, variable_count++); };

optional_star: '*' | /* empty */ ;

block: '{' local_declarations statements '}'
	{ $$ = (struct lnode *)alloc_lnode_block($3); };

local_declarations: /* empty */
		  | local_declarations type local_list req_semi ;

local_list: F_IDENTIFIER { add_local_name($1); }
	  | local_list ',' F_IDENTIFIER { add_local_name($3); }
	  | F_ARGUMENT { yyerror("Illegal to redeclare argument"); }
	  | F_LOCAL_NAME { yyerror("Illegal to redeclare local name"); };

statements: /* empty */ { $$ = 0; }
	  | statement statements
		{ if ($1 == 0)
		      $$ = $2;
		  else
		      $$ = (struct lnode *)alloc_lnode_2(F_CONS, $1, $2);
	        }
	  | error ';' { $$ = 0; };

statement: comma_expr ';' { $$ = $1; }
	 | cond | while | do | for | return ';' { $$ = $1; }
	 | block
	 | F_THROW comma_expr ';'
	      { $$ = (struct lnode *)alloc_lnode_1(F_THROW, $2); }
	 | F_BREAK req_semi { $$ = (struct lnode *)alloc_lnode_single(F_BREAK);
			    };
	 | F_CONTINUE req_semi { $$ = (struct lnode *)alloc_lnode_single(F_CONTINUE);
			    };

while: F_WHILE '(' comma_expr ')' statement
     { $$ = (struct lnode *)alloc_lnode_2(F_WHILE, $3, $5); };

do: F_DO statement F_WHILE '(' comma_expr ')' req_semi
  { $$ = (struct lnode *)alloc_lnode_2(F_DO, $2, $5); };

for: F_FOR '(' for_expr ';' for_expr ';' for_expr ')' statement
   { $$ = (struct lnode *)
           alloc_lnode_2(F_CONS,$3,
			 (struct lnode *)
			 alloc_lnode_2(F_CONS,
				       (struct lnode *)alloc_lnode_3(F_FOR,$5,
								     $7,$9),
				       (struct lnode *)0)); }

for_expr: /* EMPTY */
        { $$ = (struct lnode *)alloc_lnode_single(F_CONST1); }
        | comma_expr
        { $$=$1; }

comma_expr: expr0
          { $$=$1; };
          | expr0 ',' comma_expr
          { 
	  if($3->type==F_COMMA)
	    $$ = (struct lnode *)alloc_lnode_2(F_COMMA, $1, $3);
	  else
	    $$ = (struct lnode *)alloc_lnode_2(F_COMMA, $1,
			      (struct lnode *)alloc_lnode_2(F_COMMA, $3, 0));
	}

expr0: expr1
     | variable assign expr0
     { $$ = (struct lnode *)alloc_lnode_2($2, $1, $3); }
     | F_CATCH statement
	 { $$ = (struct lnode *)alloc_lnode_1(F_CATCH, $2); }
     | error assign expr0 { yyerror("Illegal LHS"); $$ = 0; }

assign: '=' { $$ = F_ASSIGN; }
      | F_AND_EQ { $$ = F_AND_EQ; }
      | F_OR_EQ { $$ = F_OR_EQ; }
      | F_XOR_EQ { $$ = F_XOR_EQ; }
      | F_LSH_EQ { $$ = F_LSH_EQ; }
      | F_RSH_EQ { $$ = F_RSH_EQ; }
      | F_ADD_EQ { $$ = F_ADD_EQ; }
      | F_SUB_EQ { $$ = F_SUB_EQ; }
      | F_MULT_EQ { $$ = F_MULT_EQ; }
      | F_MOD_EQ { $$ = F_MOD; }
      | F_DIV_EQ { $$ = F_DIV_EQ; };

return: F_RETURN { $$ = (struct lnode *)alloc_lnode_1(F_RETURN, 0); }
      | F_RETURN comma_expr { $$ = (struct lnode *)alloc_lnode_1(F_RETURN, $2); };

expr_list: /* empty */ { $$ = 0; }
	 | expr0
	{ $$ = (struct lnode *)alloc_lnode_2(F_CONS, $1, 0); }
         | expr0 ',' expr_list
	{ $$ = (struct lnode *)alloc_lnode_2(F_CONS, $1, $3); };

expr1: expr11
     | expr11 '?' expr1 ':' expr1
	{ $$ = (struct lnode *)alloc_lnode_3(F_COND, $1, $3, $5); }

expr11: expr2
      | expr11 F_LOR expr2
	{ $$ = (struct lnode *)alloc_lnode_2(F_LOR, $1, $3); };

expr2: expr211
     | expr211 F_LAND expr2
	{ $$ = (struct lnode *)alloc_lnode_2(F_LAND, $1, $3); };

expr211: expr212
       | expr211 '|' expr24
          { $$ = (struct lnode *)alloc_lnode_2(F_OR, $1, $3); };

expr212: expr213
       | expr212 '^' expr24
	  { $$ = (struct lnode *)alloc_lnode_2(F_XOR, $1, $3); };

expr213: expr22
       | expr213 '&' expr24
	  { $$ = (struct lnode *)alloc_lnode_2(F_AND, $1, $3); };

expr22: expr23
      | expr24 F_EQ expr24
	{ $$ = (struct lnode *)alloc_lnode_2(F_EQ, $1, $3); }
      | expr24 F_NE expr24
	{ $$ = (struct lnode *)alloc_lnode_2(F_NE, $1, $3); };

expr23: expr24
      | expr24 '>' expr24
	{ $$ = (struct lnode *)alloc_lnode_2(F_GT, $1, $3); }
      | expr24 F_GE expr24
	{ $$ = (struct lnode *)alloc_lnode_2(F_GE, $1, $3); }
      | expr24 '<' expr24
	{ $$ = (struct lnode *)alloc_lnode_2(F_LT, $1, $3); }
      | expr24 F_LE expr24
	{ $$ = (struct lnode *)alloc_lnode_2(F_LE, $1, $3); };

expr24: expr25
      | expr24 F_LSH expr25
	{ $$ = (struct lnode *)alloc_lnode_2(F_LSH, $1, $3); }
      | expr24 F_RSH expr25
	{ $$ = (struct lnode *)alloc_lnode_2(F_RSH, $1, $3); };

expr25: expr27
      | expr25 '+' expr27
	{ $$ = (struct lnode *)alloc_lnode_2(F_ADD, $1, $3); }
      | expr25 '-' expr27
	{ $$ = (struct lnode *)alloc_lnode_2(F_SUBTRACT, $1, $3); };

expr27: expr3
      | expr27 '*' expr3
	{ $$ = (struct lnode *)alloc_lnode_2(F_MULTIPLY, $1, $3); }
      | expr27 '%' expr3
	{ $$ = (struct lnode *)alloc_lnode_2(F_MOD, $1, $3); }
      | expr27 '/' expr3
	{ $$ = (struct lnode *)alloc_lnode_2(F_DIVIDE, $1, $3); };

expr3: expr31
     | F_INC variable
        { $$ = (struct lnode *)alloc_lnode_1(F_INC, $2); };
     | F_DEC variable
        { $$ = (struct lnode *)alloc_lnode_1(F_DEC, $2); };
     | F_NOT expr3
	{ $$ = (struct lnode *)alloc_lnode_1(F_NOT, $2); };
     | '~' expr3
	{ $$ = (struct lnode *)alloc_lnode_1(F_COMPL, $2); };
     | '-' expr3
	{ $$ = (struct lnode *)alloc_lnode_1(F_NEGATE, $2); };

expr31: expr4
      | variable F_INC
         { $$ = (struct lnode *)alloc_lnode_1(F_POST_INC, $1); };
      | variable F_DEC
         { $$ = (struct lnode *)alloc_lnode_1(F_POST_DEC, $1); };

expr4: function_call | variable | string | number
     | '(' comma_expr ')' { $$ = $2; }
     | '(' '{' expr_list '}' ')' { $$ = (struct lnode *)alloc_lnode_1(F_AGGREGATE, $3); };

variable: F_IDENTIFIER
	{ $$ = (struct lnode *)alloc_lnode_number(F_IDENTIFIER,
						    check_deklared($1));
						    free($1); }
	| F_ARGUMENT { $$ = (struct lnode *)alloc_lnode_single(F_ARGUMENT); }
        | F_LOCAL_NAME
	| expr4 '[' comma_expr ']'
	  { $$ = (struct lnode *)alloc_lnode_2(F_SUBSCRIPT, $1, $3); };

string: F_STRING
	{ $$ = (struct lnode *)alloc_lnode_name(F_STRING, $1); };

function_call: name '(' expr_list ')'
		{ $$ = (struct lnode *)alloc_lnode_1($1, $3); }
	     | function_name '(' expr_list ')'
		{ $$ = (struct lnode *)alloc_lnode_funcall(F_FUNCTION, $1, $3); }
	     | expr4 F_ARROW function_name '(' expr_list ')'
		{
		    struct lnode *p;
		    p = (struct lnode *)alloc_lnode_name(F_STRING, $3),
		    p = (struct lnode *)alloc_lnode_2(F_CONS, p, $5);
		    p = (struct lnode *)alloc_lnode_2(F_CONS, $1, p);
		    $$ = (struct lnode *)alloc_lnode_1(F_CALL_OTHER, p);
		};

function_name: F_IDENTIFIER
	     | F_COLON_COLON F_IDENTIFIER
		{
		    char *p = xalloc(strlen($2) + 3);
		    strcpy(p, "::"); strcat(p, $2); free($2);
		    $$ = p;
		};

name: F_THIS_PLAYER { $$ = F_THIS_PLAYER; }
    | F_THIS_OBJECT { $$ = F_THIS_OBJECT; }
    | F_SET_FALSE { $$ = F_SET_FALSE; }
    | F_WRITE { $$ = F_WRITE; }
    | F_ADD_VERB { $$ = F_ADD_VERB; }
    | F_ADD_XVERB { $$ = F_ADD_XVERB; }
    | F_ADD_SUBST { $$ = F_ADD_SUBST; }
    | F_ED { $$ = F_ED; }
    | F_ADD_ADJ { $$ = F_ADD_ADJ; }
    | F_SHUTDOWN { $$ = F_SHUTDOWN; }
    | F_CALL_OTHER { $$ = F_CALL_OTHER; }
    | F_CLONE_OBJECT { $$ = F_CLONE_OBJECT; }
    | F_ADD_ACTION { $$ = F_ADD_ACTION; }
    | F_MOVE_OBJECT { $$ = F_MOVE_OBJECT; }
    | F_LOG_FILE { $$ = F_LOG_FILE; }
    | F_SET_TRUE { $$ = F_SET_TRUE; }
    | F_SAVE_OBJECT { $$ = F_SAVE_OBJECT; }
    | F_ENVIRONMENT { $$ = F_ENVIRONMENT; }
    | F_PRESENT { $$ = F_PRESENT; }
    | F_CREATOR { $$ = F_CREATOR; }
    | F_SET_HEART_BEAT { $$ = F_SET_HEART_BEAT; }
    | F_COMMAND { $$ = F_COMMAND; }
    | F_FILE_NAME { $$ = F_FILE_NAME; }
    | F_QUERY_VERB { $$ = F_QUERY_VERB; }
    | F_THIS_VERB { $$ = F_QUERY_VERB; }
    | F_PARSE_COMMAND { $$ = F_PARSE_COMMAND; }
    | F_EXPLODE { $$ = F_EXPLODE; }
    | F_IMPLODE { $$ = F_IMPLODE; }
    | F_QUERY_IDLE { $$ = F_QUERY_IDLE; }
    | F_QUERY_LOAD_AVERAGE { $$ = F_QUERY_LOAD_AVERAGE; }
    | F_FILTER_OBJECTS { $$ = F_FILTER_OBJECTS; }
    | F_TAIL { $$ = F_TAIL; }
    | F_MKDIR { $$ = F_MKDIR; }
    | F_RMDIR { $$ = F_RMDIR; }
    | F_QUERY_SNOOP { $$ = F_QUERY_SNOOP; }
    | F_QUERY_HOST_NAME { $$ = F_QUERY_HOST_NAME; }
    | F_PREVIOUS_OBJECT { $$ = F_PREVIOUS_OBJECT; }
    | F_CRYPT { $$ = F_CRYPT; }
    | F_CAT { $$ = F_CAT; }
    | F_GREP { $$ = F_GREP; }
    | F_LS { $$ = F_LS; }
    | F_RM { $$ = F_RM; }
    | F_REALLOCATE { $$ = F_REALLOCATE; }
    | F_CONTENTS { $$ = F_CONTENTS; }
    | F_INDEX { $$ = F_INDEX; }
    | F_SEARCHA { $$ = F_SEARCHA; }
    | F_IN_EDITOR { $$ = F_IN_EDITOR; }
    | F_FIND_LIVING { $$ = F_FIND_LIVING; }
    | F_FIND_PLAYER { $$ = F_FIND_PLAYER; }
    | F_WRITE_FILE  { $$ = F_WRITE_FILE; }
    | F_FILE_SIZE   { $$ = F_FILE_SIZE; }
    | F_LOWER_CASE { $$ = F_LOWER_CASE; }
    | F_TELL_OBJECT { $$ = F_TELL_OBJECT; }
    | F_FIND_OBJECT { $$ = F_FIND_OBJECT; }
    | F_TRANSFER { $$ = F_TRANSFER; }
    | F_REGCOMP { $$ = F_REGCOMP; }
    | F_REGEXEC { $$ = F_REGEXEC; }
    | F_LOCALCMD { $$ = F_LOCALCMD; }
    | F_SWAP { $$ = F_SWAP; }
    | F_ADD_WORTH { $$ = F_ADD_WORTH; }
    | F_TIME { $$ = F_TIME; }
    | F_PEOPLE { $$ = F_PEOPLE; }
    | F_INPUT_TO { $$ = F_INPUT_TO; }
    | F_ENABLE_COMMANDS { $$ = F_ENABLE_COMMANDS; }
    | F_CAPITALIZE { $$ = F_CAPITALIZE; }
    | F_LIVING { $$ = F_LIVING; }
    | F_RANDOM { $$ = F_RANDOM; }
    | F_SNOOP { $$ = F_SNOOP; }
    | F_FIRST_INVENTORY { $$ = F_FIRST_INVENTORY; }
    | F_NEXT_INVENTORY { $$ = F_NEXT_INVENTORY; }
    | F_SET_LIGHT { $$ = F_SET_LIGHT; }
    | F_DESTRUCT { $$ = F_DESTRUCT; }
    | F_CREATE_WIZARD { $$ = F_CREATE_WIZARD; }
    | F_SAY { $$ = F_SAY; }
    | F_TELL_ROOM { $$ = F_TELL_ROOM; }
    | F_SHOUT { $$ = F_SHOUT; }
    | F_RESTORE_OBJECT { $$ = F_RESTORE_OBJECT; }
    | F_SSCANF { $$ = F_SSCANF; }
    | F_QUERY_IP_NUMBER { $$ = F_QUERY_IP_NUMBER; }
    | F_ALLOCATE { $$ = F_ALLOCATE; }
    | F_SIZEOF { $$ = F_SIZEOF; }
    | F_CTIME { $$ = F_CTIME; }
    | F_DISABLE_COMMANDS { $$ = F_DISABLE_COMMANDS; }
    | F_CALL_OUT { $$ = F_CALL_OUT; }
    | F_STRINGP { $$ = F_STRINGP; }
    | F_INTP { $$ = F_INTP; }
    | F_OBJECTP { $$ = F_OBJECTP; }
    | F_POINTERP { $$ = F_POINTERP; }
    | F_USERS { $$ = F_USERS; }
    | F_EXTRACT { $$ = F_EXTRACT; }
    | F_REMOVE_CALL_OUT { $$ = F_REMOVE_CALL_OUT; }
    | F_FIND_CALL_OUT { $$ = F_FIND_CALL_OUT; }
    | F_COMBINE_FREE_LIST { $$ = F_COMBINE_FREE_LIST; }
    | F_STRLEN { $$ = F_STRLEN; };
    | F_REMOTE_COMMAND { $$ = F_REMOTE_COMMAND; }
    | F_INTERACTIVE { $$ = F_INTERACTIVE; }
    | F_CALLER { $$ = F_CALLER; }
    | F_TYPEOF { $$ = F_TYPEOF; }
    | F_CP { $$ = F_CP; }
    | F_RENAME { $$ = F_RENAME; }
    | F_READ_FILE { $$ = F_READ_FILE; }
    | F_SET_BIT	   { $$ = F_SET_BIT; }
    | F_CLEAR_BIT  { $$ = F_CLEAR_BIT; }
    | F_TEST_BIT   { $$ = F_TEST_BIT; }
    | F_SET_LIVING_NAME { $$ = F_SET_LIVING_NAME; }
    | F_NOTIFY_FAIL { $$ = F_NOTIFY_FAIL; }

cond: F_IF '(' comma_expr ')' statement { $$ = (struct lnode *)alloc_lnode_3(F_IF, $3, $5, 0); }
    | F_IF '(' comma_expr ')' statement F_ELSE statement
	{ $$ = (struct lnode *)alloc_lnode_3(F_IF, $3, $5, $7); };
%%

void yyerror(str)
char *str;
{
    extern int num_parse_error;

    if (num_parse_error > 5)
	return;
    (void)fprintf(stderr, "%s: %s line %d\n", current_file, str,
		  current_line);
    fflush(stderr);
    smart_log(current_file, current_line, str);
    if (num_parse_error == 0)
	save_error(str, current_file, current_line);
    num_parse_error++;
}

int check_deklared(str)
    char *str;
{
    struct lnode_var_def *p;
    char buff[100];

    for (p = prog_status; p; p = p->next) {
	if (strcmp(p->name, str) == 0)
	    return p->num_var;
    }
    (void)sprintf(buff, "Variable %s not declared !", str);
    yyerror(buff);
    return 0;
}

void free_all_local_names()
{
    int i;

    for (i=0; i<current_number_of_locals; i++) {
	free(local_names[i]);
	local_names[i] = 0;
    }
    current_number_of_locals = 0;
}

void add_local_name(str)
    char *str;
{
    if (current_number_of_locals == MAX_LOCAL)
	yyerror("Too many local variables\n");
    else
	local_names[current_number_of_locals++] = str;
}

int num_val(p)
    struct lnode_number *p;
{
    switch(p->type) {
    case F_NUMBER:
        return p->number;
    case F_CONST0:
	return 0;
    case F_CONST1:
	return 1;
    default:
	fatal("Illegal type of number.\n");
    }
    /*NOTREACHED*/
}

/*
 * It could be possible to do '#include "/etc/passwd"' in the definition
 * of an object. The compilation would fail, but the .i file would remain
 * with interesting data.
 * Prevent this by checking the name of teh include file.
 */

int illegal_include_file(str)
    char *str;
{
    char *p;
    int i;

    if (str[0] == '/')
	return 1;
    if (strlen(str) < 3)
	return 0;
    for (p = str + 3, i = 0; *p; p++)
	if (p[0] == '/' &&  p[-1] == '.' && p[-2] == '.' && p[-3] == '/')
	    i += 1;
    if (i > 3)
	return 1;
    return 0;
}

static void copy_one_variable(p)
    struct lnode_var_def *p;
{
    if (p->next)
	copy_one_variable(p->next);
    static_variable_flag = p->is_static;
    alloc_lnode_var_def(F_STATUS, string_copy(p->name), variable_count++);
}

static void copy_variables(from)
    struct object *from;
{
    if (variable_count > 0)
	yyerror("Illegal to declare variables before the inherit statement");
    if (!from->status)
	return;
    copy_one_variable(from->status);
}