/*
 * Copyright 1993, 2000 Christopher Seiwald.
 *
 * This file is part of Jam - see jam.c for Copyright information.
 */

/*  This file is ALSO:
 *  Copyright 2001-2004 David Abrahams.
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 */

#include "jam.h"
#include "lists.h"
#include "parse.h"
#include "scan.h"
#include "object.h"
#include "modules.h"
#include "frames.h"
#include "function.h"

/*
 * parse.c - make and destroy parse trees as driven by the parser
 *
 * 09/07/00 (seiwald) - ref count on PARSE to avoid freeing when used,
 *      as per Matt Armstrong.
 * 09/11/00 (seiwald) - structure reworked to reflect that (*func)()
 *      returns a LIST *.
 */

static PARSE * yypsave;

static void parse_impl( FRAME * frame )
{

    /* Now parse each block of rules and execute it. Execute it outside of the
     * parser so that recursive calls to yyrun() work (no recursive yyparse's).
     */

    for ( ; ; )
    {
        PARSE * p;
        FUNCTION * func;

        /* Filled by yyparse() calling parse_save(). */
        yypsave = 0;

        /* If parse error or empty parse, outta here. */
        if ( yyparse() || !( p = yypsave ) )
            break;

        /* Run the parse tree. */
        func = function_compile( p );
        parse_free( p );
        list_free( function_run( func, frame, stack_global() ) );
        function_free( func );
    }

    yyfdone();
}


void parse_file( OBJECT * f, FRAME * frame )
{
    /* Suspend scan of current file and push this new file in the stream. */
    yyfparse( f );

    parse_impl( frame );
}


void parse_string( OBJECT * name, const char * * lines, FRAME * frame )
{
    yysparse( name, lines );
    parse_impl( frame );
}


void parse_save( PARSE * p )
{
    yypsave = p;
}


PARSE * parse_make(
    int      type,
    PARSE  * left,
    PARSE  * right,
    PARSE  * third,
    OBJECT * string,
    OBJECT * string1,
    int      num )
{
    PARSE * p = (PARSE *)BJAM_MALLOC( sizeof( PARSE ) );

    p->type = type;
    p->left = left;
    p->right = right;
    p->third = third;
    p->string = string;
    p->string1 = string1;
    p->num = num;
    p->refs = 1;
    p->rulename = 0;

    if ( left )
    {
        p->file = object_copy( left->file );
        p->line = left->line;
    }
    else
    {
        yyinput_last_read_token( &p->file, &p->line );
        p->file = object_copy( p->file );
    }

    return p;
}


void parse_refer( PARSE * p )
{
    ++p->refs;
}


void parse_free( PARSE * p )
{
    if ( --p->refs )
        return;

    if ( p->string )
        object_free( p->string );
    if ( p->string1 )
        object_free( p->string1 );
    if ( p->left )
        parse_free( p->left );
    if ( p->right )
        parse_free( p->right );
    if ( p->third )
        parse_free( p->third );
    if ( p->rulename )
        object_free( p->rulename );
    if ( p->file )
        object_free( p->file );

    BJAM_FREE( (char *)p );
}
