[882] | 1 | /* -*-C-*-
|
---|
| 2 | *
|
---|
[5522] | 3 | * Copyright 1998-2000 Bertho A. Stultiens (BS)
|
---|
[882] | 4 | *
|
---|
[5522] | 5 | * 21-May-2000 BS - Fixed the ident requirement of resource names
|
---|
| 6 | * which can be keywords.
|
---|
| 7 | * 30-Apr-2000 BS - Reintegration into the wine-tree
|
---|
| 8 | * 11-Jan-2000 BS - Very drastic cleanup because we don't have a
|
---|
| 9 | * preprocessor in here anymore.
|
---|
| 10 | * 02-Jan-2000 BS - Removed the preprocessor code
|
---|
| 11 | * 23-Dec-1999 BS - Removed the copyright for Martin von Loewis.
|
---|
| 12 | * There is really nothing left of his code in
|
---|
| 13 | * this parser.
|
---|
[882] | 14 | * 20-Jun-1998 BS - Changed the filename conversion. Filenames are
|
---|
| 15 | * case-sensitive inder *nix, but not under dos.
|
---|
| 16 | * default behaviour is to convert to lower case.
|
---|
| 17 | * - All backslashes are converted to forward and
|
---|
| 18 | * both single and double slash is recognized as
|
---|
| 19 | * MS/Borland does.
|
---|
| 20 | * - Fixed a bug in 'yywf' case that prevented
|
---|
| 21 | * double quoted names to be scanned propperly.
|
---|
| 22 | *
|
---|
| 23 | * 19-May-1998 BS - Started to build a preprocessor.
|
---|
| 24 | * - Changed keyword processing completely to
|
---|
| 25 | * table-lookups.
|
---|
| 26 | *
|
---|
| 27 | * 20-Apr-1998 BS - Added ';' comment stripping
|
---|
| 28 | *
|
---|
| 29 | * 17-Apr-1998 BS - Made the win32 keywords optional when compiling in
|
---|
| 30 | * 16bit mode
|
---|
| 31 | *
|
---|
| 32 | * 15-Apr-1998 BS - Changed string handling to include escapes
|
---|
| 33 | * - Added unicode string handling (no codepage
|
---|
| 34 | * translation though).
|
---|
| 35 | * - 'Borrowed' the main idea of string scanning from
|
---|
| 36 | * the flex manual pages.
|
---|
| 37 | * - Added conditional handling of scanning depending
|
---|
| 38 | * on the state of the parser. This was mainly required
|
---|
| 39 | * to distinguish a file to load or raw data that
|
---|
| 40 | * follows. MS's definition of filenames is rather
|
---|
| 41 | * complex... It can be unquoted or double quoted. If
|
---|
| 42 | * double quoted, then the '\\' char is not automatically
|
---|
| 43 | * escaped according to Borland's rc compiler, but it
|
---|
| 44 | * accepts both "\\path\\file.rc" and "\path\file.rc".
|
---|
| 45 | * This makes life very hard! I go for the escaped
|
---|
| 46 | * version, as this seems to be the documented way...
|
---|
| 47 | * - Single quoted strings are now parsed and converted
|
---|
| 48 | * here.
|
---|
| 49 | * - Added comment stripping. The implementation is
|
---|
| 50 | * 'borrowed' from the flex manpages.
|
---|
| 51 | * - Rebuild string processing so that it may contain
|
---|
| 52 | * escaped '\0'.
|
---|
| 53 | */
|
---|
| 54 |
|
---|
| 55 | /* Exclusive string handling */
|
---|
| 56 | %x yystr
|
---|
| 57 | /* Exclusive unicode string handling */
|
---|
| 58 | %x yylstr
|
---|
| 59 | /* Exclusive rcdata single quoted data handling */
|
---|
| 60 | %x yyrcd
|
---|
| 61 | /* Exclusive comment eating... */
|
---|
| 62 | %x comment
|
---|
| 63 | /* Set when stripping c-junk */
|
---|
[3426] | 64 | %x pp_stripe
|
---|
[882] | 65 | %x pp_strips
|
---|
| 66 | %x pp_stripp
|
---|
| 67 | %x pp_stripp_final
|
---|
[5522] | 68 | /* Set when scanning #line style directives */
|
---|
| 69 | %x pp_line
|
---|
[882] | 70 |
|
---|
[5522] | 71 | %option stack
|
---|
[882] | 72 | %option never-interactive
|
---|
[5522] | 73 |
|
---|
[882] | 74 | /* Some shortcut definitions */
|
---|
| 75 | ws [ \f\t\r]
|
---|
| 76 | cident [a-zA-Z_][0-9a-zA-Z_]*
|
---|
| 77 |
|
---|
| 78 | %{
|
---|
| 79 |
|
---|
| 80 | /*#define LEX_DEBUG*/
|
---|
| 81 |
|
---|
| 82 | #include "config.h"
|
---|
| 83 |
|
---|
| 84 | #include <stdio.h>
|
---|
| 85 | #include <stdlib.h>
|
---|
| 86 | #include <string.h>
|
---|
| 87 | #include <ctype.h>
|
---|
[5522] | 88 | #include <assert.h>
|
---|
[882] | 89 |
|
---|
| 90 | #include "wrc.h"
|
---|
| 91 | #include "utils.h"
|
---|
| 92 | #include "preproc.h"
|
---|
| 93 | #include "parser.h"
|
---|
| 94 | #include "newstruc.h"
|
---|
| 95 |
|
---|
| 96 | #include "y.tab.h"
|
---|
| 97 |
|
---|
| 98 | #define YY_USE_PROTOS
|
---|
| 99 | #define YY_NO_UNPUT
|
---|
[5522] | 100 | #define YY_NO_TOP_STATE
|
---|
[882] | 101 |
|
---|
| 102 | /* Always update the current character position within a line */
|
---|
[5522] | 103 | #define YY_USER_ACTION char_number+=yyleng; wanted_id = want_id; want_id = 0;
|
---|
[882] | 104 |
|
---|
[5522] | 105 | static void addcchar(char c);
|
---|
| 106 | static void addwchar(short s);
|
---|
| 107 | static string_t *get_buffered_cstring(void);
|
---|
| 108 | static string_t *get_buffered_wstring(void);
|
---|
| 109 | static string_t *make_string(char *s);
|
---|
[882] | 110 |
|
---|
| 111 | static char *cbuffer; /* Buffers for string collection */
|
---|
| 112 | static int cbufidx;
|
---|
| 113 | static int cbufalloc = 0;
|
---|
| 114 | static short *wbuffer;
|
---|
| 115 | static int wbufidx;
|
---|
| 116 | static int wbufalloc = 0;
|
---|
[3426] | 117 | static int stripslevel = 0; /* Count {} during pp_strips/pp_stripe mode */
|
---|
[882] | 118 | static int stripplevel = 0; /* Count () during pp_strips mode */
|
---|
| 119 | static int cjunk_tagline; /* Where did we start stripping (helps error tracking) */
|
---|
| 120 |
|
---|
[5522] | 121 | /*
|
---|
| 122 | * This one is a bit tricky.
|
---|
| 123 | * We set 'want_id' in the parser to get the first
|
---|
| 124 | * identifier we get across in the scanner, but we
|
---|
| 125 | * also want it to be reset at nearly any token we
|
---|
| 126 | * see. Exceptions are:
|
---|
| 127 | * - newlines
|
---|
| 128 | * - comments
|
---|
| 129 | * - whitespace
|
---|
| 130 | *
|
---|
| 131 | * The scanner will automatically reset 'want_id'
|
---|
| 132 | * after *each* scanner reduction and puts is value
|
---|
| 133 | * into the var below. In this way we can see the
|
---|
| 134 | * state after the YY_RULE_SETUP (i.e. the user action;
|
---|
| 135 | * see above) and don't have to worry too much when
|
---|
| 136 | * it needs to be reset.
|
---|
| 137 | */
|
---|
| 138 | static int wanted_id = 0;
|
---|
| 139 | static int save_wanted_id; /* To save across comment reductions */
|
---|
[882] | 140 |
|
---|
| 141 | struct keyword {
|
---|
| 142 | char *keyword;
|
---|
| 143 | int token;
|
---|
| 144 | int isextension;
|
---|
| 145 | int needcase;
|
---|
[5522] | 146 | int alwayskw;
|
---|
[882] | 147 | };
|
---|
| 148 |
|
---|
| 149 | static struct keyword keywords[] = {
|
---|
[5522] | 150 | { "ACCELERATORS", tACCELERATORS, 0, 0, 0},
|
---|
| 151 | { "ALT", tALT, 0, 0, 0},
|
---|
| 152 | { "ASCII", tASCII, 0, 0, 0},
|
---|
| 153 | { "AUTO3STATE", tAUTO3STATE, 1, 0, 0},
|
---|
| 154 | { "AUTOCHECKBOX", tAUTOCHECKBOX, 1, 0, 0},
|
---|
| 155 | { "AUTORADIOBUTTON", tAUTORADIOBUTTON, 1, 0, 0},
|
---|
| 156 | { "BEGIN", tBEGIN, 0, 0, 0},
|
---|
| 157 | { "BITMAP", tBITMAP, 0, 0, 0},
|
---|
| 158 | { "BLOCK", tBLOCK, 0, 0, 0},
|
---|
| 159 | { "BUTTON", tBUTTON, 1, 0, 0},
|
---|
| 160 | { "CAPTION", tCAPTION, 0, 0, 0},
|
---|
| 161 | { "CHARACTERISTICS", tCHARACTERISTICS, 1, 0, 0},
|
---|
| 162 | { "CHECKBOX", tCHECKBOX, 0, 0, 0},
|
---|
| 163 | { "CHECKED", tCHECKED, 0, 0, 0},
|
---|
| 164 | { "CLASS", tCLASS, 0, 0, 0},
|
---|
| 165 | { "COMBOBOX", tCOMBOBOX, 0, 0, 0},
|
---|
| 166 | { "CONTROL", tCONTROL, 0, 0, 0},
|
---|
| 167 | { "CTEXT", tCTEXT, 0, 0, 0},
|
---|
| 168 | { "CURSOR", tCURSOR, 0, 0, 0},
|
---|
| 169 | { "DEFPUSHBUTTON", tDEFPUSHBUTTON, 0, 0, 0},
|
---|
| 170 | { "DIALOG", tDIALOG, 0, 0, 0},
|
---|
| 171 | { "DIALOGEX", tDIALOGEX, 1, 0, 0},
|
---|
| 172 | { "DISCARDABLE", tDISCARDABLE, 0, 0, 0},
|
---|
| 173 | { "DLGINIT", tDLGINIT, 0, 0, 0},
|
---|
| 174 | { "EDITTEXT", tEDITTEXT, 0, 0, 0},
|
---|
| 175 | { "END", tEND, 0, 0, 0},
|
---|
| 176 | { "enum", tENUM, 0, 1, 1},
|
---|
| 177 | { "EXSTYLE", tEXSTYLE, 0, 0, 0},
|
---|
| 178 | { "extern", tEXTERN, 0, 1, 1},
|
---|
| 179 | { "FILEFLAGS", tFILEFLAGS, 0, 0, 0},
|
---|
| 180 | { "FILEFLAGSMASK", tFILEFLAGSMASK, 0, 0, 0},
|
---|
| 181 | { "FILEOS", tFILEOS, 0, 0, 0},
|
---|
| 182 | { "FILESUBTYPE", tFILESUBTYPE, 0, 0, 0},
|
---|
| 183 | { "FILETYPE", tFILETYPE, 0, 0, 0},
|
---|
| 184 | { "FILEVERSION", tFILEVERSION, 0, 0, 0},
|
---|
| 185 | { "FIXED", tFIXED, 0, 0, 0},
|
---|
| 186 | { "FONT", tFONT, 0, 0, 0},
|
---|
| 187 | { "FONTDIR", tFONTDIR, 0, 0, 0}, /* This is a Borland BRC extension */
|
---|
| 188 | { "GRAYED", tGRAYED, 0, 0, 0},
|
---|
| 189 | { "GROUPBOX", tGROUPBOX, 0, 0, 0},
|
---|
| 190 | { "HELP", tHELP, 0, 0, 0},
|
---|
| 191 | { "ICON", tICON, 0, 0, 0},
|
---|
| 192 | { "IMPURE", tIMPURE, 0, 0, 0},
|
---|
| 193 | { "INACTIVE", tINACTIVE, 0, 0, 0},
|
---|
| 194 | { "inline", tINLINE, 0, 1, 1},
|
---|
| 195 | { "LANGUAGE", tLANGUAGE, 1, 0, 1},
|
---|
| 196 | { "LISTBOX", tLISTBOX, 0, 0, 0},
|
---|
| 197 | { "LOADONCALL", tLOADONCALL, 0, 0, 0},
|
---|
| 198 | { "LTEXT", tLTEXT, 0, 0, 0},
|
---|
| 199 | { "MENU", tMENU, 0, 0, 0},
|
---|
| 200 | { "MENUBARBREAK", tMENUBARBREAK, 0, 0, 0},
|
---|
| 201 | { "MENUBREAK", tMENUBREAK, 0, 0, 0},
|
---|
| 202 | { "MENUEX", tMENUEX, 1, 0, 0},
|
---|
| 203 | { "MENUITEM", tMENUITEM, 0, 0, 0},
|
---|
| 204 | { "MESSAGETABLE", tMESSAGETABLE, 1, 0, 0},
|
---|
| 205 | { "MOVEABLE", tMOVEABLE, 0, 0, 0},
|
---|
| 206 | { "NOINVERT", tNOINVERT, 0, 0, 0},
|
---|
| 207 | { "NOT", tNOT, 0, 0, 0},
|
---|
| 208 | { "POPUP", tPOPUP, 0, 0, 0},
|
---|
| 209 | { "PRELOAD", tPRELOAD, 0, 0, 0},
|
---|
| 210 | { "PRODUCTVERSION", tPRODUCTVERSION, 0, 0, 0},
|
---|
| 211 | { "PURE", tPURE, 0, 0, 0},
|
---|
| 212 | { "PUSHBUTTON", tPUSHBUTTON, 0, 0, 0},
|
---|
| 213 | { "RADIOBUTTON", tRADIOBUTTON, 0, 0, 0},
|
---|
| 214 | { "RCDATA", tRCDATA, 0, 0, 0},
|
---|
| 215 | { "RTEXT", tRTEXT, 0, 0, 0},
|
---|
| 216 | { "SCROLLBAR", tSCROLLBAR, 0, 0, 0},
|
---|
| 217 | { "SEPARATOR", tSEPARATOR, 0, 0, 0},
|
---|
| 218 | { "SHIFT", tSHIFT, 0, 0, 0},
|
---|
| 219 | { "STATE3", tSTATE3, 1, 0, 0},
|
---|
| 220 | { "static", tSTATIC, 0, 1, 1},
|
---|
| 221 | { "STRING", tSTRING, 0, 0, 0},
|
---|
| 222 | { "STRINGTABLE", tSTRINGTABLE, 0, 0, 1},
|
---|
| 223 | { "struct", tSTRUCT, 0, 1, 1},
|
---|
| 224 | { "STYLE", tSTYLE, 0, 0, 0},
|
---|
| 225 | { "TOOLBAR", tTOOLBAR, 1, 0, 0},
|
---|
| 226 | { "typedef", tTYPEDEF, 0, 1, 1},
|
---|
| 227 | { "VALUE", tVALUE, 0, 0, 0},
|
---|
| 228 | { "VERSION", tVERSION, 1, 0, 0},
|
---|
| 229 | { "VERSIONINFO", tVERSIONINFO, 0, 0, 0},
|
---|
| 230 | { "VIRTKEY", tVIRTKEY, 0, 0, 0}
|
---|
[882] | 231 | };
|
---|
| 232 |
|
---|
| 233 | #define NKEYWORDS (sizeof(keywords)/sizeof(keywords[0]))
|
---|
| 234 | #define KWP(p) ((struct keyword *)(p))
|
---|
[5522] | 235 | static int kw_cmp_func(const void *s1, const void *s2)
|
---|
[882] | 236 | {
|
---|
| 237 | int ret;
|
---|
| 238 | ret = strcasecmp(KWP(s1)->keyword, KWP(s2)->keyword);
|
---|
| 239 | if(!ret && (KWP(s1)->needcase || KWP(s2)->needcase))
|
---|
| 240 | return strcmp(KWP(s1)->keyword, KWP(s2)->keyword);
|
---|
| 241 | else
|
---|
| 242 | return ret;
|
---|
| 243 | }
|
---|
| 244 |
|
---|
| 245 | #define KW_BSEARCH
|
---|
| 246 | #define DO_SORT
|
---|
[5522] | 247 | static struct keyword *iskeyword(char *kw)
|
---|
[882] | 248 | {
|
---|
| 249 | struct keyword *kwp;
|
---|
| 250 | struct keyword key;
|
---|
| 251 | key.keyword = kw;
|
---|
| 252 | key.needcase = 0;
|
---|
| 253 | #ifdef DO_SORT
|
---|
| 254 | {
|
---|
| 255 | /* Make sure that it is sorted for bsearsh */
|
---|
| 256 | static int sorted = 0;
|
---|
| 257 | if(!sorted)
|
---|
| 258 | {
|
---|
| 259 | qsort(keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
|
---|
| 260 | sorted = 1;
|
---|
| 261 | }
|
---|
| 262 | }
|
---|
| 263 | #endif
|
---|
| 264 | #ifdef KW_BSEARCH
|
---|
| 265 | kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
|
---|
| 266 | #else
|
---|
| 267 | {
|
---|
| 268 | int i;
|
---|
| 269 | for(i = 0; i < NKEYWORDS; i++)
|
---|
| 270 | {
|
---|
| 271 | if(!kw_cmp_func(&key, &keywords[i]))
|
---|
| 272 | break;
|
---|
| 273 | }
|
---|
| 274 | if(i < NKEYWORDS)
|
---|
| 275 | kwp = &keywords[i];
|
---|
| 276 | else
|
---|
| 277 | kwp = NULL;
|
---|
| 278 | }
|
---|
| 279 | #endif
|
---|
| 280 |
|
---|
| 281 | if(kwp == NULL || (kwp->isextension && !extensions))
|
---|
| 282 | return NULL;
|
---|
| 283 | else
|
---|
| 284 | return kwp;
|
---|
| 285 | }
|
---|
| 286 |
|
---|
| 287 | %}
|
---|
| 288 |
|
---|
[5522] | 289 | /*
|
---|
| 290 | **************************************************************************
|
---|
| 291 | * The flexer starts here
|
---|
| 292 | **************************************************************************
|
---|
| 293 | */
|
---|
[882] | 294 | %%
|
---|
[5522] | 295 | /*
|
---|
| 296 | * Catch the GCC-style line statements here and parse them.
|
---|
| 297 | * This has the advantage that you can #include at any
|
---|
| 298 | * stage in the resource file.
|
---|
| 299 | * The preprocessor generates line directives in the format:
|
---|
| 300 | * # <linenum> "filename" <codes>
|
---|
| 301 | *
|
---|
| 302 | * Codes can be a sequence of:
|
---|
| 303 | * - 1 start of new file
|
---|
| 304 | * - 2 returning to previous
|
---|
| 305 | * - 3 system header
|
---|
| 306 | * - 4 interpret as C-code
|
---|
| 307 | *
|
---|
| 308 | * 4 is not used and 1 mutually excludes 2
|
---|
| 309 | * Anyhow, we are not really interested in these at all
|
---|
| 310 | * because we only want to know the linenumber and
|
---|
| 311 | * filename.
|
---|
| 312 | */
|
---|
| 313 | <INITIAL,pp_strips,pp_stripp>^{ws}*\#{ws}* yy_push_state(pp_line);
|
---|
| 314 | <pp_line>[^\n]* {
|
---|
| 315 | int lineno;
|
---|
| 316 | char *cptr;
|
---|
| 317 | char *fname;
|
---|
| 318 | yy_pop_state();
|
---|
| 319 | lineno = (int)strtol(yytext, &cptr, 10);
|
---|
| 320 | if(!lineno)
|
---|
| 321 | yyerror("Malformed '#...' line-directive; invalid linenumber");
|
---|
| 322 | fname = strchr(cptr, '"');
|
---|
| 323 | if(!fname)
|
---|
| 324 | yyerror("Malformed '#...' line-directive; missing filename");
|
---|
| 325 | fname++;
|
---|
| 326 | cptr = strchr(fname, '"');
|
---|
| 327 | if(!cptr)
|
---|
| 328 | yyerror("Malformed '#...' line-directive; missing terminating \"");
|
---|
| 329 | *cptr = '\0';
|
---|
| 330 | line_number = lineno - 1; /* We didn't read the newline */
|
---|
| 331 | input_name = xstrdup(fname);
|
---|
| 332 | }
|
---|
[882] | 333 |
|
---|
[5522] | 334 | /*
|
---|
| 335 | * Strip everything until a ';' taking
|
---|
| 336 | * into account braces {} for structures,
|
---|
| 337 | * classes and enums.
|
---|
| 338 | */
|
---|
| 339 | <pp_strips>\{ stripslevel++;
|
---|
| 340 | <pp_strips>\} stripslevel--;
|
---|
| 341 | <pp_strips>; if(!stripslevel) yy_pop_state();
|
---|
[882] | 342 | <pp_strips>\/[^*\n] ; /* To catch comments */
|
---|
| 343 | <pp_strips>[^\{\};\n#/]* ; /* Ignore rest */
|
---|
[5522] | 344 | <pp_strips>\n line_number++; char_number = 1;
|
---|
[882] | 345 |
|
---|
[5522] | 346 | <pp_stripp>\( stripplevel++;
|
---|
| 347 | <pp_stripp>\) {
|
---|
| 348 | stripplevel--;
|
---|
| 349 | if(!stripplevel)
|
---|
| 350 | {
|
---|
| 351 | yy_pop_state();
|
---|
| 352 | yy_push_state(pp_stripp_final);
|
---|
| 353 | }
|
---|
[882] | 354 | }
|
---|
| 355 | <pp_stripp>\/[^*\n] ; /* To catch comments */
|
---|
| 356 | <pp_stripp>[^\(\);\n#/]* ; /* Ignore rest */
|
---|
[5522] | 357 | <pp_stripp>\n line_number++; char_number = 1;
|
---|
[882] | 358 |
|
---|
[5522] | 359 | <pp_stripp_final>{ws}* ; /* Ignore */
|
---|
| 360 | <pp_stripp_final>; yy_pop_state(); /* Kill the semicolon */
|
---|
| 361 | <pp_stripp_final>\n line_number++; char_number = 1; yy_pop_state();
|
---|
| 362 | <pp_stripp_final>. yyless(0); yy_pop_state();
|
---|
[882] | 363 |
|
---|
| 364 | \{ return tBEGIN;
|
---|
| 365 | \} return tEND;
|
---|
| 366 |
|
---|
[5522] | 367 | [0-9]+[lL]? { yylval.num = strtoul(yytext, 0, 10); return toupper(yytext[yyleng-1]) == 'L' ? tLNUMBER : tNUMBER; }
|
---|
| 368 | 0[xX][0-9A-Fa-f]+[lL]? { yylval.num = strtoul(yytext, 0, 16); return toupper(yytext[yyleng-1]) == 'L' ? tLNUMBER : tNUMBER; }
|
---|
| 369 | 0[oO][0-7]+[lL]? { yylval.num = strtoul(yytext+2, 0, 8); return toupper(yytext[yyleng-1]) == 'L' ? tLNUMBER : tNUMBER; }
|
---|
| 370 |
|
---|
| 371 | /*
|
---|
| 372 | * The next two rules scan identifiers and filenames.
|
---|
| 373 | * This is achieved by using the priority ruling
|
---|
| 374 | * of the scanner where a '.' is valid in a filename
|
---|
| 375 | * and *only* in a filename. In this case, the second
|
---|
| 376 | * rule will be reduced because it is longer.
|
---|
| 377 | */
|
---|
[882] | 378 | [A-Za-z_0-9]+ {
|
---|
[5522] | 379 | struct keyword *tok = iskeyword(yytext);
|
---|
[882] | 380 |
|
---|
[5522] | 381 | if(tok)
|
---|
[882] | 382 | {
|
---|
[5522] | 383 | if(tok->token == tCLASS && !strcmp(yytext, "class"))
|
---|
| 384 | return tCPPCLASS;
|
---|
| 385 | else if(wanted_id && !tok->alwayskw)
|
---|
[882] | 386 | {
|
---|
[5522] | 387 | yylval.str = make_string(yytext);
|
---|
| 388 | return tIDENT;
|
---|
[882] | 389 | }
|
---|
[5522] | 390 | else
|
---|
| 391 | return tok->token;
|
---|
[882] | 392 | }
|
---|
| 393 | else
|
---|
| 394 | {
|
---|
| 395 | yylval.str = make_string(yytext);
|
---|
[5522] | 396 | return tIDENT;
|
---|
[882] | 397 | }
|
---|
| 398 | }
|
---|
[5522] | 399 | [A-Za-z_0-9./\\]+ yylval.str = make_string(yytext); return tFILENAME;
|
---|
[882] | 400 |
|
---|
[5522] | 401 | /*
|
---|
| 402 | * Wide string scanning
|
---|
| 403 | */
|
---|
[882] | 404 | L\" {
|
---|
[5522] | 405 | yy_push_state(yylstr);
|
---|
[882] | 406 | wbufidx = 0;
|
---|
| 407 | if(!win32)
|
---|
| 408 | yywarning("16bit resource contains unicode strings\n");
|
---|
| 409 | }
|
---|
[5522] | 410 | <yylstr>\"{ws}+ |
|
---|
[882] | 411 | <yylstr>\" {
|
---|
[5522] | 412 | yy_pop_state();
|
---|
[882] | 413 | yylval.str = get_buffered_wstring();
|
---|
| 414 | return tSTRING;
|
---|
| 415 | }
|
---|
| 416 | <yylstr>\\[0-7]{1,6} { /* octal escape sequence */
|
---|
| 417 | int result;
|
---|
| 418 | result = strtol(yytext+1, 0, 8);
|
---|
| 419 | if ( result > 0xffff )
|
---|
| 420 | yyerror("Character constant out of range");
|
---|
| 421 | addwchar((short)result);
|
---|
| 422 | }
|
---|
| 423 | <yylstr>\\x[0-9a-fA-F]{4} { /* hex escape sequence */
|
---|
| 424 | int result;
|
---|
| 425 | result = strtol(yytext+2, 0, 16);
|
---|
| 426 | addwchar((short)result);
|
---|
| 427 | }
|
---|
[5522] | 428 | <yylstr>\\x[0-9a-fA-F]{1,3} { yyerror("Invalid hex escape sequence '%s'", yytext); }
|
---|
| 429 |
|
---|
[882] | 430 | <yylstr>\\[0-9]+ yyerror("Bad escape secuence");
|
---|
| 431 | <yylstr>\\a addwchar('\a');
|
---|
| 432 | <yylstr>\\b addwchar('\b');
|
---|
| 433 | <yylstr>\\f addwchar('\f');
|
---|
| 434 | <yylstr>\\n addwchar('\n');
|
---|
| 435 | <yylstr>\\r addwchar('\r');
|
---|
| 436 | <yylstr>\\t addwchar('\t');
|
---|
| 437 | <yylstr>\\v addwchar('\v');
|
---|
[5522] | 438 | <yylstr>\\(\n|.) addwchar(yytext[1]);
|
---|
| 439 | <yylstr>\\\r\n addwchar(yytext[2]);
|
---|
[882] | 440 | <yylstr>\"\" addcchar('\"'); /* "bla""bla" -> "bla\"bla" */
|
---|
| 441 | <yylstr>\\\"\" addcchar('\"'); /* "bla\""bla" -> "bla\"bla" */
|
---|
| 442 | <yylstr>\"{ws}+\" ; /* "bla" "bla" -> "blabla" */
|
---|
| 443 | <yylstr>[^\\\n\"]+ {
|
---|
| 444 | char *yptr = yytext;
|
---|
| 445 | while(*yptr) /* FIXME: codepage translation */
|
---|
| 446 | addwchar(*yptr++ & 0xff);
|
---|
| 447 | }
|
---|
[5522] | 448 | <yylstr>\n yyerror("Unterminated string");
|
---|
[882] | 449 |
|
---|
[5522] | 450 | /*
|
---|
| 451 | * Normal string scanning
|
---|
| 452 | */
|
---|
| 453 | \" yy_push_state(yystr); cbufidx = 0;
|
---|
| 454 | <yystr>\"{ws}+ |
|
---|
[882] | 455 | <yystr>\" {
|
---|
[5522] | 456 | yy_pop_state();
|
---|
[882] | 457 | yylval.str = get_buffered_cstring();
|
---|
| 458 | return tSTRING;
|
---|
| 459 | }
|
---|
| 460 | <yystr>\\[0-7]{1,3} { /* octal escape sequence */
|
---|
| 461 | int result;
|
---|
| 462 | result = strtol(yytext+1, 0, 8);
|
---|
| 463 | if ( result > 0xff )
|
---|
| 464 | yyerror("Character constant out of range");
|
---|
| 465 | addcchar((char)result);
|
---|
| 466 | }
|
---|
| 467 | <yystr>\\x[0-9a-fA-F]{2} { /* hex escape sequence */
|
---|
| 468 | int result;
|
---|
| 469 | result = strtol(yytext+2, 0, 16);
|
---|
| 470 | addcchar((char)result);
|
---|
| 471 | }
|
---|
[5522] | 472 | <yystr>\\x[0-9a-fA-F] { yyerror("Invalid hex escape sequence '%s'", yytext); }
|
---|
| 473 |
|
---|
[882] | 474 | <yystr>\\[0-9]+ yyerror("Bad escape secuence");
|
---|
| 475 | <yystr>\\a addcchar('\a');
|
---|
| 476 | <yystr>\\b addcchar('\b');
|
---|
| 477 | <yystr>\\f addcchar('\f');
|
---|
| 478 | <yystr>\\n addcchar('\n');
|
---|
| 479 | <yystr>\\r addcchar('\r');
|
---|
| 480 | <yystr>\\t addcchar('\t');
|
---|
| 481 | <yystr>\\v addcchar('\v');
|
---|
[5522] | 482 | <yystr>\\(\n|.) addcchar(yytext[1]);
|
---|
| 483 | <yystr>\\\r\n addcchar(yytext[2]);
|
---|
[882] | 484 | <yystr>[^\\\n\"]+ {
|
---|
| 485 | char *yptr = yytext;
|
---|
| 486 | while(*yptr)
|
---|
| 487 | addcchar(*yptr++);
|
---|
| 488 | }
|
---|
| 489 | <yystr>\"\" addcchar('\"'); /* "bla""bla" -> "bla\"bla" */
|
---|
| 490 | <yystr>\\\"\" addcchar('\"'); /* "bla\""bla" -> "bla\"bla" */
|
---|
| 491 | <yystr>\"{ws}+\" ; /* "bla" "bla" -> "blabla" */
|
---|
[5522] | 492 | <yystr>\n yyerror("Unterminated string");
|
---|
[882] | 493 |
|
---|
[5522] | 494 | /*
|
---|
| 495 | * Raw data scanning
|
---|
| 496 | */
|
---|
| 497 | \' yy_push_state(yyrcd); cbufidx = 0;
|
---|
[882] | 498 | <yyrcd>\' {
|
---|
[5522] | 499 | yy_pop_state();
|
---|
[882] | 500 | yylval.raw = new_raw_data();
|
---|
| 501 | yylval.raw->size = cbufidx;
|
---|
| 502 | yylval.raw->data = xmalloc(yylval.raw->size);
|
---|
| 503 | memcpy(yylval.raw->data, cbuffer, yylval.raw->size);
|
---|
[5522] | 504 | return tRAWDATA;
|
---|
[882] | 505 | }
|
---|
| 506 | <yyrcd>[0-9a-fA-F]{2} {
|
---|
| 507 | int result;
|
---|
| 508 | result = strtol(yytext, 0, 16);
|
---|
| 509 | addcchar((char)result);
|
---|
| 510 | }
|
---|
| 511 | <yyrcd>{ws}+ ; /* Ignore space */
|
---|
| 512 | <yyrcd>\n line_number++; char_number = 1;
|
---|
| 513 | <yyrcd>. yyerror("Malformed data-line");
|
---|
| 514 |
|
---|
[5522] | 515 | /*
|
---|
| 516 | * Comment stripping
|
---|
| 517 | * Should never occur after preprocessing
|
---|
| 518 | */
|
---|
| 519 | <INITIAL,pp_stripp,pp_strips>"/*" {
|
---|
| 520 | yy_push_state(comment);
|
---|
| 521 | save_wanted_id = wanted_id;
|
---|
| 522 | if(!no_preprocess)
|
---|
| 523 | yywarning("Found comments after preprocessing, please report");
|
---|
| 524 | }
|
---|
[882] | 525 | <comment>[^*\n]* ;
|
---|
| 526 | <comment>"*"+[^*/\n]* ;
|
---|
| 527 | <comment>\n line_number++; char_number = 1;
|
---|
[5522] | 528 | <comment>"*"+"/" yy_pop_state(); want_id = save_wanted_id;
|
---|
[882] | 529 |
|
---|
[5522] | 530 | ;[^\n]* want_id = wanted_id; /* not really comment, but left-over c-junk */
|
---|
| 531 | "//"[^\n]* want_id = wanted_id; if(!no_preprocess) yywarning("Found comments after preprocessing, please report");
|
---|
[882] | 532 |
|
---|
[5522] | 533 | \n {
|
---|
| 534 | want_id = wanted_id;
|
---|
[882] | 535 | line_number++;
|
---|
| 536 | char_number = 1;
|
---|
| 537 | if(want_nl)
|
---|
| 538 | {
|
---|
| 539 | want_nl = 0;
|
---|
| 540 | return tNL;
|
---|
| 541 | }
|
---|
| 542 | }
|
---|
[5522] | 543 | {ws}+ want_id = wanted_id; /* Eat whitespace */
|
---|
[882] | 544 |
|
---|
| 545 | <INITIAL>. return yytext[0];
|
---|
[5522] | 546 |
|
---|
[882] | 547 | <<EOF>> {
|
---|
[5522] | 548 | if(YY_START == pp_strips || YY_START == pp_stripe || YY_START == pp_stripp || YY_START == pp_stripp_final)
|
---|
| 549 | yyerror("Unexpected end of file during c-junk scanning (started at %d)", cjunk_tagline);
|
---|
| 550 | else
|
---|
| 551 | yyterminate();
|
---|
[882] | 552 | }
|
---|
| 553 |
|
---|
| 554 | <*>.|\n {
|
---|
| 555 | /* Catch all rule to find any unmatched text */
|
---|
| 556 | if(*yytext == '\n')
|
---|
| 557 | {
|
---|
| 558 | line_number++;
|
---|
| 559 | char_number = 1;
|
---|
| 560 | }
|
---|
[3426] | 561 | yywarning("Unmatched text '%c' (0x%02x) YY_START=%d stripslevel=%d",
|
---|
[5522] | 562 | isprint(*yytext & 0xff) ? *yytext : '.', *yytext, YY_START,stripslevel);
|
---|
[882] | 563 | }
|
---|
| 564 |
|
---|
| 565 | %%
|
---|
| 566 |
|
---|
| 567 | #ifndef yywrap
|
---|
| 568 | int yywrap(void)
|
---|
| 569 | {
|
---|
| 570 | #if 0
|
---|
| 571 | if(bufferstackidx > 0)
|
---|
| 572 | {
|
---|
| 573 | return 0;
|
---|
| 574 | }
|
---|
| 575 | #endif
|
---|
| 576 | return 1;
|
---|
| 577 | }
|
---|
| 578 | #endif
|
---|
| 579 |
|
---|
| 580 | /* These dup functions copy the enclosed '\0' from
|
---|
| 581 | * the resource string.
|
---|
| 582 | */
|
---|
[5522] | 583 | static void addcchar(char c)
|
---|
[882] | 584 | {
|
---|
| 585 | if(cbufidx >= cbufalloc)
|
---|
| 586 | {
|
---|
| 587 | cbufalloc += 1024;
|
---|
| 588 | cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0]));
|
---|
| 589 | if(cbufalloc > 65536)
|
---|
| 590 | yywarning("Reallocating string buffer larger than 64kB");
|
---|
| 591 | }
|
---|
| 592 | cbuffer[cbufidx++] = c;
|
---|
| 593 | }
|
---|
| 594 |
|
---|
[5522] | 595 | static void addwchar(short s)
|
---|
[882] | 596 | {
|
---|
| 597 | if(wbufidx >= wbufalloc)
|
---|
| 598 | {
|
---|
| 599 | wbufalloc += 1024;
|
---|
| 600 | wbuffer = xrealloc(wbuffer, wbufalloc * sizeof(wbuffer[0]));
|
---|
| 601 | if(wbufalloc > 65536)
|
---|
| 602 | yywarning("Reallocating wide string buffer larger than 64kB");
|
---|
| 603 | }
|
---|
| 604 |
|
---|
| 605 | /*
|
---|
| 606 | * BS 08-Aug-1999 FIXME: The '& 0xff' is probably a bug, but I have
|
---|
| 607 | * not experienced it yet and I seem to remember that this was for
|
---|
| 608 | * a reason. But, as so many things you tend to forget why.
|
---|
| 609 | * I guess that there were problems due to the sign extension of
|
---|
| 610 | * shorts WRT chars (e.g. 0x80 becomes 0xff80 instead of 0x0080).
|
---|
| 611 | * This should then be fixed in the lexer calling the function.
|
---|
| 612 | */
|
---|
| 613 | wbuffer[wbufidx++] = (short)(s & 0xff);
|
---|
| 614 | }
|
---|
| 615 |
|
---|
[5522] | 616 | static string_t *get_buffered_cstring(void)
|
---|
[882] | 617 | {
|
---|
| 618 | string_t *str = new_string();
|
---|
| 619 | str->size = cbufidx;
|
---|
| 620 | str->type = str_char;
|
---|
| 621 | str->str.cstr = (char *)xmalloc(cbufidx+1);
|
---|
| 622 | memcpy(str->str.cstr, cbuffer, cbufidx);
|
---|
| 623 | str->str.cstr[cbufidx] = '\0';
|
---|
| 624 | return str;
|
---|
| 625 | }
|
---|
| 626 |
|
---|
[5522] | 627 | static string_t *get_buffered_wstring(void)
|
---|
[882] | 628 | {
|
---|
| 629 | string_t *str = new_string();
|
---|
| 630 | str->size = wbufidx;
|
---|
| 631 | str->type = str_unicode;
|
---|
| 632 | str->str.wstr = (short *)xmalloc(2*(wbufidx+1));
|
---|
| 633 | memcpy(str->str.wstr, wbuffer, wbufidx);
|
---|
| 634 | str->str.wstr[wbufidx] = 0;
|
---|
| 635 | return str;
|
---|
| 636 | }
|
---|
| 637 |
|
---|
[5522] | 638 | static string_t *make_string(char *s)
|
---|
[882] | 639 | {
|
---|
| 640 | string_t *str = new_string();
|
---|
| 641 | str->size = strlen(s);
|
---|
| 642 | str->type = str_char;
|
---|
| 643 | str->str.cstr = (char *)xmalloc(str->size+1);
|
---|
| 644 | memcpy(str->str.cstr, s, str->size+1);
|
---|
| 645 | return str;
|
---|
| 646 | }
|
---|
| 647 |
|
---|
| 648 | /* Called from the parser to kill c-junk */
|
---|
[3426] | 649 | void strip_extern(void)
|
---|
| 650 | {
|
---|
| 651 | cjunk_tagline = line_number;
|
---|
[5522] | 652 | yy_push_state(pp_stripe);
|
---|
[3426] | 653 | }
|
---|
| 654 |
|
---|
[882] | 655 | void strip_til_semicolon(void)
|
---|
| 656 | {
|
---|
| 657 | cjunk_tagline = line_number;
|
---|
[5522] | 658 | yy_push_state(pp_strips);
|
---|
[882] | 659 | }
|
---|
| 660 |
|
---|
| 661 | void strip_til_parenthesis(void)
|
---|
| 662 | {
|
---|
| 663 | cjunk_tagline = line_number;
|
---|
| 664 | stripplevel = 1; /* One scanned already */
|
---|
[5522] | 665 | yy_push_state(pp_stripp);
|
---|
[882] | 666 | }
|
---|
| 667 |
|
---|