/*

=head1 NAME

pirout.c - Back-end for outputting PIR.

=cut

*/
#include "pirout.h"
#include "pirutil.h"
#include "pirvtable.h"
#include "pirlexer.h"
#include <stdio.h>
#include <stdlib.h>



typedef struct target {
    char *name;
    struct target *next;

} target;

/* Private declaration of emit_data.
 *
 *
 */
typedef struct emit_data {
    char *outputfile;
    FILE *file;
    int need_comma;
    target *targets;

} emit_data;


#define print_comma(D)  fprintf(data->file, ", ")





/*

=over 4

=item new_target()

=cut

*/
static target *
new_target(char *name) {
    target *t = (target *)malloc(sizeof(target));
    t->name = clone_string(name);
    t->next = NULL;
    return t;
}

/*

=item add_target()

=cut

=back

*/

static void
add_target(emit_data *data, target *t) {
    t->next = data->targets;
    data->targets = t;
}

/*

=head1 API

=cut

*/

static void
pir_name(struct emit_data *data, char *name) {
    if (data->need_comma) print_comma(data);
    fprintf(data->file, "%s", name);
    data->need_comma = 1;
}

static void
pir_sub(struct emit_data *data) {
    fprintf(data->file, "\n.sub ");
    data->need_comma = 0;
}

static void
pir_end(struct emit_data *data) {
    fprintf(data->file, ".end\n");
    data->need_comma = 0;
}

static void
pir_newline(struct emit_data *data) {
    fprintf(data->file, "\n");
}

static void
pir_param(struct emit_data *data) {
    fprintf(data->file, "  .param ");
}

static void
pir_type(struct emit_data *data, char *type) {
    fprintf(data->file, "%s ", type);
    data->need_comma = 0;
}

static void
pir_sub_flag(struct emit_data *data, int flag) {
    fprintf(data->file, "%s ", find_keyword(flag));
}

static void
pir_expr(struct emit_data *data, char *expr) {
    fprintf(data->file, "%s ", expr);
}

static void
pir_op(struct emit_data *data, char *op) {
    fprintf(data->file, "  %s ", op);
    data->need_comma = 0;
}


static void
pir_list_start(struct emit_data *data) {
    fprintf(data->file, "(");
    data->need_comma = 0;
}

static void
pir_list_end(struct emit_data *data) {
    fprintf(data->file, ")");
    data->need_comma = 0;
}

static void
pir_sub_flag_start(struct emit_data *data) {
    fprintf(data->file, "");
}


static void
pir_sub_flag_end(struct emit_data *data) {
    fprintf(data->file, "\n");
}

/*

Close the output file, free the emit_data structure.

*/
static void
pir_destroy(emit_data *data) {
    if (data->outputfile) fclose(data->file);
    free(data);
    data = NULL;
}

static void
pir_target(emit_data *data, char *target) {
    add_target(data, new_target(target));
}

static void
pir_begin_return(emit_data *data) {
    fprintf(data->file, " ");
}

static void
pir_init(emit_data *data) {
    if (data->outputfile) data->file = open_file(data->outputfile, "w");
    else data->file = stdout;
}

/* print the list of targets stored in emit_data. This is done recursively,
 * and from the end of the list to the front. This is because the items are
 * added at the front, and the order need to be restored. This also allows
 * for freeing any resources.
 */
static void
print_target(emit_data *data, target *t) {
    if (t->next) print_target(data, t->next);
    fprintf(data->file, "%s", t->name);

    /* name was a cloned string, free it again! */
    /*
    free(t->name);
    t->name = NULL;
    */

}

static void
pir_assign(emit_data *data) {
    target *t = data->targets;
    /* XXX does not work correctly yet.
    print_target(data, t);
    */
    fprintf(data->file, " = ");
}

static void
pir_assign_start(emit_data *data) {
    fprintf(data->file, "  ");
}

static void
pir_assign_end(emit_data *data) {
    fprintf(data->file, "\n");
}

static void
pir_comp_op(emit_data *data, char *op) {
    fprintf(data->file, " %s ", op);
}

static void
pir_bin_op(emit_data *data, char *op) {
    fprintf(data->file, " %s ", op);
}

/*

=over 4

=item init_pir_vtable()

Creates a vtable for the PIR emitting module, and
then this vtable is set into the parser_state struct.

=cut

*/
struct pirvtable *
init_pir_vtable(char *outputfile) {

    pirvtable *vtable = new_pirvtable();

    /* override the methods that are needed for PIR output */
    vtable->initialize     = pir_init;
    vtable->destroy        = pir_destroy;
    vtable->sub_start      = pir_sub;
    vtable->sub_end        = pir_end;
    vtable->name           = pir_name;
    vtable->stmts_start    = pir_newline;
    vtable->param_start    = pir_param;
    vtable->param_end      = pir_newline;
    vtable->type           = pir_type;
    vtable->sub_flag       = pir_sub_flag;
    vtable->op_start       = pir_op;
    vtable->op_end         = pir_newline;
    vtable->expression     = pir_expr;
    vtable->list_start     = pir_list_start;
    vtable->list_end       = pir_list_end;
    vtable->sub_flag_start = pir_sub_flag_start;
    vtable->sub_flag_end   = pir_sub_flag_end;
    vtable->assign         = pir_assign;
    vtable->assign_start   = pir_assign_start;
    vtable->assign_end     = pir_assign_end;
    vtable->target         = pir_target;

    vtable->binary_op      = pir_bin_op;
    vtable->comparison_op  = pir_comp_op;

    vtable->data = (emit_data *)malloc(sizeof(emit_data));
    if (vtable->data == NULL) {
        fprintf(stderr, "Failed to allocate memory for vtable data\n");
        exit(1);
    }

    vtable->data->outputfile = outputfile;
    vtable->data->targets = NULL;

    return vtable;
}





/*

=back

=cut

*/

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
