- Implemented a new preprocessor that is (nearly) ANSI-C compliant. The

old parser has been stripped from the old preprocessor-code which
  cleaned up both resource-scanner and -parser.
- Standard defines have been introduced (see README.wrc)
- Both preprocessor- and resource-scanner have been optimized slightly
  so that no backing up is required (one char lookahead is enough).
- Filename-scanning has been cleaned up, though not perfect yet.
- User-type resources are compatible now.
- Line-continuation in strings is corrected so that it does not
  introduce a newline in the output.
This commit is contained in:
Bertho Stultiens 2000-05-01 20:05:58 +00:00 committed by Alexandre Julliard
parent 5b4f3e8d6d
commit 27337af65c
28 changed files with 3435 additions and 1188 deletions

View File

@ -1,3 +1,4 @@
#include "windef.h"
#include "winuser.h"
#include "comctl32.h"

View File

@ -3,6 +3,7 @@
*
*/
#include "windef.h"
#include "winuser.h"
#include "winnls.h"
#include "cdlg.h"

View File

@ -3,7 +3,7 @@
*
*/
1 "OEMBIN"
1 OEMBIN
{
0x11, /* vertical thumb height (in pixels) */
0x11, /* horizontal thumb width (in pixels) */

View File

@ -3,6 +3,7 @@
*
*/
#include "windef.h"
#include "winuser.h"
#include "winnls.h"
#include "shlobj.h"

View File

@ -25,10 +25,6 @@ all: check_wrc $(PROGRAMS)
@MAKE_RULES@
# Override resource compiler rules
.rc.s:
$(CPP) $(DEFS) $(OPTIONS) $(DIVINCL) -DRC_INVOKED -P -x c $< | $(WRC) $(WRCFLAGS) $(WRCEXTRA) -o $*.s
clock: $(OBJS)
$(CC) -o clock $(OBJS) $(DLL_LINK) $(LIBS)

View File

@ -26,10 +26,6 @@ all: check_wrc $(PROGRAMS)
@MAKE_RULES@
# Override resource compiler rules
.rc.s:
$(CPP) $(DEFS) $(OPTIONS) $(DIVINCL) -DRC_INVOKED -P -x c $< | $(WRC) $(WRCFLAGS) $(WRCEXTRA) -o $*.s
notepad: $(OBJS)
$(CC) -o notepad $(OBJS) $(DLL_LINK) $(LIBS)

View File

@ -28,10 +28,6 @@ all: check_wrc $(PROGRAMS)
@MAKE_RULES@
# Override resource compiler rules
.rc.s:
$(CPP) $(DEFS) $(OPTIONS) $(DIVINCL) -DRC_INVOKED -P -x c $< | $(WRC) $(WRCFLAGS) $(WRCEXTRA) -o $*.s
progman: $(OBJS)
$(CC) -o progman $(OBJS) $(DLL_LINK) $(LIBS)

View File

@ -22,10 +22,6 @@ all: check_wrc $(PROGRAMS)
@MAKE_RULES@
# Override resource compiler rules
.rc.s:
$(CPP) $(DEFS) $(OPTIONS) $(DIVINCL) -DRC_INVOKED -P -x c $< | $(WRC) $(WRCFLAGS) $(WRCEXTRA) -o $*.s
winemine: $(OBJS)
$(CC) -o winemine $(OBJS) $(DLL_LINK) $(LIBS)

View File

@ -27,10 +27,6 @@ depend: y.tab.h
@MAKE_RULES@
# Override resource compiler rules
.rc.s:
$(CPP) $(DEFS) $(OPTIONS) $(DIVINCL) -DRC_INVOKED -P -x c $< | $(WRC) $(WRCFLAGS) $(WRCEXTRA) -o $*.s
winhelp: $(OBJS)
$(CC) -o winhelp $(OBJS) $(DLL_LINK) $(LIBS)

View File

@ -3,6 +3,7 @@
*
*/
#include "windef.h"
#include "winuser.h"
#include "winnls.h"
#include "dlgs.h"

View File

@ -19,7 +19,7 @@ EXTRASUBDIRS = \
winapi_check/win32 \
wineconf.libs
all: $(PROGRAMS)
all: $(PROGRAMS) wrc
@MAKE_RULES@

View File

@ -1,5 +1,8 @@
Makefile
lex.ppl.c
lex.yy.c
ppy.tab.c
ppy.tab.h
wrc
y.tab.c
y.tab.h

View File

@ -1,3 +1,18 @@
---------------------------------------------------------------------------
Version 1.1.0 (01-May-2000)
Bertho Stultiens <bertho@akhphd.au.dk>
- Implemented a new preprocessor that is (nearly) ANSI-C compliant. The
old parser has been stripped from the old preprocessor-code which
cleaned up both resource-scanner and -parser.
- Standard defines have been introduced (see README.wrc)
- Both preprocessor- and resource-scanner have been optimized slightly
so that no backing up is required (one char lookahead is enough).
- Filename-scanning has been cleaned up, though not perfect yet.
- User-type resources are compatible now.
- Line-continuation in strings is corrected so that it does not
introduce a newline in the output.
---------------------------------------------------------------------------
Version 1.0.18 (28-Dec-1999)

View File

@ -3,6 +3,8 @@ TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
LEXOPT = -Cf #-w -b
YACCOPT = #-v
PROGRAMS = wrc@PROGEXT@
MODULE = none
@ -17,12 +19,12 @@ C_SRCS = \
wrc.c \
writeres.c
EXTRA_SRCS = parser.y parser.l
EXTRA_OBJS = y.tab.o lex.yy.o
EXTRA_SRCS = parser.y parser.l ppl.l ppy.y ppy.tab.c lex.ppl.c
EXTRA_OBJS = y.tab.o lex.yy.o ppy.tab.o lex.ppl.o
all: $(PROGRAMS)
depend: y.tab.h
depend: y.tab.h ppy.tab.h ppy.tab.c lex.ppl.c
@MAKE_RULES@
@ -30,12 +32,18 @@ wrc@PROGEXT@: $(OBJS)
$(CC) $(CFLAGS) -o wrc@PROGEXT@ $(OBJS) $(LEXLIB)
y.tab.c y.tab.h: parser.y
$(YACC) -d -t $(SRCDIR)/parser.y
$(YACC) $(YACCOPT) -d -t $(SRCDIR)/parser.y
ppy.tab.c ppy.tab.h: ppy.y
$(YACC) $(YACCOPT) -bppy -ppp -d -t $(SRCDIR)/ppy.y
lex.yy.c: parser.l
$(LEX) -8 $(SRCDIR)/parser.l
$(LEX) $(LEXOPT) -d -8 $(SRCDIR)/parser.l
lex.ppl.c: ppl.l
$(LEX) $(LEXOPT) -d -Ppp -8 -olex.ppl.c $(SRCDIR)/ppl.l
clean::
$(RM) y.tab.c y.tab.h lex.yy.c
$(RM) y.tab.c y.tab.h lex.yy.c ppy.tab.c ppy.tab.h lex.ppl.c ppy.output lex.backup y.output
### Dependencies:

View File

@ -1,14 +1,14 @@
Release 1.0.2 of wrc (20-Jun-1998), the wine resource compiler.
Release 1.1.0 of wrc (01-May-2000), the wine resource compiler.
See the file CHANGES for differences between the version and what has been
corrected in the current version.
Wrc features:
- source preprocessing
- full source preprocessing
- 16 and 32 bit support
- LANGUAGE support (32 bit only)
- almost all resource types are supported
- most resource types are supported
- enhanced expression capabilities and resource naming
- indirect loadable resources
- NE/PE resource directory generation
@ -34,13 +34,15 @@ Usage: wrc [options...] [infile[.rc|.res]]
-d n Set debug level to 'n'
-D id[=val] Define preprocessor identifier id=val
-e Disable recognition of win32 keywords in 16bit compile
-E Preprocess only
-g Add symbols to the global c namespace
-h Also generate a .h file
-H file Same as -h but written to file
-I path Set include search dir to path (multiple -I allowed)
-l lan Set default language to lan (default is neutral {0})
-l lan Set default language to lan (default is neutral {0, 0})
-L Leave case of embedded filenames as is
-n Do not generate .s file
-N Do not preprocess input
-o file Output to file (default is infile.[res|s|h]
-p prefix Give a prefix for the generated names
-r Create binary .res file (compile only)
@ -57,6 +59,9 @@ Debug level 'n' is a bitmask with following meaning:
* 0x01 Tell which resource is parsed (verbose mode)
* 0x02 Dump internal structures
* 0x04 Create a parser trace (yydebug=1)
* 0x08 Preprocessor messages
* 0x10 Preprocessor lex messages
* 0x20 Preprocessor yacc trace
The -o option only applies to the final destination file, which is
in case of normal compile a .s file. You must use the '-H header.h'
@ -67,10 +72,12 @@ with -o and/or -H, then the output is written to "wrc.tab.[sh]"
Preprocessing
-------------
The build-in preprocessor is not a full implementation of the C counterpart.
Wrc does not understand function-type macros. These are discarded as they
are scanned. This will be a future project. Wrc does understand these:
#define
The preprocessor is a fully operational C preprocessor. It handles all
directives supported by ANSI-C. It also includes some additions from
gcc/egcs.
Wrc understands these directives:
#define (both simple and macro)
#undef
#if
#ifdef
#ifndef
@ -78,13 +85,42 @@ are scanned. This will be a future project. Wrc does understand these:
#else
#endif
#error
#warning
#line
#
#pragma (ignored)
#ident (ignored)
Also 'defined' is supported as operator (both with and without parenthesis).
'#if' expressions can be anything valid that evaluates to an integer
expression (where 0 is false and anything else is true). Others (#pragma,
#line) are ignored. A special case '#' generates an error. This is due to
the implementation to enable generation of errors on preprocessing and will
be improved in the future.
The extensions include '#'-line directives.
Not handled at the moment are variable argument macros. They are parsed,
but not expanded properly. This will be corrected in the future.
The preprocessor handles the special defines and aditionally defines an
extra set of defines:
Define | Value | Comment
-----------+-------------------+---------------
RC_INVOKED | 1 | Always defined
__FLAT__ | 1 | Only defined if win32 compile
__WIN32__ | 1 | Only defined if win32 compile
__FILE__ | "..." | Current filename as string
__LINE__ | nnn | Current linenumber as integer
__TIME__ | "23:59:59" | Timestring of compilation
__DATE__ | "May 1 2000" | Datestring of compilation
__WRC__  1 | Wrc's major version
__WRC_MINOR__ | 1 | Wrc's minor version
__WRC_MICRO__ | 0 | Wrc's minor version
__WRC_PATCH__ | 0 | Alias of __WRC_MICRO__
Include-files are not read twice if they are protected with this scheme:
#ifndef SOME_DEFINE
#define SOME_DEFINE
...
#endif
This strategy has been borrowed from gcc/egcs and results in significantly
reduced preprocessing times (20..30%). There must not be any junk before
the first #ifndef and not after the last #endif; comments and whitespace
excepted. Wrc will check the existance of the define prior to inclusion to
detect "#undef SOME_DEFINE" (notably poppack.h) and act accordingly.
16 and 32 bit support
@ -115,35 +151,15 @@ statement before (and evt. after) the code in the resource file.
Resource types supported
------------------------
All types are supported except for:
- FONT
- MESSAGETABLE
- extensions like TOOLBAR and the like (is this a user-type?)
- FONT (RT_FONT, RT_FONTDIR)
- MESSAGETABLE (RT_MESSAGETABLE)
- Animated cursors/icons (RT_ANIICON, RT_ANICURSOR)
- RT_VXD
- RT_PLUGPLAY
These types will be implemented as soon as I get a proper specification of
the layout.
Note: Usertype resources with character strings as types have a different
layout and do not accept expressions when a numerical type is specified. The
must be enclosed in double quotes. These are examples of valid usertype
resources:
MyName "MyType" mydata.bin
MyName 12345 mydata.bin
MyName "MyType" "mydata.bin"
MyName 12345 "mydata.bin"
MyName "MyType"
{
..., data, ...
}
or
MyName 12345
{
..., data, ...
}
Expression capabilities and resource names
------------------------------------------
@ -152,22 +168,19 @@ expects a number (except usertype type). Operators supported:
() parenthesis
* multiply
/ divide
+ add
+ plus/add
- minus/substract
| binary or
& binary and
~ binary not (unary operator though)
NOT ... (sigh)
Minus (-) can both be unary and binary. The NOT operator is (primarily)
used to disable window styles but I strongly suggest to refrain from using
this operator.
There is a shift/reduce conflict on the unary minus, but this is not
problematic. I was too lazy to make a new expression parser (next version or
so). Unary plus (+) would cause another confilct, so I let it out for now.
Plus (+) and minus (-) can both be unary and binary. The NOT operator is
(primarily) used to disable window styles but I strongly suggest to refrain
from using this operator.
Resource names can be both numerical (expressions) and character typed. Wrc
does supports this insane (deep sigh) construct:
does support this insane (deep sigh) construct:
MENU MENU
{
@ -250,9 +263,8 @@ though):
- No documentation ('wrc -?' gives command-line options though)
- grep for FIXME in the source
- Memory options are wrong under some conditions. There seems to be a
different action for win32 and win16.
- User-type resources have slightly different layout.
- Filename scanning is still hopeless.
different action for win32 and win16
- Little/big-endian
Reporting bugs and patches
--------------------------

View File

@ -293,3 +293,4 @@ style_t *new_style(DWORD or_mask, DWORD and_mask)
st->and_mask = and_mask;
return st;
}

View File

@ -9,8 +9,7 @@
/* From parser.y */
extern int yydebug;
extern int indialog; /* Set when parsing dialogs */
extern int want_rscname; /* Set when a resource's name is required */
extern int want_nl; /* Set when getting line-numers */
int yyparse(void);
void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico);
@ -19,15 +18,10 @@ void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur);
/* From parser.l */
extern FILE *yyin;
extern char *yytext;
extern int line_number;
extern int char_number;
extern int yy_flex_debug;
int yylex(void);
void set_yywf(void);
void set_pp_ignore(int state);
void push_to(int start);
void pop_start(void);
void strip_extern(void);
void strip_til_semicolon(void);
void strip_til_parenthesis(void);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1407
tools/wrc/ppl.l Normal file

File diff suppressed because it is too large Load Diff

624
tools/wrc/ppy.y Normal file
View File

@ -0,0 +1,624 @@
/*
* Wrc preprocessor syntax analysis
*
* Copyright 1999-2000 Bertho A. Stultiens (BS)
*
* 24-Apr-2000 BS Restructured the lot to fit the new scanner
* and reintegrate into the wine-tree.
* 01-Jan-2000 BS FIXME: win16 preprocessor calculates with
* 16 bit ints and overflows...?
* 26-Dec-1999 BS Started this file
*
*/
%{
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include "utils.h"
#include "newstruc.h"
#include "wrc.h"
#include "preproc.h"
#define UNARY_OP(r, v, OP) \
switch(v.type) \
{ \
case cv_sint: r.val.si = OP v.val.si; break; \
case cv_uint: r.val.ui = OP v.val.ui; break; \
case cv_slong: r.val.sl = OP v.val.sl; break; \
case cv_ulong: r.val.ul = OP v.val.ul; break; \
case cv_sll: r.val.sll = OP v.val.sll; break; \
case cv_ull: r.val.ull = OP v.val.ull; break; \
}
#define cv_signed(v) ((v.type & FLAG_SIGNED) != 0)
#define BIN_OP_INT(r, v1, v2, OP) \
r.type = v1.type; \
if(cv_signed(v1) && cv_signed(v2)) \
r.val.si = v1.val.si OP v2.val.si; \
else if(cv_signed(v1) && !cv_signed(v2)) \
r.val.si = v1.val.si OP v2.val.ui; \
else if(!cv_signed(v1) && cv_signed(v2)) \
r.val.ui = v1.val.ui OP v2.val.si; \
else \
r.val.ui = v1.val.ui OP v2.val.ui;
#define BIN_OP_LONG(r, v1, v2, OP) \
r.type = v1.type; \
if(cv_signed(v1) && cv_signed(v2)) \
r.val.sl = v1.val.sl OP v2.val.sl; \
else if(cv_signed(v1) && !cv_signed(v2)) \
r.val.sl = v1.val.sl OP v2.val.ul; \
else if(!cv_signed(v1) && cv_signed(v2)) \
r.val.ul = v1.val.ul OP v2.val.sl; \
else \
r.val.ul = v1.val.ul OP v2.val.ul;
#define BIN_OP_LONGLONG(r, v1, v2, OP) \
r.type = v1.type; \
if(cv_signed(v1) && cv_signed(v2)) \
r.val.sll = v1.val.sll OP v2.val.sll; \
else if(cv_signed(v1) && !cv_signed(v2)) \
r.val.sll = v1.val.sll OP v2.val.ull; \
else if(!cv_signed(v1) && cv_signed(v2)) \
r.val.ull = v1.val.ull OP v2.val.sll; \
else \
r.val.ull = v1.val.ull OP v2.val.ull;
#define BIN_OP(r, v1, v2, OP) \
switch(v1.type & SIZE_MASK) \
{ \
case SIZE_INT: BIN_OP_INT(r, v1, v2, OP); break; \
case SIZE_LONG: BIN_OP_LONG(r, v1, v2, OP); break; \
case SIZE_LONGLONG: BIN_OP_LONGLONG(r, v1, v2, OP); break; \
default: internal_error(__FILE__, __LINE__, "Invalid type indicator (0x%04x)", v1.type); \
}
/*
* Prototypes
*/
static int boolean(cval_t *v);
static void promote_equal_size(cval_t *v1, cval_t *v2);
static void cast_to_sint(cval_t *v);
static void cast_to_uint(cval_t *v);
static void cast_to_slong(cval_t *v);
static void cast_to_ulong(cval_t *v);
static void cast_to_sll(cval_t *v);
static void cast_to_ull(cval_t *v);
static marg_t *new_marg(char *str, def_arg_t type);
static marg_t *add_new_marg(char *str, def_arg_t type);
static int marg_index(char *id);
static mtext_t *new_mtext(char *str, int idx, def_exp_t type);
static mtext_t *combine_mtext(mtext_t *tail, mtext_t *mtp);
static char *merge_text(char *s1, char *s2);
/*
* Local variables
*/
static marg_t **macro_args; /* Macro parameters array while parsing */
static int nmacro_args;
%}
%union{
int sint;
unsigned int uint;
long slong;
unsigned long ulong;
wrc_sll_t sll;
wrc_ull_t ull;
int *iptr;
char *cptr;
cval_t cval;
marg_t *marg;
mtext_t *mtext;
}
%token tIF tIFDEF tIFNDEF tELSE tELIF tENDIF tDEFINED tNL
%token tINCLUDE tLINE tGCCLINE tERROR tWARNING tPRAGMA tPPIDENT
%token tUNDEF tMACROEND tCONCAT tELIPSIS tSTRINGIZE
%token <cptr> tIDENT tLITERAL tMACRO tDEFINE
%token <cptr> tDQSTRING tSQSTRING tIQSTRING
%token <uint> tUINT
%token <sint> tSINT
%token <ulong> tULONG
%token <slong> tSLONG
%token <ull> tULONGLONG
%token <sll> tSLONGLONG
%right '?' ':'
%left tLOGOR
%left tLOGAND
%left '|'
%left '^'
%left '&'
%left tEQ tNE
%left '<' tLTE '>' tGTE
%left tLSHIFT tRSHIFT
%left '+' '-'
%left '*' '/'
%right '~' '!'
%type <cval> pp_expr
%type <marg> emargs margs
%type <mtext> opt_mtexts mtexts mtext
%type <sint> nums allmargs
%type <cptr> opt_text text
/*
**************************************************************************
* The parser starts here
**************************************************************************
*/
%%
pp_file : /* Empty */
| pp_file preprocessor
;
preprocessor
: tINCLUDE tDQSTRING tNL { do_include($2, 1); }
| tINCLUDE tIQSTRING tNL { do_include($2, 0); }
| tIF pp_expr tNL { next_if_state(boolean(&$2)); }
| tIFDEF tIDENT tNL { next_if_state(pplookup($2) != NULL); free($2); }
| tIFNDEF tIDENT tNL {
int t = pplookup($2) == NULL;
if(include_state == 0 && t && !seen_junk)
{
include_state = 1;
include_ppp = $2;
include_ifdepth = get_if_depth();
}
else if(include_state != 1)
{
include_state = -1;
free($2);
}
else
free($2);
next_if_state(t);
if(debuglevel & DEBUGLEVEL_PPMSG)
fprintf(stderr, "tIFNDEF: %s:%d: include_state=%d, include_ppp='%s', include_ifdepth=%d\n", input_name, line_number, include_state, include_ppp, include_ifdepth);
}
| tELIF pp_expr tNL {
if_state_t s = pop_if();
switch(s)
{
case if_true:
case if_elif:
push_if(if_elif);
break;
case if_false:
push_if(boolean(&$2) ? if_true : if_false);
break;
case if_ignore:
push_if(if_ignore);
break;
case if_elsetrue:
case if_elsefalse:
pperror("#elif cannot follow #else");
default:
internal_error(__FILE__, __LINE__, "Invalid if_state (%d) in #elif directive", s);
}
}
| tELSE tNL {
if_state_t s = pop_if();
switch(s)
{
case if_true:
push_if(if_elsefalse);
break;
case if_elif:
push_if(if_elif);
break;
case if_false:
push_if(if_elsetrue);
break;
case if_ignore:
push_if(if_ignore);
break;
case if_elsetrue:
case if_elsefalse:
pperror("#else clause already defined");
default:
internal_error(__FILE__, __LINE__, "Invalid if_state (%d) in #else directive", s);
}
}
| tENDIF tNL {
pop_if();
if(include_ifdepth == get_if_depth() && include_state == 1)
{
include_state = 2;
seen_junk = 0;
}
else if(include_state != 1)
{
include_state = -1;
}
if(debuglevel & DEBUGLEVEL_PPMSG)
fprintf(stderr, "tENDIF: %s:%d: include_state=%d, include_ppp='%s', include_ifdepth=%d\n", input_name, line_number, include_state, include_ppp, include_ifdepth);
}
| tUNDEF tIDENT tNL { del_define($2); free($2); }
| tDEFINE opt_text tNL { add_define($1, $2); }
| tMACRO res_arg allmargs tMACROEND opt_mtexts tNL {
add_macro($1, macro_args, nmacro_args, $5);
}
| tLINE tSINT tDQSTRING tNL { fprintf(ppout, "# %d %s\n", $2 - 1, $3); free($3); }
| tGCCLINE tDQSTRING nums tNL { fprintf(ppout, "# %d %s\n", $3 - 1, $2); free($2); }
| tGCCLINE tNL /* The null-token */
| tERROR opt_text tNL { pperror("#error directive: '%s'", $2); if($2) free($2); }
| tWARNING opt_text tNL { ppwarning("#warning directive: '%s'", $2); if($2) free($2); }
| tPRAGMA opt_text tNL { if(pedantic) ppwarning("#pragma ignored (arg: '%s')", $2); if($2) free($2); }
| tPPIDENT opt_text tNL { if(pedantic) ppwarning("#ident ignored (arg: '%s')", $2); if($2) free($2); }
/*| tNL*/
;
opt_text: /* Empty */ { $$ = NULL; }
| text { $$ = $1; }
;
text : tLITERAL { $$ = $1; }
| tDQSTRING { $$ = $1; }
| tSQSTRING { $$ = $1; }
| text tLITERAL { $$ = merge_text($1, $2); }
| text tDQSTRING { $$ = merge_text($1, $2); }
| text tSQSTRING { $$ = merge_text($1, $2); }
;
res_arg : /* Empty */ { macro_args = NULL; nmacro_args = 0; }
;
nums : tSINT { $$ = $1; }
| nums tSINT /* Ignore */
;
allmargs: /* Empty */ { $$ = 0; macro_args = NULL; nmacro_args = 0; }
| emargs { $$ = nmacro_args; }
;
emargs : margs { $$ = $1; }
| margs ',' tELIPSIS { $$ = add_new_marg(NULL, arg_list); nmacro_args *= -1; }
;
margs : margs ',' tIDENT { $$ = add_new_marg($3, arg_single); }
| tIDENT { $$ = add_new_marg($1, arg_single); }
;
opt_mtexts
: /* Empty */ { $$ = NULL; }
| mtexts {
for($$ = $1; $$ && $$->prev; $$ = $$->prev)
;
}
;
mtexts : mtext { $$ = $1; }
| mtexts mtext { $$ = combine_mtext($1, $2); }
;
mtext : tLITERAL { $$ = new_mtext($1, 0, exp_text); }
| tDQSTRING { $$ = new_mtext($1, 0, exp_text); }
| tSQSTRING { $$ = new_mtext($1, 0, exp_text); }
| tCONCAT { $$ = new_mtext(NULL, 0, exp_concat); }
| tSTRINGIZE tIDENT {
int mat = marg_index($2);
if(mat < 0)
pperror("Stringification identifier must be an argument parameter");
$$ = new_mtext(NULL, mat, exp_stringize);
}
| tIDENT {
int mat = marg_index($1);
if(mat >= 0)
$$ = new_mtext(NULL, mat, exp_subst);
else
$$ = new_mtext($1, 0, exp_text);
}
;
pp_expr : tSINT { $$.type = cv_sint; $$.val.si = $1; }
| tUINT { $$.type = cv_uint; $$.val.ui = $1; }
| tSLONG { $$.type = cv_slong; $$.val.sl = $1; }
| tULONG { $$.type = cv_ulong; $$.val.ul = $1; }
| tSLONGLONG { $$.type = cv_sll; $$.val.sl = $1; }
| tULONGLONG { $$.type = cv_ull; $$.val.ul = $1; }
| tDEFINED tIDENT { $$.type = cv_sint; $$.val.si = pplookup($2) != NULL; }
| tDEFINED '(' tIDENT ')' { $$.type = cv_sint; $$.val.si = pplookup($3) != NULL; }
| tIDENT { $$.type = cv_sint; $$.val.si = 0; }
| pp_expr tLOGOR pp_expr { $$.type = cv_sint; $$.val.si = boolean(&$1) || boolean(&$3); }
| pp_expr tLOGAND pp_expr { $$.type = cv_sint; $$.val.si = boolean(&$1) && boolean(&$3); }
| pp_expr tEQ pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, ==) }
| pp_expr tNE pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, !=) }
| pp_expr '<' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, <) }
| pp_expr '>' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, >) }
| pp_expr tLTE pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, <=) }
| pp_expr tGTE pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, >=) }
| pp_expr '+' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, +) }
| pp_expr '-' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, -) }
| pp_expr '^' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, ^) }
| pp_expr '&' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, &) }
| pp_expr '|' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, |) }
| pp_expr '*' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, *) }
| pp_expr '/' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, /) }
| pp_expr tLSHIFT pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, <<) }
| pp_expr tRSHIFT pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, >>) }
| '+' pp_expr { $$ = $2; }
| '-' pp_expr { UNARY_OP($$, $2, -) }
| '~' pp_expr { UNARY_OP($$, $2, ~) }
| '!' pp_expr { $$.type = cv_sint; $$.val.si = !boolean(&$2) }
| '(' pp_expr ')' { $$ = $2; }
| pp_expr '?' pp_expr ':' pp_expr { $$ = boolean(&$1) ? $3 : $5; }
;
%%
/*
**************************************************************************
* Support functions
**************************************************************************
*/
static void cast_to_sint(cval_t *v)
{
switch(v->type)
{
case cv_sint: break;
case cv_uint: break;
case cv_slong: v->val.si = v->val.sl; break;
case cv_ulong: v->val.si = v->val.ul; break;
case cv_sll: v->val.si = v->val.sll; break;
case cv_ull: v->val.si = v->val.ull; break;
}
v->type = cv_sint;
}
static void cast_to_uint(cval_t *v)
{
switch(v->type)
{
case cv_sint: break;
case cv_uint: break;
case cv_slong: v->val.ui = v->val.sl; break;
case cv_ulong: v->val.ui = v->val.ul; break;
case cv_sll: v->val.ui = v->val.sll; break;
case cv_ull: v->val.ui = v->val.ull; break;
}
v->type = cv_uint;
}
static void cast_to_slong(cval_t *v)
{
switch(v->type)
{
case cv_sint: v->val.sl = v->val.si; break;
case cv_uint: v->val.sl = v->val.ui; break;
case cv_slong: break;
case cv_ulong: break;
case cv_sll: v->val.sl = v->val.sll; break;
case cv_ull: v->val.sl = v->val.ull; break;
}
v->type = cv_slong;
}
static void cast_to_ulong(cval_t *v)
{
switch(v->type)
{
case cv_sint: v->val.ul = v->val.si; break;
case cv_uint: v->val.ul = v->val.ui; break;
case cv_slong: break;
case cv_ulong: break;
case cv_sll: v->val.ul = v->val.sll; break;
case cv_ull: v->val.ul = v->val.ull; break;
}
v->type = cv_ulong;
}
static void cast_to_sll(cval_t *v)
{
switch(v->type)
{
case cv_sint: v->val.sll = v->val.si; break;
case cv_uint: v->val.sll = v->val.ui; break;
case cv_slong: v->val.sll = v->val.sl; break;
case cv_ulong: v->val.sll = v->val.ul; break;
case cv_sll: break;
case cv_ull: break;
}
v->type = cv_sll;
}
static void cast_to_ull(cval_t *v)
{
switch(v->type)
{
case cv_sint: v->val.ull = v->val.si; break;
case cv_uint: v->val.ull = v->val.ui; break;
case cv_slong: v->val.ull = v->val.sl; break;
case cv_ulong: v->val.ull = v->val.ul; break;
case cv_sll: break;
case cv_ull: break;
}
v->type = cv_ull;
}
static void promote_equal_size(cval_t *v1, cval_t *v2)
{
#define cv_sizeof(v) ((int)(v->type & SIZE_MASK))
int s1 = cv_sizeof(v1);
int s2 = cv_sizeof(v2);
#undef cv_sizeof
if(s1 == s2)
return;
else if(s1 > s2)
{
switch(v1->type)
{
case cv_sint: cast_to_sint(v2); break;
case cv_uint: cast_to_uint(v2); break;
case cv_slong: cast_to_slong(v2); break;
case cv_ulong: cast_to_ulong(v2); break;
case cv_sll: cast_to_sll(v2); break;
case cv_ull: cast_to_ull(v2); break;
}
}
else
{
switch(v2->type)
{
case cv_sint: cast_to_sint(v1); break;
case cv_uint: cast_to_uint(v1); break;
case cv_slong: cast_to_slong(v1); break;
case cv_ulong: cast_to_ulong(v1); break;
case cv_sll: cast_to_sll(v1); break;
case cv_ull: cast_to_ull(v1); break;
}
}
}
static int boolean(cval_t *v)
{
switch(v->type)
{
case cv_sint: return v->val.si != (int)0;
case cv_uint: return v->val.ui != (unsigned int)0;
case cv_slong: return v->val.sl != (long)0;
case cv_ulong: return v->val.ul != (unsigned long)0;
case cv_sll: return v->val.sll != (wrc_sll_t)0;
case cv_ull: return v->val.ull != (wrc_ull_t)0;
}
return 0;
}
static marg_t *new_marg(char *str, def_arg_t type)
{
marg_t *ma = (marg_t *)xmalloc(sizeof(marg_t));
ma->arg = str;
ma->type = type;
return ma;
}
static marg_t *add_new_marg(char *str, def_arg_t type)
{
marg_t *ma = new_marg(str, type);
nmacro_args++;
macro_args = (marg_t **)xrealloc(macro_args, nmacro_args * sizeof(macro_args[0]));
macro_args[nmacro_args-1] = ma;
return ma;
}
static int marg_index(char *id)
{
int t;
for(t = 0; t < nmacro_args; t++)
{
if(!strcmp(id, macro_args[t]->arg))
break;
}
return t < nmacro_args ? t : -1;
}
static mtext_t *new_mtext(char *str, int idx, def_exp_t type)
{
mtext_t *mt = (mtext_t *)xmalloc(sizeof(mtext_t));
if(str == NULL)
mt->subst.argidx = idx;
else
mt->subst.text = str;
mt->type = type;
return mt;
}
static mtext_t *combine_mtext(mtext_t *tail, mtext_t *mtp)
{
if(!tail)
return mtp;
if(!mtp)
return tail;
if(tail->type == exp_text && mtp->type == exp_text)
{
tail->subst.text = xrealloc(tail->subst.text, strlen(tail->subst.text)+strlen(mtp->subst.text)+1);
strcat(tail->subst.text, mtp->subst.text);
free(mtp->subst.text);
free(mtp);
return tail;
}
if(tail->type == exp_concat && mtp->type == exp_concat)
{
free(mtp);
return tail;
}
if(tail->type == exp_concat && mtp->type == exp_text)
{
int len = strlen(mtp->subst.text);
while(len)
{
/* FIXME: should delete space from head of string */
if(isspace(mtp->subst.text[len-1]))
mtp->subst.text[--len] = '\0';
else
break;
}
if(!len)
{
free(mtp->subst.text);
free(mtp);
return tail;
}
}
if(tail->type == exp_text && mtp->type == exp_concat)
{
int len = strlen(tail->subst.text);
while(len)
{
if(isspace(tail->subst.text[len-1]))
tail->subst.text[--len] = '\0';
else
break;
}
if(!len)
{
mtp->prev = tail->prev;
mtp->next = tail->next;
if(tail->prev)
tail->prev->next = mtp;
free(tail->subst.text);
free(tail);
return mtp;
}
}
tail->next = mtp;
mtp->prev = tail;
return mtp;
}
static char *merge_text(char *s1, char *s2)
{
int l1 = strlen(s1);
int l2 = strlen(s2);
s1 = xrealloc(s1, l1+l2+1);
memcpy(s1+l1, s2, l2+1);
free(s2);
return s1;
}

View File

@ -8,48 +8,46 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "wrc.h"
#include "utils.h"
#include "preproc.h"
#include "parser.h"
extern void set_pp_ignore(int); /* From parser.l */
static char *current_define;
#define HASHKEY 2039
static struct pp_entry *pp_defines[HASHKEY];
static pp_entry_t *pp_defines[HASHKEY];
#define MAXIFSTACK 64
static struct if_state ifstack[MAXIFSTACK];
static int ifstackidx = 0;
static if_state_t if_stack[MAXIFSTACK];
static int if_stack_idx = 0;
#if 0
void pp_status(void) __attribute__((destructor));
void pp_status(void)
{
int i;
int sum;
int total = 0;
struct pp_entry *ppp;
pp_entry_t *ppp;
printf("Defines statistics:\n");
fprintf(stderr, "Defines statistics:\n");
for(i = 0; i < HASHKEY; i++)
{
sum = 0;
for(ppp = pp_defines[i]; ppp; ppp = ppp->next)
sum++;
total += sum;
printf("%4d, %3d\n", i, sum);
fprintf(stderr, "%4d, %3d\n", i, sum);
}
printf("Total defines: %d\n", total);
fprintf(stderr, "Total defines: %d\n", total);
}
#pragma exit pp_status
#endif
/* Don't comment on the hash, its primitive but functional... */
int pp_hash(char *str)
int pphash(char *str)
{
int sum = 0;
while(*str)
@ -57,11 +55,12 @@ int pp_hash(char *str)
return sum % HASHKEY;
}
struct pp_entry *pp_lookup(char *ident)
pp_entry_t *pplookup(char *ident)
{
int index = pp_hash(ident);
struct pp_entry *ppp;
for(ppp = pp_defines[index]; ppp; ppp = ppp->next)
int idx = pphash(ident);
pp_entry_t *ppp;
for(ppp = pp_defines[idx]; ppp; ppp = ppp->next)
{
if(!strcmp(ident, ppp->ident))
return ppp;
@ -69,29 +68,44 @@ struct pp_entry *pp_lookup(char *ident)
return NULL;
}
void set_define(char *name)
{
current_define = xstrdup(name);
}
void del_define(char *name)
{
int index;
struct pp_entry *ppp;
int idx;
pp_entry_t *ppp;
if((ppp = pp_lookup(name)) == NULL)
if((ppp = pplookup(name)) == NULL)
{
if(pedantic)
yywarning("%s was not defined", name);
return;
}
index = pp_hash(name);
if(pp_defines[index] == ppp)
if(ppp->iep)
{
pp_defines[index] = ppp->next;
if(pp_defines[index])
pp_defines[index]->prev = NULL;
if(debuglevel & DEBUGLEVEL_PPMSG)
fprintf(stderr, "del_define: %s:%d: includelogic removed, include_ppp='%s', file=%s\n", input_name, line_number, name, ppp->iep->filename);
if(ppp->iep == includelogiclist)
{
includelogiclist = ppp->iep->next;
if(includelogiclist)
includelogiclist->prev = NULL;
}
else
{
ppp->iep->prev->next = ppp->iep->next;
if(ppp->iep->next)
ppp->iep->next->prev = ppp->iep->prev;
}
free(ppp->iep->filename);
free(ppp->iep);
}
idx = pphash(name);
if(pp_defines[idx] == ppp)
{
pp_defines[idx] = ppp->next;
if(pp_defines[idx])
pp_defines[idx]->prev = NULL;
}
else
{
@ -99,54 +113,128 @@ void del_define(char *name)
if(ppp->next)
ppp->next->prev = ppp->prev;
}
free(ppp);
if(debuglevel & DEBUGLEVEL_PPMSG)
printf("Deleted (%s, %d) <%s>\n", input_name, line_number, name);
}
void add_define(char *text)
pp_entry_t *add_define(char *def, char *text)
{
int len;
char *cptr;
int index = pp_hash(current_define);
struct pp_entry *ppp;
if(pp_lookup(current_define) != NULL)
int idx = pphash(def);
pp_entry_t *ppp;
if((ppp = pplookup(def)) != NULL)
{
if(pedantic)
yywarning("Redefinition of %s", current_define);
del_define(current_define);
yywarning("Redefinition of %s\n\tPrevious definition: %s:%d", def, ppp->filename, ppp->linenumber);
del_define(def);
}
ppp = (struct pp_entry *)xmalloc(sizeof(struct pp_entry));
ppp->ident = current_define;
ppp->subst = xstrdup(text);
ppp->next = pp_defines[index];
pp_defines[index] = ppp;
ppp = (pp_entry_t *)xmalloc(sizeof(pp_entry_t));
ppp->ident = def;
ppp->type = def_define;
ppp->subst.text = text;
ppp->filename = input_name ? xstrdup(input_name) : "<internal or cmdline>";
ppp->linenumber = input_name ? line_number : 0;
ppp->next = pp_defines[idx];
pp_defines[idx] = ppp;
if(ppp->next)
ppp->next->prev = ppp;
/* Strip trailing white space from subst text */
len = strlen(ppp->subst);
while(len && strchr(" \t\r\n", ppp->subst[len-1]))
if(text)
{
ppp->subst[--len] = '\0';
}
/* Strip leading white space from subst text */
for(cptr = ppp->subst; *cptr && strchr(" \t\r", *cptr); cptr++)
/* Strip trailing white space from subst text */
len = strlen(text);
while(len && strchr(" \t\r\n", text[len-1]))
{
text[--len] = '\0';
}
/* Strip leading white space from subst text */
for(cptr = text; *cptr && strchr(" \t\r", *cptr); cptr++)
;
if(ppp->subst != cptr)
memmove(ppp->subst, cptr, strlen(cptr)+1);
if(yydebug)
printf("Added (%s, %d) <%s> to <%s>\n", input_name, line_number, ppp->ident, ppp->subst);
if(text != cptr)
memmove(text, cptr, strlen(cptr)+1);
}
if(debuglevel & DEBUGLEVEL_PPMSG)
printf("Added define (%s, %d) <%s> to <%s>\n", input_name, line_number, ppp->ident, text ? text : "(null)");
return ppp;
}
void add_cmdline_define(char *set)
pp_entry_t *add_cmdline_define(char *set)
{
char *cpy = xstrdup(set); /* Because gcc passes a R/O string */
char *cptr = strchr(cpy, '=');
if(cptr)
*cptr = '\0';
set_define(cpy);
add_define(cptr ? cptr+1 : "");
free(cpy);
return add_define(cpy, xstrdup(cptr ? cptr+1 : ""));
}
pp_entry_t *add_special_define(char *id)
{
pp_entry_t *ppp = add_define(xstrdup(id), xstrdup(""));
ppp->type = def_special;
return ppp;
}
pp_entry_t *add_macro(char *id, marg_t *args[], int nargs, mtext_t *exp)
{
int idx = pphash(id);
pp_entry_t *ppp;
if((ppp = pplookup(id)) != NULL)
{
if(pedantic)
yywarning("Redefinition of %s\n\tPrevious definition: %s:%d", id, ppp->filename, ppp->linenumber);
del_define(id);
}
ppp = (pp_entry_t *)xmalloc(sizeof(pp_entry_t));
ppp->ident = id;
ppp->type = def_macro;
ppp->margs = args;
ppp->nargs = nargs;
ppp->subst.mtext= exp;
ppp->filename = input_name ? xstrdup(input_name) : "<internal or cmdline>";
ppp->linenumber = input_name ? line_number : 0;
ppp->next = pp_defines[idx];
pp_defines[idx] = ppp;
if(ppp->next)
ppp->next->prev = ppp;
if(debuglevel & DEBUGLEVEL_PPMSG)
{
fprintf(stderr, "Added macro (%s, %d) <%s(%d)> to <", input_name, line_number, ppp->ident, nargs);
for(; exp; exp = exp->next)
{
switch(exp->type)
{
case exp_text:
fprintf(stderr, " \"%s\" ", exp->subst.text);
break;
case exp_stringize:
fprintf(stderr, " #(%d) ", exp->subst.argidx);
break;
case exp_concat:
fprintf(stderr, "##");
break;
case exp_subst:
fprintf(stderr, " <%d> ", exp->subst.argidx);
break;
}
}
fprintf(stderr, ">\n");
}
return ppp;
}
/*
*-------------------------------------------------------------------------
* Include management
*-------------------------------------------------------------------------
*/
#if defined(_Windows) || defined(__MSDOS__)
#define INCLUDESEPARATOR ";"
#else
@ -188,7 +276,7 @@ void add_include_path(char *path)
free(cpy);
}
FILE *open_include(const char *name, int search)
FILE *open_include(const char *name, int search, char **newpath)
{
char *cpy = xstrdup(name);
char *cptr;
@ -208,12 +296,15 @@ FILE *open_include(const char *name, int search)
if(search)
{
/* Search current dir and then -I path */
fp = fopen(name, "rt");
fp = fopen(cpy, "rt");
if(fp)
{
if(yydebug)
if(debuglevel & DEBUGLEVEL_PPMSG)
printf("Going to include <%s>\n", name);
free(cpy);
if(newpath)
*newpath = cpy;
else
free(cpy);
return fp;
}
}
@ -226,57 +317,166 @@ FILE *open_include(const char *name, int search)
strcat(path, "/");
strcat(path, cpy);
fp = fopen(path, "rt");
if(fp && yydebug)
if(fp && (debuglevel & DEBUGLEVEL_PPMSG))
printf("Going to include <%s>\n", path);
free(path);
if(fp)
{
if(newpath)
*newpath = path;
else
free(path);
free(cpy);
return fp;
}
free(path);
}
free(cpy);
if(newpath)
*newpath = NULL;
return NULL;
}
void push_if(int truecase, int wastrue, int nevertrue)
/*
*-------------------------------------------------------------------------
* #if, #ifdef, #ifndef, #else, #elif and #endif state management
*
* #if state transitions are made on basis of the current TOS and the next
* required state. The state transitions are required to housekeep because
* #if:s can be nested. The ignore case is activated to prevent output from
* within a false clause.
* Some special cases come from the fact that the #elif cases are not
* binary, but three-state. The problem is that all other elif-cases must
* be false when one true one has been found. A second problem is that the
* #else clause is a final clause. No extra #else:s may follow.
*
* The states mean:
* if_true Process input to output
* if_false Process input but no output
* if_ignore Process input but no output
* if_elif Process input but no output
* if_elsefalse Process input but no output
* if_elsettrue Process input to output
*
* The possible state-sequences are [state(stack depth)] (rest can be deduced):
* TOS #if 1 #else #endif
* if_true(n) if_true(n+1) if_elsefalse(n+1)
* if_false(n) if_ignore(n+1) if_ignore(n+1)
* if_elsetrue(n) if_true(n+1) if_elsefalse(n+1)
* if_elsefalse(n) if_ignore(n+1) if_ignore(n+1)
* if_elif(n) if_ignore(n+1) if_ignore(n+1)
* if_ignore(n) if_ignore(n+1) if_ignore(n+1)
*
* TOS #if 1 #elif 0 #else #endif
* if_true(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
* if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
* if_elsetrue(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
* if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
* if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
* if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
*
* TOS #if 0 #elif 1 #else #endif
* if_true(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
* if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
* if_elsetrue(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
* if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
* if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
* if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
*
*-------------------------------------------------------------------------
*/
static char *if_state_str[] = {
"if_false",
"if_true",
"if_elif",
"if_elsefalse",
"if_elsetrue",
"if_ignore"
};
void push_if(if_state_t s)
{
if(ifstackidx >= MAXIFSTACK-1)
internal_error(__FILE__, __LINE__, "#if stack overflow");
ifstack[ifstackidx].current = truecase && !wastrue;
ifstack[ifstackidx].hasbeentrue = wastrue;
ifstack[ifstackidx].nevertrue = nevertrue;
if(nevertrue || !(truecase && !wastrue))
set_pp_ignore(1);
if(yydebug)
printf("push_if: %d %d %d (%d %d %d)\n",
truecase,
wastrue,
nevertrue,
ifstack[ifstackidx].current,
ifstack[ifstackidx].hasbeentrue,
ifstack[ifstackidx].nevertrue);
ifstackidx++;
if(if_stack_idx >= MAXIFSTACK)
internal_error(__FILE__, __LINE__, "#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)", MAXIFSTACK);
if(debuglevel & DEBUGLEVEL_PPLEX)
fprintf(stderr, "Push if %s:%d: %s(%d) -> %s(%d)\n", input_name, line_number, if_state_str[if_state()], if_stack_idx, if_state_str[s], if_stack_idx+1);
if_stack[if_stack_idx++] = s;
switch(s)
{
case if_true:
case if_elsetrue:
break;
case if_false:
case if_elsefalse:
case if_elif:
case if_ignore:
push_ignore_state();
break;
}
}
int pop_if(void)
if_state_t pop_if(void)
{
if(ifstackidx <= 0)
yyerror("#endif without #if|#ifdef|#ifndef (#if stack underflow)");
ifstackidx--;
if(yydebug)
printf("pop_if: %d %d %d\n",
ifstack[ifstackidx].current,
ifstack[ifstackidx].hasbeentrue,
ifstack[ifstackidx].nevertrue);
if(ifstack[ifstackidx].nevertrue || !ifstack[ifstackidx].current)
set_pp_ignore(0);
return ifstack[ifstackidx].hasbeentrue || ifstack[ifstackidx].current;
if(if_stack_idx <= 0)
yyerror("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
switch(if_state())
{
case if_true:
case if_elsetrue:
break;
case if_false:
case if_elsefalse:
case if_elif:
case if_ignore:
pop_ignore_state();
break;
}
if(debuglevel & DEBUGLEVEL_PPLEX)
fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
input_name,
line_number,
if_state_str[if_state()],
if_stack_idx,
if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
if_stack_idx-1);
return if_stack[--if_stack_idx];
}
int isnevertrue_if(void)
if_state_t if_state(void)
{
return ifstackidx > 0 && ifstack[ifstackidx-1].nevertrue;
if(!if_stack_idx)
return if_true;
else
return if_stack[if_stack_idx-1];
}
void next_if_state(int i)
{
switch(if_state())
{
case if_true:
case if_elsetrue:
push_if(i ? if_true : if_false);
break;
case if_false:
case if_elsefalse:
case if_elif:
case if_ignore:
push_if(if_ignore);
break;
default:
internal_error(__FILE__, __LINE__, "Invalid if_state (%d) in #{if,ifdef,ifndef} directive", (int)if_state());
}
}
int get_if_depth(void)
{
return if_stack_idx;
}

View File

@ -6,30 +6,193 @@
#ifndef __WRC_PREPROC_H
#define __WRC_PREPROC_H
struct pp_entry {
struct pp_entry; /* forward */
/*
* Include logic
* A stack of files which are already included and
* are protected in the #ifndef/#endif way.
*/
typedef struct includelogicentry {
struct includelogicentry *next;
struct includelogicentry *prev;
struct pp_entry *ppp; /* The define which protects the file */
char *filename; /* The filename of the include */
} includelogicentry_t;
/*
* The arguments of a macrodefinition
*/
typedef enum {
arg_single,
arg_list
} def_arg_t;
typedef struct marg {
def_arg_t type; /* Normal or ... argument */
char *arg; /* The textual argument */
int nnl; /* Number of newlines in the text to subst */
} marg_t;
/*
* The expansiontext of a macro
*/
typedef enum {
exp_text, /* Simple text substitution */
exp_concat, /* Concat (##) operator requested */
exp_stringize, /* Stringize (#) operator requested */
exp_subst /* Substitute argument */
} def_exp_t;
typedef struct mtext {
struct mtext *next;
struct mtext *prev;
def_exp_t type;
union {
char *text;
int argidx; /* For exp_subst and exp_stringize reference */
} subst;
} mtext_t;
/*
* The define descriptor
*/
typedef enum {
def_none, /* Not-a-define; used as return value */
def_define, /* Simple defines */
def_macro, /* Macro defines */
def_special /* Special expansions like __LINE__ and __FILE__ */
} def_type_t;
typedef struct pp_entry {
struct pp_entry *next;
struct pp_entry *prev;
char *ident;
char *subst;
int expanding;
};
def_type_t type; /* Define or macro */
char *ident; /* The key */
marg_t **margs; /* Macro arguments array or NULL if none */
int nargs;
union {
mtext_t *mtext; /* The substitution sequence or NULL if none */
char *text;
} subst;
int expanding; /* Set when feeding substitution into the input */
char *filename; /* Filename where it was defined */
int linenumber; /* Linenumber where it was defined */
includelogicentry_t *iep; /* Points to the include it protects */
} pp_entry_t;
struct if_state {
int current;
int hasbeentrue;
int nevertrue;
};
struct pp_entry *pp_lookup(char *ident);
void set_define(char *name);
/*
* If logic
*/
#define MAXIFSTACK 64 /* If this isn't enough you should alter the source... */
typedef enum {
if_false,
if_true,
if_elif,
if_elsefalse,
if_elsetrue,
if_ignore
} if_state_t;
/*
* I assume that 'long long' exists in the compiler when it has a size
* of 8 or bigger. If not, then we revert to a simple 'long' for now.
* This should prevent most unexpected things with other compilers than
* gcc and egcs for now.
* In the future it should be possible to use another way, like a
* structure, so that we can emulate the MS compiler.
*/
#if defined(SIZEOF_LONGLONG) && SIZEOF_LONGLONG >= 8
typedef long long wrc_sll_t;
typedef unsigned long long wrc_ull_t;
#else
typedef long wrc_sll_t;
typedef unsigned long wrc_ull_t;
#endif
#define SIZE_CHAR 1
#define SIZE_SHORT 2
#define SIZE_INT 3
#define SIZE_LONG 4
#define SIZE_LONGLONG 5
#define SIZE_MASK 0x00ff
#define FLAG_SIGNED 0x0100
typedef enum {
#if 0
cv_schar = SIZE_CHAR + FLAG_SIGNED,
cv_uchar = SIZE_CHAR,
cv_sshort = SIZE_SHORT + FLAG_SIGNED,
cv_ushort = SIZE_SHORT,
#endif
cv_sint = SIZE_INT + FLAG_SIGNED,
cv_uint = SIZE_INT,
cv_slong = SIZE_LONG + FLAG_SIGNED,
cv_ulong = SIZE_LONG,
cv_sll = SIZE_LONGLONG + FLAG_SIGNED,
cv_ull = SIZE_LONGLONG
} ctype_t;
typedef struct cval {
ctype_t type;
union {
#if 0
signed char sc; /* Explicitely signed because compilers are stupid */
unsigned char uc;
short ss;
unsigned short us;
#endif
int si;
unsigned int ui;
long sl;
unsigned long ul;
wrc_sll_t sll;
wrc_ull_t ull;
} val;
} cval_t;
pp_entry_t *pplookup(char *ident);
pp_entry_t *add_define(char *def, char *text);
pp_entry_t *add_cmdline_define(char *set);
pp_entry_t *add_special_define(char *id);
pp_entry_t *add_macro(char *ident, marg_t *args[], int nargs, mtext_t *exp);
void del_define(char *name);
void add_define(char *text);
void add_cmdline_define(char *set);
FILE *open_include(const char *name, int search);
FILE *open_include(const char *name, int search, char **newpath);
void add_include_path(char *path);
void push_if(int truecase, int wastrue, int nevertrue);
int pop_if(void);
int isnevertrue_if(void);
void push_if(if_state_t s);
void next_if_state(int);
if_state_t pop_if(void);
if_state_t if_state(void);
int get_if_depth(void);
/*
* From ppl.l
*/
extern FILE *ppin;
extern FILE *ppout;
extern char *pptext;
extern int pp_flex_debug;
int pplex(void);
void do_include(char *fname, int type);
void push_ignore_state(void);
void pop_ignore_state(void);
extern int include_state;
extern char *include_ppp;
extern char *include_filename;
extern int include_ifdepth;
extern int seen_junk;
extern includelogicentry_t *includelogiclist;
/*
* From ppy.y
*/
int ppparse(void);
extern int ppdebug;
#endif

View File

@ -17,8 +17,9 @@
#include "wrc.h"
#include "utils.h"
#include "parser.h"
#include "preproc.h"
#define WANT_NEAR_INDICATION
/* #define WANT_NEAR_INDICATION */
#ifdef WANT_NEAR_INDICATION
@ -33,22 +34,31 @@ void make_print(char *str)
}
#endif
static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
{
fprintf(stderr, "%s %s: %d, %d: ", t, input_name ? input_name : "stdin", line_number, char_number);
vfprintf(stderr, s, ap);
#ifdef WANT_NEAR_INDICATION
{
char *cpy;
if(n)
{
cpy = xstrdup(n);
make_print(cpy);
fprintf(stderr, " near '%s'", cpy);
free(cpy);
}
}
#endif
fprintf(stderr, "\n");
}
int yyerror(const char *s, ...)
{
va_list ap;
va_start(ap, s);
fprintf(stderr, "Error %s: %d, %d: ", input_name ? input_name : "stdin", line_number, char_number);
vfprintf(stderr, s, ap);
#ifdef WANT_NEAR_INDICATION
{
char *cpy = xstrdup(yytext);
make_print(cpy);
fprintf(stderr, " near '%s'\n", cpy);
free(cpy);
}
#else
fprintf(stderr, "\n");
#endif
generic_msg(s, "Error", yytext, ap);
va_end(ap);
exit(1);
return 1;
@ -58,22 +68,31 @@ int yywarning(const char *s, ...)
{
va_list ap;
va_start(ap, s);
fprintf(stderr, "Warning %s: %d, %d: ", input_name ? input_name : "stdin", line_number, char_number);
vfprintf(stderr, s, ap);
#ifdef WANT_NEAR_INDICATION
{
char *cpy = xstrdup(yytext);
make_print(cpy);
fprintf(stderr, " near '%s'\n", cpy);
free(cpy);
}
#else
fprintf(stderr, "\n");
#endif
generic_msg(s, "Warning", yytext, ap);
va_end(ap);
return 0;
}
int pperror(const char *s, ...)
{
va_list ap;
va_start(ap, s);
generic_msg(s, "Error", pptext, ap);
va_end(ap);
exit(1);
return 1;
}
int ppwarning(const char *s, ...)
{
va_list ap;
va_start(ap, s);
generic_msg(s, "Warning", pptext, ap);
va_end(ap);
return 0;
}
void internal_error(const char *file, int line, const char *s, ...)
{
va_list ap;
@ -156,6 +175,11 @@ void *xmalloc(size_t size)
{
error("Virtual memory exhausted.\n");
}
/*
* We set it to 0.
* This is *paramount* because we depend on it
* just about everywhere in the rest of the code.
*/
memset(res, 0, size);
return res;
}
@ -177,7 +201,10 @@ void *xrealloc(void *p, size_t size)
char *xstrdup(const char *str)
{
char *s = (char *)xmalloc(strlen(str)+1);
char *s;
assert(str != NULL);
s = (char *)xmalloc(strlen(str)+1);
return strcpy(s, str);
}

View File

@ -18,12 +18,14 @@ void *xmalloc(size_t);
void *xrealloc(void *, size_t);
char *xstrdup(const char *str);
int yyerror(const char *s, ...);
int yywarning(const char *s, ...);
void internal_error(const char *file, int line, const char *s, ...);
void error(const char *s, ...);
void warning(const char *s, ...);
void chat(const char *s, ...);
int pperror(const char *s, ...) __attribute__((format (printf, 1, 2)));
int ppwarning(const char *s, ...) __attribute__((format (printf, 1, 2)));
int yyerror(const char *s, ...) __attribute__((format (printf, 1, 2)));
int yywarning(const char *s, ...) __attribute__((format (printf, 1, 2)));
void internal_error(const char *file, int line, const char *s, ...) __attribute__((format (printf, 3, 4)));
void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
void warning(const char *s, ...) __attribute__((format (printf, 1, 2)));
void chat(const char *s, ...) __attribute__((format (printf, 1, 2)));
char *dup_basename(const char *name, const char *ext);
int string_compare(const string_t *s1, const string_t *s2);

View File

@ -3,6 +3,7 @@
* Copyright Martin von Loewis, 1994
* Copyrignt 1998 Bertho A. Stultiens (BS)
*
* 30-Apr-2000 BS - Integrated a new preprocessor (-E and -N)
* 20-Jun-1998 BS - Added -L option to prevent case conversion
* of embedded filenames.
*
@ -36,9 +37,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <signal.h>
#include "wrc.h"
#include "utils.h"
@ -59,13 +62,15 @@ char usage[] = "Usage: wrc [options...] [infile[.rc|.res]]\n"
" -d n Set debug level to 'n'\n"
" -D id[=val] Define preprocessor identifier id=val\n"
" -e Disable recognition of win32 keywords in 16bit compile\n"
" -E Preprocess only\n"
" -g Add symbols to the global c namespace\n"
" -h Also generate a .h file\n"
" -H file Same as -h but written to file\n"
" -I path Set include search dir to path (multiple -I allowed)\n"
" -l lan Set default language to lan (default is neutral {0})\n"
" -l lan Set default language to lan (default is neutral {0, 0})\n"
" -L Leave case of embedded filenames as is\n"
" -n Do not generate .s file\n"
" -N Do not preprocess input\n"
" -o file Output to file (default is infile.[res|s|h]\n"
" -p prefix Give a prefix for the generated names\n"
" -r Create binary .res file (compile only)\n"
@ -80,6 +85,9 @@ char usage[] = "Usage: wrc [options...] [infile[.rc|.res]]\n"
" * 0x01 Tell which resource is parsed (verbose mode)\n"
" * 0x02 Dump internal structures\n"
" * 0x04 Create a parser trace (yydebug=1)\n"
" * 0x08 Preprocessor messages\n"
" * 0x10 Preprocessor lex messages\n"
" * 0x20 Preprocessor yacc trace\n"
"The -o option only applies to the final destination file, which is\n"
"in case of normal compile a .s file. You must use the '-H header.h'\n"
"option to override the header-filename.\n"
@ -88,7 +96,7 @@ char usage[] = "Usage: wrc [options...] [infile[.rc|.res]]\n"
;
char version_string[] = "Wine Resource Compiler Version " WRC_FULLVERSION "\n"
"Copyright 1998,1999 Bertho A. Stultiens\n"
"Copyright 1998-2000 Bertho A. Stultiens\n"
" 1994 Martin von Loewis\n";
/*
@ -121,6 +129,9 @@ int create_res = 0;
* debuglevel & DEBUGLEVEL_CHAT Say whats done
* debuglevel & DEBUGLEVEL_DUMP Dump internal structures
* debuglevel & DEBUGLEVEL_TRACE Create parser trace
* debuglevel & DEBUGLEVEL_PPMSG Preprocessor messages
* debuglevel & DEBUGLEVEL_PPLEX Preprocessor lex trace
* debuglevel & DEBUGLEVEL_PPTRACE Preprocessor yacc trace
*/
int debuglevel = DEBUGLEVEL_NONE;
@ -198,15 +209,32 @@ int auto_register = 0;
*/
int leave_case = 0;
/*
* Set when _only_ to run the preprocessor (-E option)
*/
int preprocess_only = 0;
/*
* Set when _not_ to run the preprocessor (-N option)
*/
int no_preprocess = 0;
char *output_name; /* The name given by the -o option */
char *input_name; /* The name given on the command-line */
char *header_name; /* The name given by the -H option */
char *temp_name; /* Temporary file for preprocess pipe */
int line_number = 1; /* The current line */
int char_number = 1; /* The current char pos within the line */
char *cmdline; /* The entire commandline */
time_t now; /* The time of start of wrc */
resource_t *resource_top; /* The top of the parsed resources */
int getopt (int argc, char *const *argv, const char *optstring);
static void rm_tempfile(void);
static void segvhandler(int sig);
int main(int argc,char *argv[])
{
@ -219,6 +247,10 @@ int main(int argc,char *argv[])
int i;
int cmdlen;
signal(SIGSEGV, segvhandler);
now = time(NULL);
/* First rebuild the commandline to put in destination */
/* Could be done through env[], but not all OS-es support it */
cmdlen = 4; /* for "wrc " */
@ -233,7 +265,7 @@ int main(int argc,char *argv[])
strcat(cmdline, " ");
}
while((optc = getopt(argc, argv, "a:AbcC:d:D:eghH:I:l:Lno:p:rstTVw:W")) != EOF)
while((optc = getopt(argc, argv, "a:AbcC:d:D:eEghH:I:l:LnNo:p:rstTVw:W")) != EOF)
{
switch(optc)
{
@ -261,6 +293,9 @@ int main(int argc,char *argv[])
case 'e':
extensions = 0;
break;
case 'E':
preprocess_only = 1;
break;
case 'g':
global = 1;
break;
@ -286,6 +321,9 @@ int main(int argc,char *argv[])
case 'n':
create_s = 0;
break;
case 'N':
no_preprocess = 1;
break;
case 'o':
output_name = strdup(optarg);
break;
@ -390,6 +428,62 @@ int main(int argc,char *argv[])
}
}
if(preprocess_only)
{
if(constant)
{
warning("Option -c ignored with preprocess only\n");
constant = 0;
}
if(create_header)
{
warning("Option -[h|H] ignored with preprocess only\n");
create_header = 0;
}
if(indirect)
{
warning("Option -l ignored with preprocess only\n");
indirect = 0;
}
if(indirect_only)
{
error("Option -E and -L cannot be used together\n");
}
if(global)
{
warning("Option -g ignored with preprocess only\n");
global = 0;
}
if(create_dir)
{
warning("Option -s ignored with preprocess only\n");
create_dir = 0;
}
if(binary)
{
error("Option -E and -b cannot be used together\n");
}
if(no_preprocess)
{
error("Option -E and -N cannot be used together\n");
}
}
#if !defined(HAVE_WINE_CONSTRUCTOR)
if(auto_register)
{
warning("Autoregister code non-operable (HAVE_WINE_CONSTRUCTOR not defined)");
auto_register = 0;
}
#endif
/* Set alignment power */
a = alignment;
for(alignment_pwr = 0; alignment_pwr < 10 && a > 1; alignment_pwr++)
@ -413,16 +507,29 @@ int main(int argc,char *argv[])
}
yydebug = debuglevel & DEBUGLEVEL_TRACE ? 1 : 0;
yy_flex_debug = debuglevel & DEBUGLEVEL_TRACE ? 1 : 0;
ppdebug = debuglevel & DEBUGLEVEL_PPTRACE ? 1 : 0;
pp_flex_debug = debuglevel & DEBUGLEVEL_PPLEX ? 1 : 0;
/* Set the default defined stuff */
add_cmdline_define("__WRC__=" WRC_STRINGIZE(WRC_MAJOR_VERSION));
add_cmdline_define("__WRC_MINOR__=" WRC_STRINGIZE(WRC_MINOR_VERSION));
add_cmdline_define("__WRC_MICRO__=" WRC_STRINGIZE(WRC_MICRO_VERSION));
add_cmdline_define("__WRC_PATCH__=" WRC_STRINGIZE(WRC_MICRO_VERSION));
add_cmdline_define("RC_INVOKED=1");
add_cmdline_define("__WRC__=1");
if(win32)
{
add_cmdline_define("__WIN32__=1");
add_cmdline_define("__FLAT__=1");
}
add_special_define("__FILE__");
add_special_define("__LINE__");
add_special_define("__DATE__");
add_special_define("__TIME__");
/* Check if the user set a language, else set default */
if(!currentlanguage)
currentlanguage = new_language(0, 0);
@ -431,23 +538,15 @@ int main(int argc,char *argv[])
if(optind < argc)
{
input_name = argv[optind];
yyin = fopen(input_name, "rb");
if(!yyin)
{
error("Could not open %s\n", input_name);
}
}
else
{
yyin = stdin;
}
if(binary && !input_name)
{
error("Binary mode requires .res file as input");
error("Binary mode requires .res file as input\n");
}
if(!output_name)
/* Generate appropriate outfile names */
if(!output_name && !preprocess_only)
{
output_name = dup_basename(input_name, binary ? ".res" : ".rc");
strcat(output_name, create_res ? ".res" : ".s");
@ -459,10 +558,75 @@ int main(int argc,char *argv[])
strcat(header_name, ".h");
}
/* Run the preprocessor on the input */
if(!no_preprocess && !binary)
{
char *real_name;
/*
* Preprocess the input to a temp-file, or stdout if
* no output was given.
*/
chat("Starting preprocess");
if(preprocess_only && !output_name)
{
ppout = stdout;
}
else if(preprocess_only && output_name)
{
if(!(ppout = fopen(output_name, "wb")))
error("Could not open %s for writing\n", output_name);
}
else
{
if(!(temp_name = tmpnam(NULL)))
error("Could nor generate a temp-name\n");
temp_name = xstrdup(temp_name);
if(!(ppout = fopen(temp_name, "wb")))
error("Could not create a temp-file\n");
atexit(rm_tempfile);
}
real_name = input_name; /* Because it gets overwritten */
if(!input_name)
ppin = stdin;
else
{
if(!(ppin = fopen(input_name, "rb")))
error("Could not open %s\n", input_name);
}
fprintf(ppout, "# 1 \"%s\" 1\n", input_name ? input_name : "");
ret = ppparse();
input_name = real_name;
if(input_name)
fclose(ppin);
fclose(ppout);
input_name = temp_name;
if(ret)
exit(1); /* Error during preprocess */
if(preprocess_only)
exit(0);
}
if(!binary)
{
/* Go from .rc to .res or .s */
chat("Starting parse");
if(!(yyin = fopen(input_name, "rb")))
error("Could not open %s for input\n", input_name);
ret = yyparse();
if(input_name)
@ -521,5 +685,17 @@ int main(int argc,char *argv[])
}
static void rm_tempfile(void)
{
if(temp_name)
unlink(temp_name);
}
static void segvhandler(int sig)
{
fprintf(stderr, "\n%s:%d: Oops, segment violation\n", input_name, line_number);
fflush(stdout);
fflush(stderr);
abort();
}

View File

@ -12,9 +12,17 @@
#include "wrctypes.h"
#endif
#define WRC_VERSION "1.0.18"
#define WRC_RELEASEDATE "(28-Dec-1999)"
#define WRC_FULLVERSION WRC_VERSION " " WRC_RELEASEDATE
#include <time.h> /* For time_t */
#define WRC_MAJOR_VERSION 1
#define WRC_MINOR_VERSION 1
#define WRC_MICRO_VERSION 0
#define WRC_RELEASEDATE "(01-May-2000)"
#define WRC_STRINGIZE(a) #a
#define WRC_VERSIONIZE(a,b,c) WRC_STRINGIZE(a) "." WRC_STRINGIZE(b) "." WRC_STRINGIZE(c)
#define WRC_VERSION WRC_VERSIONIZE(WRC_MAJOR_VERSION, WRC_MINOR_VERSION, WRC_MICRO_VERSION)
#define WRC_FULLVERSION WRC_VERSION " " WRC_RELEASEDATE
/* Only used in heavy debugging sessions */
#define HEAPCHECK()
@ -25,6 +33,9 @@ extern int debuglevel;
#define DEBUGLEVEL_CHAT 0x0001
#define DEBUGLEVEL_DUMP 0x0002
#define DEBUGLEVEL_TRACE 0x0004
#define DEBUGLEVEL_PPMSG 0x0008
#define DEBUGLEVEL_PPLEX 0x0010
#define DEBUGLEVEL_PPTRACE 0x0020
extern int win32;
extern int constant;
@ -43,12 +54,18 @@ extern DWORD codepage;
extern int pedantic;
extern int auto_register;
extern int leave_case;
extern int preprocess_only;
extern int no_preprocess;
extern char *prefix;
extern char *output_name;
extern char *input_name;
extern char *header_name;
extern char *cmdline;
extern time_t now;
extern int line_number;
extern int char_number;
extern resource_t *resource_top;
extern language_t *currentlanguage;

View File

@ -11,7 +11,6 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include "wrc.h"
#include "writeres.h"
@ -91,8 +90,6 @@ int n_name_entries = 0; /* win32 only: Nr of unique namess in the type-level ar
static int direntries; /* win32 only: Total number of unique resources */
time_t now;
/*
*****************************************************************************
* Function : write_resfile
@ -940,7 +937,6 @@ void write_s_file(char *outname, resource_t *top)
{
char *s, *p;
now = time(NULL);
s = ctime(&now);
p = strchr(s, '\n');
if(p) *p = '\0';
@ -1127,7 +1123,6 @@ void write_h_file(char *outname, resource_t *top)
error("Could not open %s\n", outname);
}
time(&now);
fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
cmdline, ctime(&now), (long)now, (long)now);