%{
/*
 * Simple example lex input file
 * Original provided by
 * Shawn Ostermann -- Mon Sep 24, 2001
 *
 * Modified by Kyle Wheeler
 */

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <math.h>
#include <errno.h>
#include <ctype.h> /* for isdigit() */
#include "number.h"
#include "calculator.h"
#include "conversion.h"
#ifdef HAVE_CONFIG_H
#include "parser.h"
#else
#include "y.tab.h"
#endif
#include "string_manip.h"
#include "explain.h"
#include "isfunc.h" /* for isfunc() */
#include "isconst.h" /* for isconst() */
#ifdef MEMWATCH
#include "memwatch.h"
#endif

    extern short scanerror;

#ifndef HUGE_VALF
# define HUGE_VALF HUGE_VAL
#endif
#ifndef UINT32_MAX
# define UINT32_MAX 4294967295U
#endif

#ifdef REENTRANT_PARSER
    /* Re-entrant */
#define YY_DECL int yylex (YYSTYPE *yylval)
#define YYLVALAC yylval
#else
#define YYLVALAC (&yylval)
#endif

int line_is_a_command = 0;
int column = 0;

#define POS_CHAR() do { column ++; } while(0)
#define POS_STR() do { column += yyleng; } while (0)

/* Everything up to the funny characters on the next line */
/* goes directly into the lex.yy.c file */
%}

%pointer
%option nounput noinput
/* shorthand definitions for later */
DIGIT		[0123456789]
NDIGIT		[123456789]
LETTER		[a-zA-Z]
WHITESPACE	[ \t]
ACCEPTABLE	[_:0-9]
UNITCHRS	[-_a-zA-Z0-9^./µÅ]
SPACE		[ ]

/* The rest of this after the '%%' is lex rules */
%%

{WHITESPACE}+	{ POS_STR(); }

"\n"            { return(EOLN); }

%{ /* These are commands */
%}

\\b(in(ary)?)?		{ line_is_a_command = 1; POS_STR(); return(BIN_CMD); }
\\d(ec(imal)?)?		{ line_is_a_command = 1; POS_STR(); return(DEC_CMD); }
\\dsep{WHITESPACE}*.     {
	int i = 5;
	while (isspace(yytext[i])) i++;
	if (yytext[i] == 0) i--;
	YYLVALAC->character = yytext[i];
	line_is_a_command = 1;
	POS_STR();
	return(DSEP_CMD);
}
\\e(ng(ineering)?)?{WHITESPACE}*{DIGIT}* {
	int i = 2;
    while (! isdigit((int)(yytext[i]))) ++i;
    if (yytext[i] != 0) YYLVALAC->integer = strtoul(yytext+i, NULL, 0);
    else YYLVALAC->integer = -1;
	line_is_a_command = 1;
	POS_STR();
    return(ENG_CMD);
}
\\cons(ervative)?       { line_is_a_command = 1; POS_STR(); return(GUARD_CMD); }
\\h(ex(adecimal)?)?     { line_is_a_command = 1; POS_STR(); return(HEX_CMD); }
\\help           { line_is_a_command = 1; POS_STR(); return(PRINT_HELP_CMD); }
\\hlimit{WHITESPACE}*{DIGIT}+ {
	int i = 7;
	while (isspace(yytext[i])) ++i;
	if (yytext[i] != 0) YYLVALAC->integer = strtoul(yytext+i, NULL, 0);
	else YYLVALAC->integer = 0;
	line_is_a_command = 1;
	POS_STR();
	return(HLIMIT_CMD);
}
\\ints?             { line_is_a_command = 1; POS_STR(); return(INT_CMD); }
\\del(im(iters)?)?	{ line_is_a_command = 1; POS_STR(); return(DELIM_CMD); }
\\x                 { line_is_a_command = 1; POS_STR(); return(HEX_CMD); }
\\li(st(vars)?)?    { line_is_a_command = 1; POS_STR(); return(LISTVAR_CMD); }
\\o(ct(al)?)?       { line_is_a_command = 1; POS_STR(); return(OCT_CMD); }
\\open{WHITESPACE}+.*   {
	int i = 5;
    char *returnme;
    Dprintf("open\n");
    while (isspace(yytext[i])) ++i;
    returnme = strdup(yytext + i);
	/* now trim trailing whitespace */
	i = (int)strlen(returnme) - 1;
    while (isspace(returnme[i])) {
        returnme[i] = 0;
        i--;
    }
    YYLVALAC->variable = returnme;
    Dprintf("filename: %s\n",returnme);
    line_is_a_command = 1;
	POS_STR();
	return(OPEN_CMD);
}
\\p{WHITESPACE}*(({DIGIT}+)|(-1)) {
	int i = 2;
	while (isspace(yytext[i])) ++i;
	YYLVALAC->integer = strtol(yytext+i, NULL, 0);
	line_is_a_command = 1;
	POS_STR();
	return(PRECISION_CMD);
}
\\pre(fix(es)?)?        { line_is_a_command = 1; POS_STR(); return(PREFIX_CMD); }
\\pref(s|erences)?		{ line_is_a_command = 1; POS_STR(); return(DISPLAY_PREFS_CMD); }
\\r(ad(ians)?)?         { line_is_a_command = 1; POS_STR(); return(RADIAN_CMD); }
\\rou(nd(ing)?)?{WHITESPACE}+no(ne)? {
	YYLVALAC->integer = NO_ROUNDING_INDICATION;
	line_is_a_command = 1;
	POS_STR();
	return(ROUNDING_INDICATION_CMD);
}
\\rou(nd(ing)?)?{WHITESPACE}+simple {
	YYLVALAC->integer = SIMPLE_ROUNDING_INDICATION;
	line_is_a_command = 1;
	POS_STR();
	return(ROUNDING_INDICATION_CMD);
}
\\rou(nd(ing)?)?{WHITESPACE}+sig_fig {
	YYLVALAC->integer = SIG_FIG_ROUNDING_INDICATION;
	line_is_a_command = 1;
	POS_STR();
	return(ROUNDING_INDICATION_CMD);
}
\\rou(nd(ing)?)?        {
	YYLVALAC->integer = -1;
	line_is_a_command = 1;
	POS_STR();
	return(ROUNDING_INDICATION_CMD);
}
\\re(member(_errors)?)?		{ line_is_a_command = 1; POS_STR(); return(REMEMBER_CMD); }
\\bits{WHITESPACE}*{DIGIT}+ {
	int i = 5;
	while (isspace(yytext[i])) ++i;
	YYLVALAC->integer = strtoul(yytext+i, NULL, 0);
	line_is_a_command = 1;
	POS_STR();
	return(BITS_CMD);
}
\\save{WHITESPACE}.*		{
	int i = 5;
    char *returnme;
	while (isspace(yytext[i])) ++i;
    returnme = strdup(yytext + i);
	/* now trim trailing whitespace */
	i = (int)strlen(returnme) - 1;
    while (isspace(returnme[i])) {
        returnme[i] = 0;
        i--;
    }
    YYLVALAC->variable = returnme;
	line_is_a_command = 1;
	POS_STR();
    return(SAVE_CMD);
}
\\tsep{WHITESPACE}*.       {
	int i = 5;
	while (isspace(yytext[i])) ++i;
	if (yytext[i] == 0) i--;
	YYLVALAC->character = yytext[i];
	line_is_a_command = 1;
	POS_STR();
	return(TSEP_CMD);
}
\?                      { line_is_a_command = 1; POS_STR(); return(PRINT_HELP_CMD); }
[Hh][Ee][Ll][Pp]        { line_is_a_command = 1; POS_STR(); return(PRINT_HELP_CMD); }
\\c(onv(ert)?)?{WHITESPACE}+{UNITCHRS}+({WHITESPACE}+to)?{WHITESPACE}+{UNITCHRS}+ {
    char *unitone;
	int i = 2;
	/* find the first space */
	while (! isspace(yytext[i])) ++i;
	/* find the end of that space */
	while (isspace(yytext[i])) ++i;
    unitone = yytext + i;
	/* skip the unit */
	while (! isspace(yytext[i])) ++i;
	yytext[i++] = 0;
	/* onward to the word "to" */
	while (isspace(yytext[i])) ++i;
	if (yytext[i] == 't' && yytext[i+1] == 'o' && isspace(yytext[i+2])) {
		i += 3; /* to */
	}
	/* seek the next unit */
	while (isspace(yytext[i])) ++i;
    YYLVALAC->conver.u1 = strdup(unitone);
    YYLVALAC->conver.u2 = strdup(yytext+i);
    line_is_a_command = 1;
	POS_STR();
	return(CONVERT_CMD);
}
\\base{WHITESPACE}*{DIGIT}+  {
	int i = 5;
	while (isspace(yytext[i])) ++i;
	YYLVALAC->integer = strtoul(yytext + i, NULL, 0);
	line_is_a_command = 1;
	POS_STR();
	return(BASE_CMD);
}
\\verbose					{ line_is_a_command = 1; POS_STR(); return(VERBOSE_CMD); }
\\explain{WHITESPACE}*.*	{
	int i = 9, j;
	while (isspace(yytext[i])) ++i;
	j = strlen(yytext+i);
	while (isspace(yytext[j])) {
		yytext[j] = 0;
		j--;
	}
	explain(yytext+i);
	line_is_a_command = 1;
	POS_STR();
}
\\store			{ line_is_a_command = 1; POS_STR(); return(STORE_CMD); }
\\cmod			{ line_is_a_command = 1; POS_STR(); return(CMOD_CMD); }

%{ /* These are comments */
%}
\/\*.*\*\/              { POS_STR(); }
\/\/.*                  { POS_STR(); }
\#.*                    { POS_STR(); }


%{ /* These are the constants (except random) */
    %}
(e)			{
	num_init_set_str(YYLVALAC->number,W_E,0);
	POS_STR();
	return(NUMBER);
}
([pP][iI])|(\317\200)	{
	num_init(YYLVALAC->number);
	num_const_pi(YYLVALAC->number);
	POS_STR();
	return(NUMBER);
}
random			{
	num_init(YYLVALAC->number);
	while (num_random(YYLVALAC->number) != 0) ;
	num_mul_ui(YYLVALAC->number,YYLVALAC->number,UINT32_MAX);
	POS_STR();
	return(NUMBER);
}
irandom		{
	num_init(YYLVALAC->number);
	while (num_random(YYLVALAC->number) != 0) ;
	num_mul_ui(YYLVALAC->number,YYLVALAC->number,UINT32_MAX);
	num_rint(YYLVALAC->number,YYLVALAC->number);
	POS_STR();
	return(NUMBER);
}
N[aA]	{
	num_init_set_str(YYLVALAC->number,W_AVOGADROS_CONSTANT,0);
	POS_STR();
	return(NUMBER);
}
k	{
	num_init_set_str(YYLVALAC->number,W_BOLTZMANN_CONSTANT,0);
	POS_STR();
	return(NUMBER);
}
Cc	{ num_init_set_str(YYLVALAC->number,W_COULOMB_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
ec	{ num_init_set_str(YYLVALAC->number,W_ELEMENTARY_CHARGE,0);
	POS_STR();
                  return(NUMBER); }
R	{ num_init_set_str(YYLVALAC->number,W_MOLAR_GAS_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
G	{ num_init_set_str(YYLVALAC->number,W_GRAVITATIONAL_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
g	{ num_init_set_str(YYLVALAC->number,W_GRAVITATIONAL_ACCELLERATION,0);
	POS_STR();
                  return(NUMBER); }
Me	{ num_init_set_str(YYLVALAC->number,W_ELECTRON_MASS,0);
	POS_STR();
                  return(NUMBER); }
Mp	{ num_init_set_str(YYLVALAC->number,W_PROTON_MASS,0);
	POS_STR();
                  return(NUMBER); }
Mn	{ num_init_set_str(YYLVALAC->number,W_NEUTRON_MASS,0);
	POS_STR();
                  return(NUMBER); }
Md	{ num_init_set_str(YYLVALAC->number,W_DEUTERON_MASS,0);
	POS_STR();
                  return(NUMBER); }
(u)|(amu) { num_init_set_str(YYLVALAC->number,W_ATOMIC_MASS,0);
	POS_STR();
                  return(NUMBER); }
c	{ num_init_set_str(YYLVALAC->number,W_SPEED_OF_LIGHT,0);
	POS_STR();
                  return(NUMBER); }
h	{ num_init_set_str(YYLVALAC->number,W_PLANCK_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
(\302\265|\316\274|mu)(0|zero|ZERO) {
                  Number temp;
                  num_init(YYLVALAC->number);
                  num_init(temp);
                  num_set_d(temp,1e-7);
                  num_const_pi(YYLVALAC->number);
                  num_mul_ui(YYLVALAC->number,YYLVALAC->number,4);
                  num_mul(YYLVALAC->number,YYLVALAC->number,temp);
                  num_free(temp);
		  POS_STR();
                  return(NUMBER); }
(epsilon|EPSILON|\316\265)(0|zero|ZERO) { num_init_set_str(YYLVALAC->number,W_PERMITTIVITY_OF_FREE_SPACE,0);
	POS_STR();
                  return(NUMBER); }
(\302\265|\316\274|mu)B	{ num_init_set_str(YYLVALAC->number,W_BOHR_MAGNETON,0);
	POS_STR();
                  return(NUMBER); }
(\302\265|\316\274|mu)N	{ num_init_set_str(YYLVALAC->number,W_NUCLEAR_MAGNETON,0);
	POS_STR();
                  return(NUMBER); }
b	{ num_init_set_str(YYLVALAC->number,W_WIEN_DISPLACEMENT,0);
	POS_STR();
                  return(NUMBER); }
a0	{ num_init_set_str(YYLVALAC->number,W_BOHR_RADIUS,0);
	POS_STR();
                  return(NUMBER); }
F	{ num_init_set_str(YYLVALAC->number,W_FARADAY_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
(Vm)|(NAk) { num_init_set_str(YYLVALAC->number,W_MOLAR_VOLUME_OF_IDEAL_GAS,0);
	POS_STR();
                  return(NUMBER); }
eV	{ num_init_set_str(YYLVALAC->number,W_ELECTRON_VOLT,0);
	POS_STR();
                  return(NUMBER); }
sigma|\317\203 { num_init_set_str(YYLVALAC->number,W_STEFAN_BOLTZMANN,0);
	POS_STR();
                  return(NUMBER); }
alpha|\316\261 { num_init_set_str(YYLVALAC->number,W_FINE_STRUCTURE,0);
	POS_STR();
                  return(NUMBER); }
gamma|GAMMA|\316\263 { num_init(YYLVALAC->number); num_const_euler(YYLVALAC->number);
	POS_STR();
                  return(NUMBER); }
re	{ num_init_set_str(YYLVALAC->number,W_ELECTRON_RADIUS,0);
	POS_STR();
                  return(NUMBER); }
Kj	{ num_init_set_str(YYLVALAC->number,W_JOSEPHSON_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
Rk	{ num_init_set_str(YYLVALAC->number,W_VON_KLITZING_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
R(inf|\342\210\236)	{ num_init_set_str(YYLVALAC->number,W_RYDBERG_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
Eh	{ num_init_set_str(YYLVALAC->number,W_HARTREE_ENERGY,0);
	POS_STR();
                  return(NUMBER); }
Gf	{ num_init_set_str(YYLVALAC->number,W_FERMI_COUPLING_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
M(\302\265|\316\274|mu)	{ num_init_set_str(YYLVALAC->number,W_MUON_MASS,0);
	POS_STR();
                  return(NUMBER); }
M(t|tau|\317\204)	{ num_init_set_str(YYLVALAC->number,W_TAU_MASS,0);
	POS_STR();
                  return(NUMBER); }
Mh	{ num_init_set_str(YYLVALAC->number,W_HELION_MASS,0);
	POS_STR();
                  return(NUMBER); }
M(alpha|\316\261)	{ num_init_set_str(YYLVALAC->number,W_ALPHA_PARTICLE_MASS,0);
	POS_STR();
                  return(NUMBER); }
n(0|zero|ZERO)	{ num_init_set_str(YYLVALAC->number,W_LOSCHMIDT_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
c1	{ num_init_set_str(YYLVALAC->number,W_FIRST_RADIATION_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
c2	{ num_init_set_str(YYLVALAC->number,W_SECOND_RADIATION_CONSTANT,0);
	POS_STR();
                  return(NUMBER); }
G(0|zero|ZERO)	{ num_init_set_str(YYLVALAC->number,W_CONDUCTANCE_QUANTUM,0);
	POS_STR();
                  return(NUMBER); }
Z(0|zero|ZERO)	{ num_init_set_str(YYLVALAC->number,W_IMPEDANCE_OF_VACUUM,0);
	POS_STR();
                  return(NUMBER); }
(Phi|\316\246)(0|zero|ZERO)	{ num_init_set_str(YYLVALAC->number,W_MAGNETIC_FLUX_QUANTUM,0);
	POS_STR();
                  return(NUMBER); }
\302\274	{ num_init_set_d(YYLVALAC->number,0.25);
	POS_STR();
                  return(NUMBER); }
\302\275	{ num_init_set_d(YYLVALAC->number,0.5);
	POS_STR();
                  return(NUMBER); }
\302\276	{ num_init_set_d(YYLVALAC->number,0.75);
	POS_STR();
                  return(NUMBER); }
K	{ num_init(YYLVALAC->number);
	num_const_catalan(YYLVALAC->number);
	POS_STR();
	return(NUMBER); }

%{ /* These are the grouping symbols */
    %}
[(] { POS_STR(); return(OPEN_PARENTHESES); }
[)] { POS_STR(); return(CLOSE_PARENTHESES); }
[{] { POS_STR(); return(OPEN_BRACE); }
[}] { POS_STR(); return(CLOSE_BRACE); }
\[  { POS_STR(); return(OPEN_BRACKET); }
\]  { POS_STR(); return(CLOSE_BRACKET); }

%{ /* These are the binary operations */
    %}
not					{ POS_STR(); return(WNOT); }
\302\254			{ POS_CHAR(); return(WNOT); }
[!]					{ POS_CHAR(); return(WBANG); }
[*][*]				{ POS_STR(); return(WSQR); }
\302\262			{ POS_CHAR(); return(WSQR); }
[+]					{ POS_CHAR(); return(WPLUS); }
[*]|\303\227		{ POS_CHAR(); return(WMULT); }
[/]|\303\267		{ POS_CHAR(); return(WDIV); }
[%]					{ POS_CHAR(); return(WMOD); }
[=]					{ POS_CHAR(); return(EQUALS_SIGN); }
(\^)				{ POS_CHAR(); return(WPOW); }
\|                  { POS_CHAR(); return(WBOR); }
\&                  { POS_CHAR(); return(WBAND); }
\~                  { POS_CHAR(); return(WBNOT); }
(\|\|)|(or)			{ POS_STR(); return(WOR); }
\342\210\250		{ POS_CHAR(); return(WOR); }
(\&\&)|(and)		{ POS_STR(); return(WAND); }
\342\210\247		{ POS_CHAR(); return(WAND); }
(\=\=)|(equals)|(eq)	{ POS_STR(); return(WEQUAL); }
(\!\=)|(ne)			{ POS_STR(); return(WNEQUAL); }
\342\211\240		{ POS_CHAR(); return(WNEQUAL); }
xor					{ POS_STR(); return(WBXOR); }
\>					{ POS_CHAR(); return(WGT); }
\<					{ POS_CHAR(); return(WLT); }
\>\>                { POS_STR(); return(WRSHFT); }
\<\<                { POS_STR(); return(WLSHFT); }
\>\=				{ POS_STR(); return(WGEQ); }
\342\211\245		{ POS_CHAR(); return(WGEQ); }
\<\=				{ POS_STR(); return(WLEQ); }
\342\211\244		{ POS_CHAR(); return(WLEQ); }

%{ /* This is a special operator/function */
    %}
\-|\342\210\222  { POS_CHAR(); return(WMINUS); }

%{ /* These are functions (unary operations) */
    %}
sin(e)? { POS_STR(); return(WSIN); }
cos(in(e)?)? { POS_STR(); return(WCOS); }
tan { POS_STR(); return(WTAN); }
cot { POS_STR(); return(WCOT); }
sec(ant)? { POS_STR(); return(WSEC); }
csc|cosec(ant)? { POS_STR(); return(WCSC); }
(asin)|(arcsin)|(sin^-1) { POS_STR(); return(WASIN); }
(acos)|(arccos)|(cos^-1) { POS_STR(); return(WACOS); }
(atan)|(arctan)|(tan^-1) { POS_STR(); return(WATAN); }
(acot)|(arccot)|(cot^-1) { POS_STR(); return(WACOT); }
(asec)|(arcsec)|(sec^-1) { POS_STR(); return(WASEC); }
(acsc)|(arccsc)|(csc^-1) { POS_STR(); return(WACSC); }
sinh { POS_STR(); return(WSINH); }
cosh { POS_STR(); return(WCOSH); }
tanh { POS_STR(); return(WTANH); }
coth { POS_STR(); return(WCOTH); }
sech { POS_STR(); return(WSECH); }
csch { POS_STR(); return(WCSCH); }
asinh|arsinh|areasinh|(sinh^-1) { POS_STR(); return(WASINH); }
acosh|arcosh|areacosh|(cosh^-1) { POS_STR(); return(WACOSH); }
atanh|artanh|areatanh|(tanh^-1) { POS_STR(); return(WATANH); }
acoth|arcoth|areacoth|(tanh^-1) { POS_STR(); return(WACOTH); }
asech|areasech|(sech^-1) { POS_STR(); return(WASECH); }
acsch|areacsch|(csch^-1) { POS_STR(); return(WACSCH); }
sinc { POS_STR(); return(WSINC); }
log { POS_STR(); return(WLOG); }
logtwo { POS_STR(); return(WLOGTWO); }
ln { POS_STR(); return(WLN); }
round { POS_STR(); return(WROUND); }
abs { POS_STR(); return(WABS); }
(sqrt)|(\342\210\232) { POS_STR(); return(WSQRT); }
exp { POS_STR(); return(WEXP); }
floor { POS_STR(); return(WFLOOR); }
(ceil)|(ceiling) { POS_STR(); return(WCEIL); }
cbrt { POS_STR(); return(WCBRT); }
rand { POS_STR(); return(WRAND); }
irand { POS_STR(); return(WIRAND); }
fact { POS_STR(); return(WFACT); }
comp { POS_STR(); return(WCOMP); }
eint { POS_STR(); return(WEINT); }
Gamma { POS_STR(); return(WGAMMA); }
ln[gG]amma { POS_STR(); return(WLNGAMMA); }
zeta { POS_STR(); return(WZETA); }

'[^']*' {
    char * temp = strdup(yytext+1);
    temp[yyleng-2] = 0;
    YYLVALAC->variable = temp;
	POS_STR();
    return(STRING);
}

{LETTER}+({LETTER}|{ACCEPTABLE})*{WHITESPACE}*= {
	int i = 0;
	while (!isspace(yytext[i]) && yytext[i] != '=') i++;
	yytext[i] = 0;
	if (isfunc(yytext)) {
		report_error("'%s' is a function and functions cannot be reassigned.", yytext);
		scanerror = 1;
	} else if (isconst(yytext)) {
		report_error("'%s' is a pre-defined constant, which cannot be reassigned.", yytext);
		scanerror = 1;
	} else {
		YYLVALAC->variable = strdup(yytext);
	}
	POS_STR();
	if (! scanerror) {
		return(ASSIGNMENT);
	}
}

{LETTER}+({LETTER}|{ACCEPTABLE})* {
	if (line_is_a_command) {
		YYLVALAC->variable = strdup(yytext);
		POS_STR();
		return(VARIABLE);
	} else {
		report_error("Undefined variable: %s", yytext);
		scanerror = 1;
		POS_STR();
	}
}

%{
%}

({NDIGIT}{DIGIT}{0,2}\.{DIGIT}{3})(e[+-]?{DIGIT}+)? {
    /* simple decimals */
    extern int yydebug;
    int retval;

    /* take out the ignored char */
    strstrip(',', yytext);

    if (yydebug)
        printf("ambiguous %s\n", yytext);

    retval = num_init_set_str(YYLVALAC->number, yytext, DEFAULT_BASE);

    if (-1 == retval) {
        report_error("Invalid characters for base 10");
		scanerror = 1;
    } else {
        unsigned int t = count_digits(yytext);
	Dprintf("simple decimals digits in %s: %u (%u)\n",yytext,t,sig_figs);
        if (t<sig_figs) sig_figs = t;
    }

	POS_STR();
    return(NUMBER);
}

0?[.][0-9]*([eE][+-]?[1-9][0-9]*)? {
    /* zero-optional decimal */
    extern int yydebug;
    int retval;

    Dprintf("zero-optional decimal\n");
    if (yydebug) printf("nonambiguous %s => ", yytext);
    retval = num_init_set_str(YYLVALAC->number, yytext, DEFAULT_BASE);
    if (-1 == retval) {
        report_error("Invalid characters for base 10");
		scanerror = 1;
    } else {
        unsigned int t = count_digits(yytext);
	Dprintf("zero optional decimal digits in %s: %u (%u)\n",yytext,t,sig_figs);
        if (t<sig_figs) sig_figs = t;
    }
	POS_STR();
    return(NUMBER);
}

[1-9]([0-9]*|([0-9]{0,2}([,][0-9]{3})+))([.][0-9]*)?([eE][+-]?0?[1-9][0-9]*)? {
    /* big ugly */
    extern int yydebug;
    int retval;

    Dprintf("big ugly (%s)\n",yytext);
    /* strip out ignored characters */
    strstrip(',',yytext);

    if (yydebug) printf("complex one %s => ", yytext);
    retval = num_init_set_str(YYLVALAC->number, yytext, DEFAULT_BASE);

    if (-1 == retval) {
        report_error("Invalid characters for base 10");
		scanerror = 1;
	} else {
		unsigned int t = count_digits(yytext);
		char * period = strchr(yytext,'.');
		Dprintf("period: %s\n",period);
		if (period == NULL) { // no period means subtract the zeros
			period = yytext+strlen(yytext)-1;
			while (*period == '0') {
				t--;
				period--;
			}
			Dprintf("period: %s\n",period);
		}
		Dprintf("big ugly digits in %s: %u (%u)\n",yytext,t,sig_figs);
		if (t<sig_figs) sig_figs = t;
	}
	POS_STR();
    return(NUMBER);
}

0x[0-9a-fA-F]+([.][0-9a-fA-F]*)?([@][+-]?0?[1-9a-fA-F][0-9a-fA-F]*)? {
    /* hex */
    extern int yydebug;
    int retval;

    Dprintf("hex\n");
    if (yydebug) printf("complex one %s => ", yytext);
    retval = num_init_set_str(YYLVALAC->number,yytext,16);

    if (-1 == retval) {
        report_error("some characters invalid for base 16");
		scanerror = 1;
    } else {
        unsigned int t = count_digits(yytext); //strlen(yytext+2);
        if (yydebug) {
            num_out_str(stdout,DEFAULT_BASE,YYLVALAC->number);
            printf("\n");
        }
	Dprintf("hex digits in %s: %u (%u)\n",yytext,t,sig_figs);
        if (t<sig_figs) sig_figs = t;
    }
	POS_STR();
    return(NUMBER);
}

0[0-9]*([.][0-9]*)?([eE][+-]?[0-9]+)? {
    /* octal */
    //char err[strlen(yytext)+57];
    Dprintf("octal\n");
    if (strchr(yytext,'8') || strchr(yytext,'9')) {
        report_error("Incorrect number format (%s) - expected 0-7 for octal", yytext);
        scanerror = 1;
		POS_STR();
    } else {
        /*unsigned long int value;*/
        unsigned int t;
        int retval;
        retval = num_init_set_str(YYLVALAC->number,yytext,8);
        if (-1 == retval) {
			report_error(strerror(errno));
			scanerror = 1;
		}
        /*sscanf(yytext,"%lo",&value);
        yylval.number = value; */
        t = yyleng-1; //strlen(yytext+1);
	Dprintf("octal digits in %s: %u (%u)\n",yytext,t,sig_figs);
        if (t<sig_figs) sig_figs = t;
		POS_STR();
        return(NUMBER);
    }
}

0b[0-9]+([.][0-9]*)?([eE][+-]?[0-9]+)? {
    /* binary */
    extern int yydebug;

    Dprintf("binary\n");
    /* verify the digits */
    if (strchr(yytext,'2') || strchr(yytext,'3') || strchr(yytext,'4') || strchr(yytext,'5') || strchr(yytext,'6') || strchr(yytext,'7') || strchr(yytext,'8') || strchr(yytext,'9')) {
        report_error("Incorrect number format (%s) - expected 0 or 1 for binary", yytext);
        scanerror = 1;
    } else {
        int retval;

        retval = num_init_set_str(YYLVALAC->number,yytext,2);
        if (-1 == retval) {
            report_error("Expected a 0 or 1 for binary.");
			scanerror = 1;
        } else {
            unsigned int t = count_digits(yytext); //strlen(yytext+2);
            if (yydebug) {
                num_out_str(stdout,DEFAULT_BASE,YYLVALAC->number);
                printf("\n");
            }
	Dprintf("binary digits in %s: %u (%u)\n",yytext,t,sig_figs);
            if (t<sig_figs) sig_figs = t;
        }
    }
	POS_STR();
    return(NUMBER);
}

(({DIGIT})|[,.])+ {
    /* This is the garbage-number collector */
    int i;
    for (i=0;i<yyleng;++i) {
        if (yytext[i] == ',') {
			yytext[i] = conf.thou_delimiter;
        } else if (yytext[i] == '.') {
			yytext[i] = conf.dec_delimiter;
		}
    }
    report_error("Confusing number format (%s)", yytext);
    scanerror = 1;
	POS_STR();
}

%{ /* if we haven't matched anything yet, then it's illegal */
    %}
. {
    if (*yytext == ',') *yytext = conf.thou_delimiter;
    else if (*yytext == '.') *yytext = conf.dec_delimiter;
    report_error("scanner(%i): cannot understand character", (unsigned char) (yytext[0]));
    scanerror = 1;
	POS_CHAR();
}

%%


syntax highlighted by Code2HTML, v. 0.9.1