iverilog/ivlpp/lexor.lex

351 lines
8.7 KiB
Plaintext
Raw Normal View History

1999-07-03 19:24:11 +02:00
%{
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
1999-07-10 02:36:12 +02:00
#ident "$Id: lexor.lex,v 1.5 1999/07/10 00:36:12 steve Exp $"
1999-07-03 19:24:11 +02:00
#endif
# include <stdio.h>
# include <malloc.h>
# include <string.h>
# include <assert.h>
# include "parse.h"
1999-07-03 22:03:47 +02:00
# include "globals.h"
static void output_init();
#define YY_USER_INIT output_init()
1999-07-03 19:24:11 +02:00
static void def_match();
static void def_start();
static void do_define();
static void include_filename();
static void do_include();
static int yywrap();
1999-07-03 22:03:47 +02:00
struct include_stack_t {
char* path;
1999-07-07 03:07:57 +02:00
/* If the current input is the the file, this member is set. */
1999-07-03 22:03:47 +02:00
FILE*file;
1999-07-07 03:07:57 +02:00
/* If we are reparsing a macro expansion, file is 0 and this
member points to the string is progress */
const char*str;
1999-07-03 22:03:47 +02:00
unsigned lineno;
YY_BUFFER_STATE yybs;
struct include_stack_t*next;
};
static struct include_stack_t*istack = 0;
static struct include_stack_t*standby = 0;
1999-07-07 03:07:57 +02:00
#define YY_INPUT(buf,result,max_size) do { \
if (istack->file) { \
size_t rc = fread(buf, 1, max_size, istack->file); \
if (rc == 0) result = YY_NULL; \
else result = rc; \
} else { \
if (*istack->str == 0) result = YY_NULL; \
else { buf[0] = *istack->str++; result = 1; } \
} \
} while(0)
1999-07-10 02:36:12 +02:00
static int comment_enter = 0;
1999-07-03 19:24:11 +02:00
%}
%x PPINCLUDE
%x PPDEFINE
1999-07-10 02:36:12 +02:00
%x CCOMMENT
1999-07-03 19:24:11 +02:00
%%
1999-07-10 02:36:12 +02:00
/* detect multiline, c-style comments, passing them directly to the
output. This is necessary to allow for ignoring directives that
are included within the comments. */
"/*" { comment_enter = YY_START; BEGIN(CCOMMENT); ECHO; }
<CCOMMENT>. { ECHO; }
<CCOMMENT>\n { istack->lineno += 1; ECHO; }
<CCOMMENT>"*/" { BEGIN(comment_enter); ECHO; }
1999-07-03 19:24:11 +02:00
/* This set of patterns matches the include directive and the name
that follows it. when the directive ends, the do_include function
performs the include operation. */
^`include { BEGIN(PPINCLUDE); }
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
1999-07-10 02:36:12 +02:00
<PPINCLUDE>[ \t\b\f] { ; }
1999-07-03 19:24:11 +02:00
1999-07-03 22:03:47 +02:00
<PPINCLUDE>\n { istack->lineno += 1; BEGIN(0); do_include(); }
1999-07-03 19:24:11 +02:00
/* Detect the define directive, and match the name. Match any
white space that might be found, as well. After I get the
directive and the name, go into PPDEFINE mode and prepare to
collect the defined value. */
1999-07-07 03:18:57 +02:00
^`define[ \t]+[a-zA-Z][a-zA-Z0-9_]*[ \t]+ { BEGIN(PPDEFINE); def_start(); }
1999-07-03 19:24:11 +02:00
<PPDEFINE>.* { do_define(); }
1999-07-03 22:03:47 +02:00
<PPDEFINE>\n { istack->lineno += 1; BEGIN(0); ECHO; }
1999-07-03 19:24:11 +02:00
1999-07-10 02:36:12 +02:00
1999-07-03 19:24:11 +02:00
/* This pattern notices macros and arranges for it to be replaced. */
1999-07-07 03:18:57 +02:00
`[a-zA-Z][a-zA-Z0-9_]* { def_match(); }
1999-07-03 19:24:11 +02:00
/* Any text that is not a directive just gets passed through to the
output. Very easy. */
. { ECHO; }
1999-07-03 22:03:47 +02:00
\n { istack->lineno += 1; ECHO; }
1999-07-03 19:24:11 +02:00
%%
/* Defined macros are kept in this table for convenient lookup. As
`define directives are matched (and the do_define() function
called) the tree is built up to match names with values. If a
define redefines an existing name, the new value it taken. */
struct define_t {
char*name;
char*value;
struct define_t*left, *right;
};
static struct define_t*def_table = 0;
/* When a macro use is discovered in the source, this function is
used to look up the name and emit the substitution in its
place. If the name is not found, then the `name string is written
out instead. */
static void def_match()
{
struct define_t*cur = def_table;
while (cur) {
int cmp = strcmp(yytext+1, cur->name);
if (cmp == 0) break;
if (cmp < 0)
cur = cur->left;
else
cur = cur->right;
}
1999-07-07 03:07:57 +02:00
if (cur) {
struct include_stack_t*isp
= calloc(1, sizeof(struct include_stack_t));
isp->str = cur->value;
isp->next = istack;
1999-07-10 02:36:12 +02:00
istack->yybs = YY_CURRENT_BUFFER;
1999-07-07 03:07:57 +02:00
istack = isp;
yy_switch_to_buffer(yy_new_buffer(istack->file, YY_BUF_SIZE));
} else {
}
1999-07-03 19:24:11 +02:00
}
static char def_name[256];
static void def_start()
{
sscanf(yytext, "`define %s", def_name);
}
1999-07-03 22:03:47 +02:00
void define_macro(const char*name, const char*value)
1999-07-03 19:24:11 +02:00
{
struct define_t*def = malloc(sizeof(struct define_t));
1999-07-03 22:03:47 +02:00
def->name = strdup(name);
def->value = strdup(value);
1999-07-03 19:24:11 +02:00
def->left = 0;
def->right = 0;
if (def_table == 0) {
def_table = def;
} else {
struct define_t*cur = def_table;
for (;;) {
int cmp = strcmp(def->name, cur->name);
if (cmp == 0) {
free(cur->value);
cur->value = def->value;
free(def->name);
free(def);
break;
} else if (cmp < 0) {
if (cur->left == 0) {
cur->left = def;
break;
} else {
cur = cur->left;
}
} else {
if (cur->right == 0) {
cur->right = def;
break;
} else {
cur = cur->right;
}
}
}
}
}
1999-07-03 22:03:47 +02:00
static void do_define()
{
1999-07-10 02:36:12 +02:00
/* FIXME: This strips trailing line comments out of the
definition. It's not adequate as the "//" may have been
quoted or commented, but it'll do for now. */
char *cp;
if(cp = strstr(yytext, "//"))
*cp = 0;
1999-07-03 22:03:47 +02:00
define_macro(def_name, yytext);
}
1999-07-03 19:24:11 +02:00
/*
* Include file handling works by keeping an include stack of the
* files that are opened and being processed. The first item on the
* stack is the current file being scanned. If I get to an include
* statement,
* open the new file,
* save the current buffer context,
* create a new buffer context,
* and push the new file information.
*
* When the file runs out, the yywrap closes the file and deletes the
* buffer. If after popping the current file information there is
* another file on the stack, restore its buffer context and resume
* parsing.
*/
1999-07-03 22:03:47 +02:00
static void output_init()
{
if (line_direct_flag)
fprintf(yyout, "#line \"%s\" 0\n", istack->path);
}
1999-07-03 19:24:11 +02:00
static void include_filename()
{
assert(standby == 0);
standby = malloc(sizeof(struct include_stack_t));
standby->path = strdup(yytext+1);
standby->path[strlen(standby->path)-1] = 0;
1999-07-03 22:03:47 +02:00
standby->lineno = 0;
1999-07-03 19:24:11 +02:00
}
static void do_include()
{
1999-07-03 22:03:47 +02:00
if (standby->path[0] == '/') {
standby->file = fopen(standby->path, "r");
} else {
unsigned idx = 0;
standby->file = 0;
for (idx = 0 ; idx < include_cnt ; idx += 1) {
char path[4096];
sprintf(path, "%s/%s", include_dir[idx], standby->path);
standby->file = fopen(path, "r");
if (standby->file)
break;
}
}
1999-07-03 19:24:11 +02:00
if (standby->file == 0) {
perror(standby->path);
exit(1);
}
assert(standby->file);
standby->next = istack;
istack->yybs = YY_CURRENT_BUFFER;
istack = standby;
standby = 0;
yy_switch_to_buffer(yy_new_buffer(istack->file, YY_BUF_SIZE));
1999-07-03 22:03:47 +02:00
1999-07-07 03:07:57 +02:00
if (line_direct_flag && istack->path)
1999-07-03 22:03:47 +02:00
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
1999-07-03 19:24:11 +02:00
}
static int yywrap()
{
struct include_stack_t*isp = istack;
istack = isp->next;
yy_delete_buffer(YY_CURRENT_BUFFER);
1999-07-07 03:07:57 +02:00
if (isp->file) {
fclose(isp->file);
free(isp->path);
} else {
/* If I am printing line directives and I just finished
macro substitution, I should terminate the line and
arrange for a new directive to be printed. */
if (line_direct_flag && istack->path)
fprintf(yyout, "\n");
}
1999-07-03 19:24:11 +02:00
free(isp);
if (istack == 0)
return 1;
yy_switch_to_buffer(istack->yybs);
1999-07-03 22:03:47 +02:00
1999-07-07 03:07:57 +02:00
if (line_direct_flag && istack->path)
1999-07-03 22:03:47 +02:00
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
1999-07-03 19:24:11 +02:00
return 0;
}
/*
* This function initializes the whole process. The first file is
* opened, and the lexor is initialized. The include stack is cleared
* and ready to go.
*/
1999-07-03 22:03:47 +02:00
void reset_lexor(FILE*out, const char*path)
1999-07-03 19:24:11 +02:00
{
struct include_stack_t*isp = malloc(sizeof(struct include_stack_t));
isp->path = strdup(path);
isp->file = fopen(path, "r");
1999-07-07 03:07:57 +02:00
isp->str = 0;
1999-07-03 19:24:11 +02:00
if (isp->file == 0) {
perror(path);
exit(1);
}
1999-07-03 22:03:47 +02:00
yyout = out;
1999-07-03 19:24:11 +02:00
yyrestart(isp->file);
assert(istack == 0);
istack = isp;
isp->next = 0;
}