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;
|
|
|
|
|
}
|