#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef USE_NLLIBC
#include <nllibc.h>
#endif

#include "config.h"
#include "lib.h"
#include "type.h"
#include "syntax.h"
#include "asm.h"
#include "asm_syntax.h"
#include "asm_symbol.h"
#include "asm_format.h"
#include "asm_code.h"
#include "asm_queue.h"

static int asm_syntax_symbol(FILE *out, symbol_t symbol, symbol_t function)
{
  asm_symbol_value_set(out, symbol, function);
  if (symbol->flags & SYMBOL_FLAG_LOCATED)
    asm_symbol_value_get(out, symbol, function);
  return 0;
}

static int asm_syntax_ifgoto(FILE *out, syntax_ifgoto_t ifgoto, symbol_t function)
{
  asm_symbol_value_set(out, ifgoto->cond, function);
  asm_symbol_value_get(out, ifgoto->cond, function);
  asm_symbol_branch_nzero(out, ifgoto->label->obj.label.name);
  return 0;
}

static int asm_syntax_ifngoto(FILE *out, syntax_ifngoto_t ifngoto, symbol_t function)
{
  asm_symbol_value_set(out, ifngoto->cond, function);
  asm_symbol_value_get(out, ifngoto->cond, function);
  asm_symbol_branch_zero(out, ifngoto->label->obj.label.name);
  return 0;
}

static int asm_syntax_goto(FILE *out, syntax_goto_t _goto, symbol_t function)
{
  asm_queue_code_branch(out, _goto->label->obj.label.name);
  return 0;
}

static int asm_syntax_label(FILE *out, syntax_label_t label, symbol_t function)
{
  asm_queue_format_label(out, label->name);
  return 0;
}

static int asm_syntax_return(FILE *out, syntax_return_t _return, symbol_t function)
{
  if (_return->value != NULL) {
    asm_symbol_value_set(out, _return->value, function);
    asm_symbol_value_get(out, _return->value, function);
  }
  asm_queue_code_branch(out, _return->function->obj.function.retlabel->obj.label.name);
  return 0;
}

int asm_syntax(FILE *out, syntax_t syntax, symbol_t function)
{
  saveline(syntax->line);

  switch (syntax->type) {
  case C_TYPE_BLOCK:
    asm_syntax_list(out, syntax->obj.block.syntaxes, function);
    break;

  case C_TYPE_SYMBOL:
    asm_syntax_symbol(out, syntax->obj.symbol, function);
    break;

  case C_TYPE_IFGOTO:
    asm_syntax_ifgoto(out, &syntax->obj.ifgoto, function);
    break;

  case C_TYPE_IFNGOTO:
    asm_syntax_ifngoto(out, &syntax->obj.ifngoto, function);
    break;

  case C_TYPE_GOTO:
    asm_syntax_goto(out, &syntax->obj._goto, function);
    break;

  case C_TYPE_LABEL:
    asm_syntax_label(out, &syntax->obj.label, function);
    break;

  case C_TYPE_RETURN:
    asm_syntax_return(out, &syntax->obj._return, function);
    break;

  case C_TYPE_NOP:
    break;

  default:
    ERREXIT(1);
  }

  return 0;
}
