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

/* ----------------------------------------------------- */

void displayGlobals (void)
{
  printf ("GLOBALS\n");
  struct nameEntry* p = GLOBALS;
  while (p != NULL)
  {
    printf ("%15s\n",p->data);
    p = p->next;
  }
  printf ("\n");
}

void displayExterns (void)
{
  printf ("EXTERNS\n");
  struct nameEntry* p = EXTERNS;
  while (p != NULL)
  {
    printf ("%15s\n",p->data);
    p = p->next;
  }
  printf ("\n");
}

void displayLabels (void)
{
  printf ("LABELS\n");
  struct labelEntry* p = LABELS;
  while (p != NULL)
  {
    printf ("%15s %15d\n",p->data.name,p->data.location);
    p = p->next;
  }
  printf ("\n");
}

long long labelAddress (char* ident)
{
  struct labelEntry* p = LABELS;
  while (p != NULL)
  {
    if (strcmp(p->data.name,ident) == 0)
      return p->data.location;
    else
      p = p->next;
  }
  return -1;
}

/* ----------------------------------------------------- */

void _LABEL (char* ident)
{
  if (isLabel(ident))
    printf ("duplicate label identifier: %s!\n");
  else
  {
    struct labelEntry* p =
      malloc (sizeof(struct labelEntry));
    p->data.name = ident;
    p->data.location = INSTRUCTION_COUNTER;
    p->next = LABELS;
    LABELS = p;
  }
}

void _EXTERN (char* ident)
{
  if (isExtern(ident))
    printf ("duplicate extern identifier: %s!\n");
  else
  {
    struct nameEntry* p =
      malloc (sizeof(struct nameEntry));
    p->data = ident;
    p->next = EXTERNS;
    EXTERNS = p;
  }
}

void _GLOBAL (char* ident)
{
  if (isGlobal(ident))
    printf ("duplicate extern identifier: %s!\n");
  else
  {
    struct nameEntry* p =
      malloc (sizeof(struct nameEntry));
    p->data = ident;
    p->next = GLOBALS;
    GLOBALS = p;
  }
}

/* ----------------------------------------------------- */

int isLabel (char* ident)
{
  struct labelEntry* p = LABELS;
  int found = 0;
  while ((p != NULL) & !found)
    if (strcmp(p->data.name,ident) == 0)
      return 1;
    else
      p = p->next;
  return 0;
}

int isExtern (char* ident)
{
  struct nameEntry* p = EXTERNS;
  int found = 0;
  while ((p != NULL) & !found)
    if (strcmp(p->data,ident) == 0)
      return 1;
    else p = p->next;
  return 0;
}

int isGlobal (char* ident)
{
  struct nameEntry* p = GLOBALS;
  int found = 0;
  while ((p != NULL) & !found)
    if (strcmp(p->data,ident) == 0)
      return 1;
    else
      p = p->next;
  return 0;
}

/* ----------------------------------------------------- */

void setPC (long long instruction)
{ PC = instruction; }

void setEQ (void)
{ EQ = 1; GT = 0; LT = 0; }

void setGT (void)
{ EQ = 0; GT = 1; LT = 0; }

void setLT (void)
{ EQ = 0; GT = 0; LT = 1; }

/* ----------------------------------------------------- */

void displayCode (void)
{
  printf ("INSTRUCTIONS\n\n");
  printf ("%15s %15d\n\n","COUNTER:",INSTRUCTION_COUNTER);
  for (long long index=0;index<INSTRUCTION_COUNTER;index++)
  {
    struct codeData instruction = INSTRUCTIONS[index];
    printf ("%15s %15s %15s %15s\n",
      instruction.opcode,
      instruction.oper1,
      instruction.oper2,
      instruction.oper3);
  }
  printf ("\n");
}

void addInstruction (char* op, char* oper1,
                     char* oper2, char* oper3)
{
  struct codeData instruction = {op,oper1,oper2,oper3};
  INSTRUCTIONS[INSTRUCTION_COUNTER++] = instruction;
}

struct codeData fetchInstruction (void)
{ return INSTRUCTIONS[PC++]; }

/* ----------------------------------------------------- */
