#include <stdio.h>
#include <assert.h>
#include "tokens.h" /* your token code definitions here! */
#include "token_bytecodes.h"

extern int yylineno;

YYSTYPE yylval;

struct {
  bytecode bc;
  int tok;
} table[] = {
#define xx(s) {LBC_##s,s}
xx(ID), 
xx(STRING),
xx(REAL),
xx(INTEGER),
xx(AND),
xx(ARRAY),
{LBC_BEGIN,yyBEGIN},
xx(BY),
xx(DIV),
xx(DO),
xx(ELSE),
xx(ELSIF),
xx(END),
xx(EXIT),
xx(FOR),
xx(IF),
xx(IS),
xx(LOOP),
xx(MOD),
xx(NOT),
xx(OF),
xx(OR),
xx(PROCEDURE),
xx(PROGRAM),
xx(READ),
xx(RECORD),
xx(RETURN),
xx(THEN),
xx(TO),
xx(TYPE),
xx(VAR),
xx(WHILE),
xx(WRITE),
xx(ASGN),
xx(LEQ),
xx(GEQ),
xx(NEQ),
xx(LBRANG),
xx(RBRANG),
{LBC_SEMICOLON,';'},
{LBC_COMMA,','},
{LBC_COLON,':'},
{LBC_LPAREN,'('},
{LBC_RPAREN,')'},
{LBC_LT,'<'},
{LBC_GT,'>'},
{LBC_EQ,'='},
{LBC_PLUS,'+'},
{LBC_MINUS,'-'},
{LBC_STAR,'*'},
{LBC_SLASH,'/'},
{LBC_LCURLY,'{'},
{LBC_RCURLY,'}'},
{LBC_LSQUARE,'['},
{LBC_RSQUARE,']'},
{LBC_DOT,'.'}
};

unsigned char tok_to_bc(int tok) {
  int i;
  for (i = 0; i < (sizeof(table)/sizeof(table[0])); i++)
    if (table[i].tok == tok)
      return table[i].bc;
  assert(0); /* no matching bytecode for token. */
}

void dump_code(unsigned char code) {
  assert(putchar(code) != EOF);
}

/* Dump counted string, one-byte length first. */
void dump_string(char *s) {
  int slen = strlen(s);
  assert(slen < 256);
  assert(putchar(slen) != EOF);
  while (*s) 
    assert(putchar(*s++) != EOF);
}

/* To avoid byte-order problems between machines,
   always dump low-order byte first. */
void dump_int(int i) {
  assert(putchar(i & 0xff) != EOF);
  assert(putchar((i & 0xff00) >> 8) != EOF);
  assert(putchar((i & 0xff0000) >> 16) != EOF);
  assert(putchar((i & 0xff000000) >> 24) != EOF);
}


void lexout() {
  int tok;
  int lastlineno = 0;
  while (tok = yylex()) {
    unsigned char bc = tok_to_bc(tok);
    if (yylineno > lastlineno) {
      dump_code(LBC_LINE);
      dump_int(yylineno);
      lastlineno = yylineno;
    }
    dump_code(bc);
    switch (tok) {
    case ID:
    case REAL:
    case STRING:
      dump_string(yylval.svalue);
      break;
    case INTEGER:
      dump_int(yylval.ivalue);
    }
  }
}      
      
