]> granicus.if.org Git - graphviz/commitdiff
need lex and yacc source
authornorth <devnull@localhost>
Sun, 28 Oct 2007 17:53:39 +0000 (17:53 +0000)
committernorth <devnull@localhost>
Sun, 28 Oct 2007 17:53:39 +0000 (17:53 +0000)
lib/cgraph/scan.l [new file with mode: 0644]

diff --git a/lib/cgraph/scan.l b/lib/cgraph/scan.l
new file mode 100644 (file)
index 0000000..aa13e94
--- /dev/null
@@ -0,0 +1,171 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+
+/* requires flex (i.e. not lex)  */
+%{
+#include <grammar.h>
+#include <cghdr.h>
+#include <ctype.h>
+#define GRAPH_EOF_TOKEN                '@'             /* lex class must be defined below */
+       /* this is a workaround for linux flex */
+static int line_num = 1;
+static int html_nest = 0;  /* nesting level for html strings */
+static char* InputFile;
+static Agdisc_t        *Disc;
+static void    *Ifile;
+
+  /* Reset line number */
+void agreadline(int n) { line_num = n; }
+
+  /* (Re)set file:
+   */
+void agsetfile(char* f) { InputFile = f; line_num = 1; }
+
+/* There is a hole here, because switching channels 
+ * requires pushing back whatever was previously read.
+ * There probably is a right way of doing this.
+ */
+void aglexinit(Agdisc_t *disc, void *ifile) { Disc = disc; Ifile = ifile;}
+
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ((result = Disc->io->afread(Ifile, buf, max_size)) < 0) \
+               YY_FATAL_ERROR( "input in flex scanner failed" )
+#endif
+
+/* buffer for arbitrary length strings (longer than BUFSIZ) */
+static char    *Sbuf,*Sptr,*Send;
+static void beginstr(void) {
+       if (Sbuf == NIL(char*)) {
+               Sbuf = malloc(BUFSIZ);
+               Send = Sbuf + BUFSIZ;
+       }
+       Sptr = Sbuf;
+       *Sptr = 0;
+}
+
+static void addstr(char *src) {
+       char    c;
+       if (Sptr > Sbuf) Sptr--;
+       do {
+               do {c = *Sptr++ = *src++;} while (c && (Sptr < Send));
+               if (c) {
+                       long    sz = Send - Sbuf;
+                       long    off = Sptr - Sbuf;
+                       sz *= 2;
+                       Sbuf = (char*)realloc(Sbuf,sz);
+                       Send = Sbuf + sz;
+                       Sptr = Sbuf + off;
+               }
+       } while (c);
+}
+
+static void endstr(void) {
+       yylval.str = (char*)agstrdup(Ag_G_global,Sbuf);
+}
+
+static void endstr_html(void) {
+       yylval.str = (char*)agstrdup_html(Ag_G_global,Sbuf);
+}
+
+/* chkNum:
+ * The regexp for NUMBER allows a terminating letter.
+ * This way we can catch a number immediately followed by a name
+ * and report this to the user.
+ */
+static int chkNum(void) {
+  unsigned char        c = (unsigned char)yytext[yyleng-1];   /* last character */
+  if (!isdigit(c) && (c != '.')) {  /* c is letter */
+       char    buf[BUFSIZ];
+       sprintf(buf,"syntax error - badly formed number '%s' in line %d\n",yytext,line_num);
+    strcat (buf, "splits into two name tokens");
+       agerr(AGWARN,buf);
+    return 1;
+  }
+  else return 0;
+}
+
+/* The LETTER class below consists of ascii letters, underscore, all non-ascii
+ * characters. This allows identifiers to have characters from any
+ * character set independent of locale. The downside is that, for certain
+ * character sets, non-letter and, in fact, undefined characters will be
+ * accepted. This is not likely and, from dot's stand, shouldn't do any
+ * harm. (Presumably undefined characters will be ignored in display.) And,
+ * it allows a greater wealth of names. */
+%}
+GRAPH_EOF_TOKEN                                [@]     
+LETTER [A-Za-z_\200-\377]
+DIGIT  [0-9]
+NAME   {LETTER}({LETTER}|{DIGIT})*
+NUMBER [-]?(({DIGIT}+(\.{DIGIT}*)?)|(\.{DIGIT}+)){LETTER}?
+ID             ({NAME}|{NUMBER})
+%x comment
+%x qstring
+%x hstring
+%%
+{GRAPH_EOF_TOKEN}              return(EOF);
+<INITIAL,comment,qstring>\n    line_num++;
+"/*"                                   BEGIN(comment);
+<comment>[^*\n]*               /* eat anything not a '*' */
+<comment>"*"+[^*/\n]*  /* eat up '*'s not followed by '/'s */
+<comment>"*"+"/"               BEGIN(INITIAL);
+"//".*                                 /* ignore C++-style comments */
+"#".*                                  /* ignore shell-like comments */
+[ \t\r]                                        /* ignore whitespace */
+"node"                                 return(T_node);                 /* see tokens in agcanonstr */
+"edge"                                 return(T_edge);
+"graph"                                        return(T_graph);
+"digraph"                              return(T_digraph);
+"strict"                               return(T_strict);
+"subgraph"                             return(T_subgraph);
+"->"|"--"                              return(T_edgeop);
+{NAME}                                 { yylval.str = (char*)agstrdup(Ag_G_global,yytext); return(T_atom); }
+{NUMBER}                               { if (chkNum()) yyless(yyleng-1); yylval.str = (char*)agstrdup(Ag_G_global,yytext); return(T_atom); }
+["]                                            BEGIN(qstring); beginstr();
+<qstring>["]                   BEGIN(INITIAL); endstr(); return (T_qatom);
+<qstring>[\\]["]               addstr ("\"");
+<qstring>[\\][\n]              line_num++; /* ignore escaped newlines */
+<qstring>([^"\\]*|[\\].)       addstr(yytext);
+[<]                                            BEGIN(hstring); html_nest = 1; beginstr();
+<hstring>[>]                   html_nest--; if (html_nest) addstr(yytext); else {BEGIN(INITIAL); endstr_html(); return (T_qatom);}
+<hstring>[<]                   html_nest++; addstr(yytext);
+<hstring>[\n]                  addstr(yytext); line_num++; /* add newlines */
+<hstring>([^><]*)              addstr(yytext);
+.                                              return (yytext[0]);
+%%
+void yyerror(char *str)
+{
+       char    buf[BUFSIZ];
+       if (InputFile)
+               sprintf(buf,"%s:%d: %s in line %d near '%s'",InputFile, line_num,
+                       str,line_num,yytext);
+       else
+               sprintf(buf," %s in line %d near '%s'", str,line_num,yytext);
+       agerr(AGWARN,buf);
+}
+/* must be here to see flex's macro defns */
+void aglexeof() { unput(GRAPH_EOF_TOKEN); }
+
+#ifndef YY_CALL_ONLY_ARG
+# define YY_CALL_ONLY_ARG void
+#endif
+
+int yywrap(YY_CALL_ONLY_ARG)
+{
+       return 1;
+}
+