📄 rclex.l
字号:
%{ /* rclex.l -- lexer for Windows rc files parser *//* Copyright 1997, 1998, 1999 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it 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. *//* This is a lex input file which generates a lexer used by the Windows rc file parser. It basically just recognized a bunch of keywords. */#include "bfd.h"#include "bucomm.h"#include "libiberty.h"#include "windres.h"#include "rcparse.h"#include <ctype.h>#include <assert.h>/* Whether we are in rcdata mode, in which we returns the lengths of strings. */static int rcdata_mode;/* Whether we are supressing lines from cpp (including windows.h or headers from your C sources may bring in externs and typedefs). When active, we return IGNORED_TOKEN, which lets us ignore these outside of resource constructs. Thus, it isn't required to protect all the non-preprocessor lines in your header files with #ifdef RC_INVOKED. It also means your RC file can't include other RC files if they're named "*.h". Sorry. Name them *.rch or whatever. */static int suppress_cpp_data;#define MAYBE_RETURN(x) return suppress_cpp_data ? IGNORED_TOKEN : (x)/* The first filename we detect in the cpp output. We use this to tell included files from the original file. */static char *initial_fn;/* List of allocated strings. */struct alloc_string{ struct alloc_string *next; char *s;};static struct alloc_string *strings;/* Local functions. */static void cpp_line PARAMS ((const char *));static char *handle_quotes PARAMS ((const char *, unsigned long *));static char *get_string PARAMS ((int));%}%%"BEGIN" { MAYBE_RETURN (BEG); }"{" { MAYBE_RETURN (BEG); }"END" { MAYBE_RETURN (END); }"}" { MAYBE_RETURN (END); }"ACCELERATORS" { MAYBE_RETURN (ACCELERATORS); }"VIRTKEY" { MAYBE_RETURN (VIRTKEY); }"ASCII" { MAYBE_RETURN (ASCII); }"NOINVERT" { MAYBE_RETURN (NOINVERT); }"SHIFT" { MAYBE_RETURN (SHIFT); }"CONTROL" { MAYBE_RETURN (CONTROL); }"ALT" { MAYBE_RETURN (ALT); }"BITMAP" { MAYBE_RETURN (BITMAP); }"CURSOR" { MAYBE_RETURN (CURSOR); }"DIALOG" { MAYBE_RETURN (DIALOG); }"DIALOGEX" { MAYBE_RETURN (DIALOGEX); }"EXSTYLE" { MAYBE_RETURN (EXSTYLE); }"CAPTION" { MAYBE_RETURN (CAPTION); }"CLASS" { MAYBE_RETURN (CLASS); }"STYLE" { MAYBE_RETURN (STYLE); }"AUTO3STATE" { MAYBE_RETURN (AUTO3STATE); }"AUTOCHECKBOX" { MAYBE_RETURN (AUTOCHECKBOX); }"AUTORADIOBUTTON" { MAYBE_RETURN (AUTORADIOBUTTON); }"CHECKBOX" { MAYBE_RETURN (CHECKBOX); }"COMBOBOX" { MAYBE_RETURN (COMBOBOX); }"CTEXT" { MAYBE_RETURN (CTEXT); }"DEFPUSHBUTTON" { MAYBE_RETURN (DEFPUSHBUTTON); }"EDITTEXT" { MAYBE_RETURN (EDITTEXT); }"GROUPBOX" { MAYBE_RETURN (GROUPBOX); }"LISTBOX" { MAYBE_RETURN (LISTBOX); }"LTEXT" { MAYBE_RETURN (LTEXT); }"PUSHBOX" { MAYBE_RETURN (PUSHBOX); }"PUSHBUTTON" { MAYBE_RETURN (PUSHBUTTON); }"RADIOBUTTON" { MAYBE_RETURN (RADIOBUTTON); }"RTEXT" { MAYBE_RETURN (RTEXT); }"SCROLLBAR" { MAYBE_RETURN (SCROLLBAR); }"STATE3" { MAYBE_RETURN (STATE3); }"USERBUTTON" { MAYBE_RETURN (USERBUTTON); }"BEDIT" { MAYBE_RETURN (BEDIT); }"HEDIT" { MAYBE_RETURN (HEDIT); }"IEDIT" { MAYBE_RETURN (IEDIT); }"FONT" { MAYBE_RETURN (FONT); }"ICON" { MAYBE_RETURN (ICON); }"LANGUAGE" { MAYBE_RETURN (LANGUAGE); }"CHARACTERISTICS" { MAYBE_RETURN (CHARACTERISTICS); }"VERSION" { MAYBE_RETURN (VERSIONK); }"MENU" { MAYBE_RETURN (MENU); }"MENUEX" { MAYBE_RETURN (MENUEX); }"MENUITEM" { MAYBE_RETURN (MENUITEM); }"SEPARATOR" { MAYBE_RETURN (SEPARATOR); }"POPUP" { MAYBE_RETURN (POPUP); }"CHECKED" { MAYBE_RETURN (CHECKED); }"GRAYED" { MAYBE_RETURN (GRAYED); }"HELP" { MAYBE_RETURN (HELP); }"INACTIVE" { MAYBE_RETURN (INACTIVE); }"MENUBARBREAK" { MAYBE_RETURN (MENUBARBREAK); }"MENUBREAK" { MAYBE_RETURN (MENUBREAK); }"MESSAGETABLE" { MAYBE_RETURN (MESSAGETABLE); }"RCDATA" { MAYBE_RETURN (RCDATA); }"STRINGTABLE" { MAYBE_RETURN (STRINGTABLE); }"VERSIONINFO" { MAYBE_RETURN (VERSIONINFO); }"FILEVERSION" { MAYBE_RETURN (FILEVERSION); }"PRODUCTVERSION" { MAYBE_RETURN (PRODUCTVERSION); }"FILEFLAGSMASK" { MAYBE_RETURN (FILEFLAGSMASK); }"FILEFLAGS" { MAYBE_RETURN (FILEFLAGS); }"FILEOS" { MAYBE_RETURN (FILEOS); }"FILETYPE" { MAYBE_RETURN (FILETYPE); }"FILESUBTYPE" { MAYBE_RETURN (FILESUBTYPE); }"VALUE" { MAYBE_RETURN (VALUE); }"MOVEABLE" { MAYBE_RETURN (MOVEABLE); }"FIXED" { MAYBE_RETURN (FIXED); }"PURE" { MAYBE_RETURN (PURE); }"IMPURE" { MAYBE_RETURN (IMPURE); }"PRELOAD" { MAYBE_RETURN (PRELOAD); }"LOADONCALL" { MAYBE_RETURN (LOADONCALL); }"DISCARDABLE" { MAYBE_RETURN (DISCARDABLE); }"NOT" { MAYBE_RETURN (NOT); }"BLOCK"[ \t\n]*"\""[^\#\n]*"\"" { char *s, *send; /* This is a hack to let us parse version information easily. */ s = strchr (yytext, '"'); ++s; send = strchr (s, '"'); if (strncmp (s, "StringFileInfo", sizeof "StringFileInfo" - 1) == 0 && s + sizeof "StringFileInfo" - 1 == send) MAYBE_RETURN (BLOCKSTRINGFILEINFO); else if (strncmp (s, "VarFileInfo", sizeof "VarFileInfo" - 1) == 0 && s + sizeof "VarFileInfo" - 1 == send) MAYBE_RETURN (BLOCKVARFILEINFO); else { char *r; r = get_string (send - s + 1); strncpy (r, s, send - s); r[send - s] = '\0'; yylval.s = r; MAYBE_RETURN (BLOCK); } }"#"[^\n]* { cpp_line (yytext); }[0-9][x0-9A-Fa-f]*L { yylval.i.val = strtoul (yytext, 0, 0); yylval.i.dword = 1; MAYBE_RETURN (NUMBER); }[0-9][x0-9A-Fa-f]* { yylval.i.val = strtoul (yytext, 0, 0); yylval.i.dword = 0; MAYBE_RETURN (NUMBER); }("\""[^\"\n]*"\""[ \t]*)+ { char *s; unsigned long length; s = handle_quotes (yytext, &length); if (! rcdata_mode) { yylval.s = s; MAYBE_RETURN (QUOTEDSTRING); } else { yylval.ss.length = length; yylval.ss.s = s; MAYBE_RETURN (SIZEDSTRING); } }[A-Za-z][^ ,\t\r\n]* { char *s; /* I rejected comma in a string in order to handle VIRTKEY, CONTROL in an accelerator resource. This means that an unquoted file name can not contain a comma. I don't know what rc permits. */ s = get_string (strlen (yytext) + 1); strcpy (s, yytext); yylval.s = s; MAYBE_RETURN (STRING); }[\n] { ++rc_lineno; }[ \t\r]+ { /* ignore whitespace */ }. { MAYBE_RETURN (*yytext); }%%#ifndef yywrap/* This is needed for some versions of lex. */int yywrap (){ return 1;}#endif/* Handle a C preprocessor line. */static voidcpp_line (s) const char *s;{ int line; char *send, *fn; ++s; while (isspace ((unsigned char) *s)) ++s; line = strtol (s, &send, 0); if (*send != '\0' && ! isspace ((unsigned char) *send)) return; /* Subtract 1 because we are about to count the newline. */ rc_lineno = line - 1; s = send; while (isspace ((unsigned char) *s)) ++s; if (*s != '"') return; ++s; send = strchr (s, '"'); if (send == NULL) return; fn = (char *) xmalloc (send - s + 1); strncpy (fn, s, send - s); fn[send - s] = '\0'; free (rc_filename); rc_filename = fn; if (!initial_fn) { initial_fn = xmalloc (strlen (fn) + 1); strcpy(initial_fn, fn); } /* Allow the initial file, regardless of name. Suppress all other files if they end in ".h" (this allows included "*.rc") */ if (strcmp (initial_fn, fn) == 0 || strcmp (fn + strlen (fn) - 2, ".h") != 0) suppress_cpp_data = 0; else suppress_cpp_data = 1;}/* Handle a quoted string. The quotes are stripped. A pair of quotes in a string are turned into a single quote. Adjacent strings are merged separated by whitespace are merged, as in C. */static char *handle_quotes (input, len) const char *input; unsigned long *len;{ char *ret, *s; const char *t; int ch; ret = get_string (strlen (input) + 1); s = ret; t = input; if (*t == '"') ++t; while (*t != '\0') { if (*t == '\\') { ++t; switch (*t) { case '\0': rcparse_warning ("backslash at end of string"); break; case '\"': rcparse_warning ("use \"\" to put \" in a string"); break; case 'a': *s++ = ESCAPE_A; ++t; break; case 'b': *s++ = ESCAPE_B; ++t; break; case 'f': *s++ = ESCAPE_F; ++t; break; case 'n': *s++ = ESCAPE_N; ++t; break; case 'r': *s++ = ESCAPE_R; ++t; break; case 't': *s++ = ESCAPE_T; ++t; break; case 'v': *s++ = ESCAPE_V; ++t; break; case '\\': *s++ = *t++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': ch = *t - '0'; ++t; if (*t >= '0' && *t <= '7') { ch = (ch << 3) | (*t - '0'); ++t; if (*t >= '0' && *t <= '7') { ch = (ch << 3) | (*t - '0'); ++t; } } *s++ = ch; break; case 'x': ++t; ch = 0; while (1) { if (*t >= '0' && *t <= '9') ch = (ch << 4) | (*t - '0'); else if (*t >= 'a' && *t <= 'f') ch = (ch << 4) | (*t - 'a'); else if (*t >= 'A' && *t <= 'F') ch = (ch << 4) | (*t - 'A'); else break; ++t; } *s++ = ch; break; default: rcparse_warning ("unrecognized escape sequence"); *s++ = '\\'; *s++ = *t++; break; } } else if (*t != '"') *s++ = *t++; else if (t[1] == '\0') break; else if (t[1] == '"') { *s++ = '"'; t += 2; } else { ++t; assert (isspace ((unsigned char) *t)); while (isspace ((unsigned char) *t)) ++t; if (*t == '\0') break; assert (*t == '"'); ++t; } } *s = '\0'; *len = s - ret; return ret;}/* Allocate a string of a given length. */static char *get_string (len) int len;{ struct alloc_string *as; as = (struct alloc_string *) xmalloc (sizeof *as); as->s = xmalloc (len); as->next = strings; strings = as->next; return as->s;}/* Discard all the strings we have allocated. The parser calls this when it no longer needs them. */voidrcparse_discard_strings (){ struct alloc_string *as; as = strings; while (as != NULL) { struct alloc_string *n; free (as->s); n = as->next; free (as); as = n; } strings = NULL;}/* Enter rcdata mode. */voidrcparse_rcdata (){ rcdata_mode = 1;}/* Go back to normal mode from rcdata mode. */voidrcparse_normal (){ rcdata_mode = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -