%{
#include "sql2.h"
#include <string.h>

int lineno = 1;
void yyerror(char *s);

       /* macro to save the text of a SQL token */
#define SV save_str(yytext)

       /* macro to save the text and return a token */
#define TOK(name) { SV;return name; }
%}
%s SQL
%%

EXEC[ \t]+SQL   { BEGIN SQL; start_save(); }


       /* literal keyword tokens */

<SQL>ALL                TOK(ALL)
<SQL>AND                TOK(AND)
<SQL>AVG                TOK(AMMSC)
<SQL>MIN                TOK(AMMSC)
<SQL>MAX                TOK(AMMSC)
<SQL>SUM                TOK(AMMSC)
<SQL>COUNT              TOK(AMMSC)
<SQL>ANY                TOK(ANY)
<SQL>AS                 TOK(AS)
<SQL>ASC                TOK(ASC)
<SQL>AUTHORIZATION      TOK(AUTHORIZATION)
<SQL>BETWEEN            TOK(BETWEEN)
<SQL>BY                 TOK(BY)
<SQL>CHAR(ACTER)?       TOK(CHARACTER)
<SQL>CHECK              TOK(CHECK)
<SQL>CLOSE              TOK(CLOSE)
<SQL>COMMIT             TOK(COMMIT)
<SQL>CONTINUE           TOK(CONTINUE)
<SQL>CREATE             TOK(CREATE)
<SQL>CURRENT            TOK(CURRENT)
<SQL>CURSOR             TOK(CURSOR)
<SQL>DECIMAL            TOK(DECIMAL)
<SQL>DECLARE            TOK(DECLARE)
<SQL>DEFAULT            TOK(DEFAULT)
<SQL>DELETE             TOK(DELETE)
<SQL>DESC               TOK(DESC)
<SQL>DISTINCT           TOK(DISTINCT)
<SQL>DOUBLE             TOK(DOUBLE)
<SQL>ESCAPE             TOK(ESCAPE)
<SQL>EXISTS             TOK(EXISTS)
<SQL>FETCH              TOK(FETCH)
<SQL>FLOAT              TOK(FLOAT)
<SQL>FOR                TOK(FOR)
<SQL>FOREIGN            TOK(FOREIGN)
<SQL>FOUND              TOK(FOUND)
<SQL>FROM               TOK(FROM)
<SQL>GO[ \t]*TO         TOK(GOTO)
<SQL>GRANT              TOK(GRANT)
<SQL>GROUP              TOK(GROUP)
<SQL>HAVING             TOK(HAVING)
<SQL>IN                 TOK(IN)
<SQL>INDICATOR          TOK(INDICATOR)
<SQL>INSERT             TOK(INSERT)
<SQL>INT(EGER)?         TOK(INTEGER)
<SQL>INTO               TOK(INTO)
<SQL>IS                 TOK(IS)
<SQL>KEY                TOK(KEY)
<SQL>LANGUAGE           TOK(LANGUAGE)
<SQL>LIKE               TOK(LIKE)
<SQL>NOT                TOK(NOT)
<SQL>NULL               TOK(NULLX)
<SQL>NUMERIC            TOK(NUMERIC)
<SQL>OF                 TOK(OF)
<SQL>ON                 TOK(ON)
<SQL>OPEN               TOK(OPEN)
<SQL>OPTION             TOK(OPTION)
<SQL>OR                 TOK(OR)
<SQL>ORDER              TOK(ORDER)
<SQL>PRECISION          TOK(PRECISION)
<SQL>PRIMARY            TOK(PRIMARY)
<SQL>PRIVILEGES         TOK(PRIVILEGES)
<SQL>PROCEDURE          TOK(PROCEDURE)
<SQL>PUBLIC             TOK(PUBLIC)
<SQL>REAL               TOK(REAL)
<SQL>REFERENCES         TOK(REFERENCES)
<SQL>ROLLBACK           TOK(ROLLBACK)
<SQL>SCHEMA             TOK(SCHEMA)
<SQL>SELECT             TOK(SELECT)
<SQL>SET                TOK(SET)
<SQL>SMALLINT           TOK(SMALLINT)
<SQL>SOME               TOK(SOME)
<SQL>SQLCODE            TOK(SQLCODE)
<SQL>TABLE              TOK(TABLE)
<SQL>TO                 TOK(TO)
<SQL>UNION              TOK(UNION)
<SQL>UNIQUE             TOK(UNIQUE)
<SQL>UPDATE             TOK(UPDATE)
<SQL>USER               TOK(USER)
<SQL>VALUES             TOK(VALUES)
<SQL>VIEW               TOK(VIEW)
<SQL>WHENEVER           TOK(WHENEVER)
<SQL>WHERE              TOK(WHERE)
<SQL>WITH               TOK(WITH)
<SQL>WORK               TOK(WORK)

       /* punctuation */

<SQL>"="        |
<SQL>"<>"       |
<SQL>"<"        |
<SQL>">"        |
<SQL>"<="       |
<SQL>">="               TOK(COMPARISON)

<SQL>[-+*/(),.;]        TOK(yytext[0])


       /* names */
<SQL>[A-Za-z][A-Za-z0-9_]*      TOK(NAME)

       /* parameters */
<SQL>":"[A-Za-z][A-Za-z0-9_]*   {
                       save_param(yytext+1);
                       return PARAMETER;
               }

       /* numbers */

<SQL>[0-9]+     |
<SQL>[0-9]+"."[0-9]* |
<SQL>"."[0-9]*          TOK(INTNUM)

<SQL>[0-9]+[eE][+-]?[0-9]+      |
<SQL>[0-9]+"."[0-9]*[eE][+-]?[0-9]+ |
<SQL>"."[0-9]*[eE][+-]?[0-9]+   TOK(APPROXNUM)

       /* strings */

<SQL>'[^'\n]*'  {
               int c = input();

               unput(c);       /* just peeking */
               if(c != '\'') {
                       SV;return STRING;
               } else
                       yymore();
       }

<SQL>'[^'\n]*$  {       yyerror("Unterminated string"); }

<SQL>\n         { save_str(" ");lineno++; }
\n              { lineno++; ECHO; }

<SQL>[ \t\r]+   save_str(" ");  /* white space */

<SQL>"--".*     ;       /* comment */

               ECHO;   /* random non-SQL text */
%%

void
yyerror(char *s)
{
       printf("%d: %s at %s\n", lineno, s, yytext);
}

main(int ac, char **av)
{
       if(ac > 1 && (yyin = fopen(av[1], "r")) == NULL) {
               perror(av[1]);
               exit(1);
       }

       if(!yyparse())
               fprintf(stderr, "Embedded SQL parse worked\n");
       else
               fprintf(stderr, "Embedded SQL parse failed\n");
} /* main */

/* leave SQL lexing mode */
un_sql()
{
       BEGIN INITIAL;
} /* un_sql */