/* hi emacs, this is a part of -*- C -*- source */
/* $Id: bac_lexical.l,v 1.20 2012/01/29 03:56:41 oohara Exp $ */
/* process this file with flex -Pbac_ */

/* definitions */
%option yylineno
%option noyywrap

%option noinput
%option nounput
%option noyyget_leng
%option noyyget_text
%option noyyget_lineno
%option noyyset_lineno
%option noyyget_in
%option noyyset_in
%option noyyget_out
%option noyyset_out
%option noyyget_debug
%option noyyset_debug

%x value_string
%x value_long_int

%{
/* FILE */
#include <stdio.h>
/* strtol, malloc */
#include <stdlib.h>
/* strlen, strncpy */
#include <string.h>
/* errno */
#include <errno.h>

/* this is generated by bison -d */
#include "bac_parser.h"

#include "bac_lexical.h"

static char *silly_tail = NULL;

%}

/* rules */
/* this comment must be before %% */
%%
[eE]ntry-[vV]ersion {
  BEGIN(value_long_int);
  bac_lval.val_int = BEGIN_ENTRY_VERSION;
  return BEGIN_ENTRY_VERSION;}

[cC]omment {
  BEGIN(value_string);
  bac_lval.val_int = BEGIN_COMMENT;
  return BEGIN_COMMENT;}

[sS]tage-[dD]ata-[vV]ersion {
  BEGIN(value_long_int);
  bac_lval.val_int = BEGIN_STAGE_DATA_VERSION;
  return BEGIN_STAGE_DATA_VERSION;}

[wW]hen {
  BEGIN(value_long_int);
  bac_lval.val_int = BEGIN_WHEN;
  return BEGIN_WHEN;}

[uU]id {
  BEGIN(value_long_int);
  bac_lval.val_int = BEGIN_UID;
  return BEGIN_UID;}

[uU]ser-[nN]ame {
  BEGIN(value_string);
  bac_lval.val_int = BEGIN_USER_NAME;
  return BEGIN_USER_NAME;}

[sS]core-[sS]ort {
  BEGIN(value_long_int);
  bac_lval.val_int = BEGIN_SCORE_SORT;
  return BEGIN_SCORE_SORT;}

[sS]core-[tT]otal {
  BEGIN(value_long_int);
  bac_lval.val_int = BEGIN_SCORE_TOTAL;
  return BEGIN_SCORE_TOTAL;}

[nN]umber-[sS]tage {
  BEGIN(value_long_int);
  bac_lval.val_int = BEGIN_NUMBER_STAGE;
  return BEGIN_NUMBER_STAGE;}

[sS]core-[sS]tage {
  BEGIN(value_long_int);
  bac_lval.val_int = BEGIN_SCORE_STAGE;
  return BEGIN_SCORE_STAGE;}

<value_long_int>[+\-]?[0-9]+ {
  /* you can write 7 as 007 for example, but it is always decimal,
   * not octal */
  /* to detect overflow */
  errno = 0;
  bac_lval.val_long_int = strtol(yytext, &silly_tail, 10);
  if (silly_tail[0] != '\0')
  {
    fprintf(stderr, "bac_lexical.l: strange integer\n");
    return LEXICAL_ERROR;
  }
  if (errno != 0)
  {
    fprintf(stderr, "bac_lexical.l: integer overflow\n");
    return LEXICAL_ERROR;
  }
  return LONG_INT;}

<value_string>[[:print:]]+ {
  /* note that [:print:] does not match \t or \n */
  /* +1 is for the trailing \0 */
  bac_lval.val_string = (char *) malloc(sizeof (char) * (strlen(yytext) + 1));
  if (bac_lval.val_string == NULL)
  {
    fprintf(stderr, "bac_lexical.l: malloc(string) failed\n");
    return LEXICAL_ERROR;
  }
  strncpy(bac_lval.val_string, yytext, strlen(yytext));
  bac_lval.val_string[strlen(yytext)] = '\0';
  return STRING;}

<value_long_int>\t |
<value_string>\t {
  bac_lval.val_int = '\t';
  return TAB;}

<value_long_int>\n |
<value_string>\n {
  BEGIN(INITIAL);
  bac_lval.val_int = '\n';
  return NEWLINE;}

\n {
  /* empty line*/
  return END_OF_ENTRY;}

\t {
  /* no field name */
  return LEXICAL_ERROR;}

<*>[^\n\t]+ {
  /* catch-all */
  return LEXICAL_ERROR;}

%%
/* user code */
void
bac_read_from_file(FILE *file)
{
  /* yyrestart */
  bac_restart(file);
}

/* the return value is void because yyrestart() returns void
 * --- you can't check if it succeeded
 */
void
bac_read_from_string(const char *string)
{
  /* yy_scan_string */
  bac__scan_string(string);
}

void
bac_close_string(void)
{
  /* yy_delete_buffer */
  bac__delete_buffer(YY_CURRENT_BUFFER);
}
