/*
 *  Eukleides  version 1.0.3
 *  Copyright (c) Christian Obrecht 2000-2004
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

%x FILTER
%{

#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "parser.tab.h"

#define FILTER_MODE 0
#define NORMAL_MODE 1
#define TRACE_MODE 2
#define STRING_MODE 3
#define COMMENT_MODE 4

int warning(char *);

extern int filter, undefined, lineno, drawing_style, first, inputmode;

int count, pos;

extern char * buffer;

symrec *sym_table = NULL;

/* Symbol table management */

symrec *putsym (char *sym_name)
{
    symrec *ptr;
    ptr = (symrec *)malloc (sizeof (symrec));
    ptr->name = (char *) malloc (strlen (sym_name) + 1);
    strcpy (ptr->name, sym_name);
    ptr->type = VARIABLE;
    ptr->next = sym_table;
    sym_table = ptr;
    return ptr;
}

symrec *getsym (char *sym_name)
{
    symrec *ptr;
    for (ptr = sym_table; ptr != NULL; ptr = ptr->next)
	if (strcmp (ptr->name, sym_name) == 0)
	    return ptr;
    return NULL;
}

void clearsym(void)
{
    symrec *ptr, *prev;
    ptr = sym_table;
    while (ptr != NULL) {
	free(ptr->name);
	prev = ptr;
	ptr = ptr->next;
	free(prev);
    }
    sym_table = NULL;
}

saverec *save_table = NULL;

void save(void * s)
{
    saverec *ptr;
    ptr = (saverec *)malloc(sizeof(saverec));
    ptr->s = s;
    ptr->next = save_table;
    save_table = ptr;
}

void clearsave(void)
{
    saverec *ptr, *prev;
    ptr = save_table;
    while (ptr != NULL) {
	free(ptr->s);
	prev = ptr;
	ptr = ptr->next;
	free(prev);
    }
    save_table = NULL;
}

#undef YY_INPUT
#define YY_INPUT(buf,result,max) (result = char_input(buf,max))

/* Input function */

int char_input(char *buf, int max)
{
    int n;

    static int cursor = 0, bracepos, loopcount, lastmode;

    n = 0;

    while (buffer[cursor] != '\0' && n < max) {
	buf[n] = buffer[cursor];
	switch (buffer[cursor]) {
	    case '%':
		if (inputmode == FILTER_MODE
		    && strncmp("%--eukleides",buffer+cursor,12) == 0)
		    inputmode = COMMENT_MODE;
		if (inputmode == NORMAL_MODE) {
		    inputmode = COMMENT_MODE;
		    if (strncmp("%--end",buffer+cursor,6) == 0
			|| strncmp("%--stop",buffer+cursor,7) == 0)
			inputmode = FILTER_MODE;
		};
		break;
	    case '\n':
		if (inputmode == STRING_MODE || inputmode == COMMENT_MODE)
		    inputmode = NORMAL_MODE;
		break;
	    case '"':
		if (inputmode == NORMAL_MODE || inputmode == TRACE_MODE) {
		    lastmode = inputmode;
		    inputmode = STRING_MODE;
		}
		else if (inputmode == STRING_MODE) inputmode = lastmode;
		break;
	    case '{':
		if (inputmode == NORMAL_MODE) {
		    bracepos = cursor-1;
		    buffer[cursor] = ';';
		    loopcount = 300;
		    inputmode = TRACE_MODE;
		}
		break;
	    case '}':
		if (inputmode == TRACE_MODE) {
		    if (--loopcount)
			cursor = bracepos;
		    else
			inputmode = NORMAL_MODE;
		}
	};
	cursor++; n++;
    }
    return n;
}

int yywrap(void)
{
    return 1;
}

%}

%%

%{

    if (filter) BEGIN FILTER;
    else BEGIN INITIAL;

%}

	/* Ignore whitespace */

[\t ]+

	/* Stop compiling */

"%--stop"[\t ]*\n {

    lineno++;
    filter = 1;
    undefined = 1;
    printf("\\endpspicture\n");
    printf("%% End of figure\n");
    BEGIN FILTER;
}
				  
"%--end"[\t ]*\n {

    lineno++;
    filter = 1;
    clearsave(); /* Clear memory */
    clearsym();
    sym_table = NULL;
    undefined = 1;
    drawing_style = FULL;
    printf("\\endpspicture\n");
    printf("%% End of figure\n");
    BEGIN FILTER;
}

	/* Comments */
				  
%.*\n	{ lineno++; }
				  
%.*	{ return '\n'; }

	/* Numbers */

(([0-9]+)|([0-9]*\.[0-9]+)) {

    yylval.number = atof(yytext);
    return NUMBER;
}

	/* Strings */

\"[^\"\n]*[\"\n] {

    yylval.string = strdup(yytext+1);
    if (yylval.string[yyleng-2] != '"') {
	warning("Unterminated character string");
	lineno++;
    }
    else yylval.string[yyleng-2] = '\0';
    return STRING;
}

\$[^\$\n]*[\$\n] {

    yylval.string = strdup(yytext);
    if (yylval.string[yyleng-1] != '$') {
	warning("Unterminated character string");
	lineno++;
    }
    return STRING;
}

	/* Reserved words */

point		{ return POINT; }

vector		{ return VECTOR; }

line		{ return LINE; }

segment		{ return SEGMENT; }

circle		{ return CIRCLE; }

conic		{ return CONIC; }

parabola	{ return PARABOLA; }

ellipse		{ return ELLIPSE; }

hyperbola	{ return HYPERBOLA; }

translation	{ return TRANSLATION; }

reflection	{ return REFLECTION; }

rotation	{ return ROTATION; }

projection	{ return PROJECTION; }

homothecy	{ return HOMOTHECY; }

intersection	{ return INTERSECTION; }

parallel	{ return PARALLEL; }

perpendicular	{ return PERPENDICULAR; }

midpoint	{ return MIDPOINT; }

begin		{ return TOKBEGIN; }

end		{ return END; }

center		{ return CENTER; }

vertices	{ return VERTICES; }

foci		{ return FOCI; }

triangle	{ return TRIANGLE; }

equilateral	{ return EQUILATERAL; }

isosceles	{ return ISOSCELES; }

right		{ return RIGHT; }

barycenter	{ return BARYCENTER; }

median		{ return MEDIAN; }

altitude	{ return ALTITUDE; }

orthocenter	{ return ORTHOCENTER; }

bisector	{ return BISECTOR; }

incircle	{ return INCIRCLE; }

parallelogram	{ return PARALLELOGRAM; }

rectangle	{ return RECTANGLE; }

square		{ return SQUARE; }

pentagon	{ return PENTAGON; }

hexagon		{ return HEXAGON; }

abscissa	{ return ABSCISSA; }

ordinate	{ return ORDINATE; }

length		{ return LENGTH; }

distance	{ return DISTANCE; }

angle		{ return ANGLE; }

arg		{ return ARGUMENT; }

radius		{ return RADIUS; }

major		{ return MAJOR; }

minor		{ return MINOR; }

eccentricity	{ return ECCENTRICITY; }

height		{ return HEIGHT; }

exp		{ return EXP; }

ln		{ return LN; }

pi		{ return TOKPI; }

sin		{ return SIN; }

cos		{ return COS; }

tan		{ return TAN; }

asin		{ return ASIN; }

acos		{ return ACOS; }

atan		{ return ATAN; }

deg		{ return TOKDEG; }

rad		{ return TOKRAD; }

sqrt		{ return SQRT; }

abs		{ return TOKABS; }

sign		{ return SIGN; }

ceil		{ return CEIL; }

floor		{ return FLOOR; }

round		{ return ROUND; }

min		{ return TOKMIN; }

max		{ return TOKMAX; }

clamp		{ return TOKCLAMP; }

"=="		{ return EQ; }

"!="		{ return NEQ; }

"<="		{ return LEQ; }

">="		{ return GEQ; }

and		{ return AND; }

or		{ return OR; }

not		{ return NOT; }

frame		{ return FRAME; }

color		{ return COLOR; }

black		{ return BLACK; }

darkgray	{ return DARKGRAY; }

gray		{ return GRAY; }

lightgray	{ return LIGHTGRAY; }

white		{ return WHITE; }

red		{ return RED; }

green		{ return GREEN; }

blue		{ return BLUE; }

cyan		{ return CYAN; }

magenta		{ return MAGENTA; }

yellow		{ return YELLOW; }

thickness	{ return THICKNESS; }

font		{ return FONT; }

tricks		{ return TRICKS; }

export		{ return EXPORT; }

draw		{ return DRAW; }

label		{ return LABEL; }

mark		{ return MARK; }

dot		{ return DOT; }

disc		{ return DISC; }

box		{ return BOX; }

cross		{ return CROSS; }

plus		{ return PLUS; }

noarrow		{ return NOARROW; }

arrow		{ return ARROW; }

backarrow	{ return BACKARROW; }

doublearrow	{ return DOUBLEARROW; }

entire		{ return ENTIRE;}

halfline	{ return HALFLINE; }

backhalfline	{ return BACKHALFLINE; }

style		{ return STYLE; }

full		{ return FULL; }

dotted		{ return DOTTED; }

dashed		{ return DASHED; }

simple		{ return SIMPLE; }

double		{ return DOUBLE; }

triple		{ return TRIPLE; }

interactive	{ return INTERACTIVE; }

up		{ return UP; }

strokes		{ return STROKES; }

trace		{ return TRACE; }

	/* Variables */

[a-zA-Z_][a-zA-Z0-9_']* {
    symrec *s;
    s = getsym (yytext);
    if (s == NULL) 
	s = putsym (yytext); 
    yylval.ptr = s;
    switch (s->type)
    {
	case NUMBER	: return NUMBER_VARIABLE;
	case POINT	: return POINT_VARIABLE;
	case VECTOR	: return VECTOR_VARIABLE;
	case LINE	: return LINE_VARIABLE;
	case SEGMENT	: return SEGMENT_VARIABLE;
	case CIRCLE	: return CIRCLE_VARIABLE;
	case CONIC	: return CONIC_VARIABLE;
	case VARIABLE	: return VARIABLE;
    }
}

	/* Semi-colons and \r are handled as \n */

(;)|(\r) { return '\n'; }

	/* New line */

\n { lineno++; return '\n'; }

	/* Trace command block */

"{" {

    if (first) {
	count = 300;
	pos = lineno;
	first = 0;
	return '\n';
    } else return '{';
}

"}" {

    if (count == 300)
	lineno -= 299*(lineno-pos);
    if (--count == 0)
	first = 1;
    return '}';
}

	/* Anything else */

. { return yytext[0]; }

	/* Start compiling */

<FILTER>"%--eukleides"[\t ]*\n {

    lineno++; filter = 0;
    printf("%% Generated by eukleides 1.0.3\n");
    printf("\\psset{linecolor=black, linewidth=.5pt, arrowsize=2pt 4}\n");
    BEGIN INITIAL;
}

	/* New line */

<FILTER>\n { lineno++; ECHO; }

	/* Anything else */

<FILTER>. { ECHO; }

%%



syntax highlighted by Code2HTML, v. 0.9.1