1
/* $Id: scan.l,v 1.7 2009/06/03 01:10:51 ellson Exp $ $Revision: 1.7 $ */
2
/* vim:set shiftwidth=4 ts=8: */
4
/**********************************************************
5
* This software is part of the graphviz package *
6
* http://www.graphviz.org/ *
8
* Copyright (c) 1994-2004 AT&T Corp. *
9
* and is licensed under the *
10
* Common Public License, Version 1.0 *
13
* Information and Software Systems Research *
14
* AT&T Research, Florham Park NJ *
15
**********************************************************/
18
/* requires flex (i.e. not lex) */
24
#define GRAPH_EOF_TOKEN '@' /* lex class must be defined below */
25
/* this is a workaround for linux flex */
26
static int line_num = 1;
27
static int html_nest = 0; /* nesting level for html strings */
28
static char* InputFile;
29
static Agdisc_t *Disc;
33
/* Reset line number */
34
void agreadline(int n) { line_num = n; }
38
void agsetfile(char* f) { InputFile = f; line_num = 1; }
40
/* There is a hole here, because switching channels
41
* requires pushing back whatever was previously read.
42
* There probably is a right way of doing this.
44
void aglexinit(Agdisc_t *disc, void *ifile) { Disc = disc; Ifile = ifile; graphType = 0;}
47
#define YY_INPUT(buf,result,max_size) \
48
if ((result = Disc->io->afread(Ifile, buf, max_size)) < 0) \
49
YY_FATAL_ERROR( "input in flex scanner failed" )
52
/* buffer for arbitrary length strings (longer than BUFSIZ) */
53
static char *Sbuf,*Sptr,*Send;
54
static void beginstr(void) {
55
if (Sbuf == NIL(char*)) {
56
Sbuf = malloc(BUFSIZ);
63
static void addstr(char *src) {
65
if (Sptr > Sbuf) Sptr--;
67
do {c = *Sptr++ = *src++;} while (c && (Sptr < Send));
69
long sz = Send - Sbuf;
70
long off = Sptr - Sbuf;
72
Sbuf = (char*)realloc(Sbuf,sz);
79
static void endstr(void) {
80
yylval.str = (char*)agstrdup(Ag_G_global,Sbuf);
83
static void endstr_html(void) {
84
yylval.str = (char*)agstrdup_html(Ag_G_global,Sbuf);
88
storeFileName (char* fname, int len)
94
if (cnt) buf = (char*)realloc (buf, len+1);
95
else buf = (char*)malloc (len+1);
103
* Process a possible preprocessor line directive.
106
static void ppDirective (void)
110
char* s = yytext + 1; /* skip initial # */
112
if (strncmp(s, "line", 4) == 0) s += 4;
113
r = sscanf(s, "%d %1[\"]%n", &lineno, buf, &cnt);
114
if (r > 0) { /* got line number */
115
line_num = lineno - 1;
116
if (r > 1) { /* saw quote */
119
while (*e && (*e != '"')) e++;
122
storeFileName (p, e-p);
129
* The regexp for NUMBER allows a terminating letter.
130
* This way we can catch a number immediately followed by a name
131
* and report this to the user.
133
static int chkNum(void) {
134
unsigned char c = (unsigned char)yytext[yyleng-1]; /* last character */
135
if (!isdigit(c) && (c != '.')) { /* c is letter */
137
sprintf(buf,"syntax error - badly formed number '%s' in line %d\n",yytext,line_num);
138
strcat (buf, "splits into two name tokens");
145
/* The LETTER class below consists of ascii letters, underscore, all non-ascii
146
* characters. This allows identifiers to have characters from any
147
* character set independent of locale. The downside is that, for certain
148
* character sets, non-letter and, in fact, undefined characters will be
149
* accepted. This is not likely and, from dot's stand, shouldn't do any
150
* harm. (Presumably undefined characters will be ignored in display.) And,
151
* it allows a greater wealth of names. */
154
LETTER [A-Za-z_\200-\377]
156
NAME {LETTER}({LETTER}|{DIGIT})*
157
NUMBER [-]?(({DIGIT}+(\.{DIGIT}*)?)|(\.{DIGIT}+)){LETTER}?
163
{GRAPH_EOF_TOKEN} return(EOF);
164
<INITIAL,comment,qstring>\n line_num++;
166
<comment>[^*\n]* /* eat anything not a '*' */
167
<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
168
<comment>"*"+"/" BEGIN(INITIAL);
169
"//".* /* ignore C++-style comments */
170
^"#".* ppDirective ();
171
"#".* /* ignore shell-like comments */
172
[ \t\r] /* ignore whitespace */
173
"node" return(T_node); /* see tokens in agcanonstr */
174
"edge" return(T_edge);
175
"graph" if (!graphType) graphType = T_graph; return(T_graph);
176
"digraph" if (!graphType) graphType = T_digraph; return(T_digraph);
177
"strict" return(T_strict);
178
"subgraph" return(T_subgraph);
179
"->" if (graphType == T_digraph) return(T_edgeop); else return('-');
180
"--" if (graphType == T_graph) return(T_edgeop); else return('-');
181
{NAME} { yylval.str = (char*)agstrdup(Ag_G_global,yytext); return(T_atom); }
182
{NUMBER} { if (chkNum()) yyless(yyleng-1); yylval.str = (char*)agstrdup(Ag_G_global,yytext); return(T_atom); }
183
["] BEGIN(qstring); beginstr();
184
<qstring>["] BEGIN(INITIAL); endstr(); return (T_qatom);
185
<qstring>[\\]["] addstr ("\"");
186
<qstring>[\\][\n] line_num++; /* ignore escaped newlines */
187
<qstring>([^"\\]*|[\\].) addstr(yytext);
188
[<] BEGIN(hstring); html_nest = 1; beginstr();
189
<hstring>[>] html_nest--; if (html_nest) addstr(yytext); else {BEGIN(INITIAL); endstr_html(); return (T_qatom);}
190
<hstring>[<] html_nest++; addstr(yytext);
191
<hstring>[\n] addstr(yytext); line_num++; /* add newlines */
192
<hstring>([^><]*) addstr(yytext);
193
. return (yytext[0]);
195
void yyerror(char *str)
197
unsigned char xbuf[BUFSIZ];
201
agxbinit(&xb, BUFSIZ, xbuf);
203
agxbput (&xb, InputFile);
206
sprintf(buf," %s in line %d near '", str,line_num);
208
agxbput (&xb, yytext);
210
agerr(AGWARN,agxbuse(&xb));
213
/* must be here to see flex's macro defns */
214
void aglexeof() { unput(GRAPH_EOF_TOKEN); }
216
#ifndef YY_CALL_ONLY_ARG
217
# define YY_CALL_ONLY_ARG void
220
int yywrap(YY_CALL_ONLY_ARG)