summaryrefslogtreecommitdiff
path: root/cpp/cexp.y
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/cexp.y')
-rw-r--r--cpp/cexp.y591
1 files changed, 591 insertions, 0 deletions
diff --git a/cpp/cexp.y b/cpp/cexp.y
new file mode 100644
index 00000000000..c41aa25af14
--- /dev/null
+++ b/cpp/cexp.y
@@ -0,0 +1,591 @@
+/* Parse C expressions for CCCP.
+ Copyright (C) 1986 Free Software Foundation.
+
+ NO WARRANTY
+
+ BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
+NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
+WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
+RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
+WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
+AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
+STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
+WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
+LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
+OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
+DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
+A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
+PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
+
+ GENERAL PUBLIC LICENSE TO COPY
+
+ 1. You may copy and distribute verbatim copies of this source file
+as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy a valid copyright notice
+"Copyright (C) 1986 Free Software Foundation"; and include
+following the copyright notice a verbatim copy of the above disclaimer
+of warranty and of this License.
+
+ 2. You may modify your copy or copies of this source file or
+any portion of it, and copy and distribute such modifications under
+the terms of Paragraph 1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish,
+ that in whole or in part contains or is a derivative of this
+ program or any part thereof, to be licensed at no charge to all
+ third parties on terms identical to those contained in this
+ License Agreement (except that you may choose to grant more extensive
+ warranty protection to some or all third parties, at your option).
+
+ c) You may charge a distribution fee for the physical act of
+ transferring a copy, and you may at your option offer warranty
+ protection in exchange for a fee.
+
+Mere aggregation of another unrelated program with this program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other program under the scope of these terms.
+
+ 3. You may copy and distribute this program (or a portion or derivative
+of it, under Paragraph 2) in object code or executable form under the terms
+of Paragraphs 1 and 2 above provided that you also do one of the following:
+
+ a) accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal
+ shipping charge) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+For an executable file, complete source code means all the source code for
+all modules it contains; but, as a special exception, it need not include
+source code for modules which are standard libraries that accompany the
+operating system on which the executable file runs.
+
+ 4. You may not copy, sublicense, distribute or transfer this program
+except as expressly provided under this License Agreement. Any attempt
+otherwise to copy, sublicense, distribute or transfer this program is void and
+your rights to use the program under this License agreement shall be
+automatically terminated. However, parties who have received computer
+software programs from you with this License Agreement will not have
+their licenses terminated so long as such parties remain in full compliance.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+
+ Adapted from expread.y of GDB by Paul Rubin, July 1986.
+
+/* Parse a C expression from text in a string */
+
+%{
+#include <setjmp.h>
+/* #define YYDEBUG 1 */
+
+ static int yylex ();
+ static yyerror ();
+ int expression_value;
+
+ static jmp_buf parse_return_error;
+
+ /* some external tables of character types */
+ extern unsigned char is_idstart[], is_idchar[];
+
+%}
+
+%union {
+ long lval;
+ int voidval;
+ char *sval;
+}
+
+%type <lval> exp exp1 start
+%token <lval> INT CHAR
+%token <sval> NAME
+%token <lval> ERROR
+
+%left ','
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY
+
+%%
+
+start : exp1
+ { expression_value = $1; }
+ ;
+
+/* Expressions, including the comma operator. */
+exp1 : exp
+ | exp1 ',' exp
+ { $$ = $3; }
+ ;
+
+/* Expressions, not including the comma operator. */
+exp : '-' exp %prec UNARY
+ { $$ = - $2; }
+ | '!' exp %prec UNARY
+ { $$ = ! $2; }
+ | '~' exp %prec UNARY
+ { $$ = ~ $2; }
+ | '(' exp1 ')'
+ { $$ = $2; }
+ ;
+
+/* Binary operators in order of decreasing precedence. */
+exp : exp '*' exp
+ { $$ = $1 * $3; }
+ | exp '/' exp
+ { $$ = $1 / $3; }
+ | exp '%' exp
+ { $$ = $1 % $3; }
+ | exp '+' exp
+ { $$ = $1 + $3; }
+ | exp '-' exp
+ { $$ = $1 - $3; }
+ | exp LSH exp
+ { $$ = $1 << $3; }
+ | exp RSH exp
+ { $$ = $1 >> $3; }
+ | exp EQUAL exp
+ { $$ = ($1 == $3); }
+ | exp NOTEQUAL exp
+ { $$ = ($1 != $3); }
+ | exp LEQ exp
+ { $$ = ($1 <= $3); }
+ | exp GEQ exp
+ { $$ = ($1 >= $3); }
+ | exp '<' exp
+ { $$ = ($1 < $3); }
+ | exp '>' exp
+ { $$ = ($1 > $3); }
+ | exp '&' exp
+ { $$ = ($1 & $3); }
+ | exp '^' exp
+ { $$ = ($1 ^ $3); }
+ | exp '|' exp
+ { $$ = ($1 | $3); }
+ | exp AND exp
+ { $$ = ($1 && $3); }
+ | exp OR exp
+ { $$ = ($1 || $3); }
+ | exp '?' exp ':' exp
+ { $$ = $1 ? $3 : $5; }
+ | INT
+ { $$ = yylval.lval; }
+ | CHAR
+ { $$ = yylval.lval; }
+ | NAME
+ { $$ = 0; }
+ ;
+%%
+
+/* During parsing of a C expression, the pointer to the next character
+ is in this variable. */
+
+static char *lexptr;
+
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr.
+ LEN is the number of characters in it. */
+
+/* maybe needs to actually deal with floating point numbers */
+
+static int
+parse_number (olen)
+ int olen;
+{
+ register char *p = lexptr;
+ register long n = 0;
+ register int c;
+ register int base = 10;
+ register len = olen;
+ char *err_copy;
+
+ extern double atof ();
+
+ for (c = 0; c < len; c++)
+ if (p[c] == '.') {
+ /* It's a float since it contains a point. */
+ yyerror ("floating point numbers not allowed in #if expressions");
+ return ERROR;
+
+/* ****************
+ yylval.dval = atof (p);
+ lexptr += len;
+ return FLOAT;
+ **************** */
+ }
+
+ if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ else if (*p == '0')
+ base = 8;
+
+ while (len-- > 0) {
+ c = *p++;
+ n *= base;
+ if (c >= '0' && c <= '9')
+ n += c - '0';
+ else {
+ if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
+ if (base == 16 && c >= 'a' && c <= 'f')
+ n += c - 'a' + 10;
+ else if (len == 0 && c == 'l')
+ ;
+ else {
+ yyerror ("Invalid number in #if expression");
+ return ERROR;
+ }
+ }
+ }
+
+ lexptr = p;
+ yylval.lval = n;
+ return INT;
+}
+
+struct token {
+ char *operator;
+ int token;
+};
+
+#define NULL 0
+
+static struct token tokentab2[] = {
+ {"&&", AND},
+ {"||", OR},
+ {"<<", LSH},
+ {">>", RSH},
+ {"==", EQUAL},
+ {"!=", NOTEQUAL},
+ {"<=", LEQ},
+ {">=", GEQ},
+ {NULL, ERROR}
+};
+
+/* Read one token, getting characters through lexptr. */
+
+static int
+yylex ()
+{
+ register int c;
+ register int namelen;
+ register char *tokstart;
+ register struct token *toktab;
+
+ retry:
+
+ tokstart = lexptr;
+ c = *tokstart;
+ /* See if it is a special token of length 2. */
+ for (toktab = tokentab2; toktab->operator != NULL; toktab++)
+ if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
+ lexptr += 2;
+ return toktab->token;
+ }
+
+ switch (c) {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '\'':
+ lexptr++;
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&lexptr);
+ yylval.lval = c;
+ c = *lexptr++;
+ if (c != '\'') {
+ yyerror ("Invalid character constant in #if");
+ return ERROR;
+ }
+
+ return CHAR;
+
+ case '/': /* possible comment */
+ if (*lexptr != '*')
+ return c;
+ for (;;) {
+ while (*lexptr != '\0') {
+ if (*lexptr++ == '*' && *lexptr == '/') {
+ lexptr++;
+ goto retry;
+ }
+ }
+ }
+
+ /* some of these chars are invalid in constant expressions;
+ maybe do something about them later */
+ case '+':
+ case '-':
+ case '*':
+ case '%':
+ case '|':
+ case '&':
+ case '^':
+ case '~':
+ case '!':
+ case '@':
+ case '<':
+ case '>':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '.':
+ case '?':
+ case ':':
+ case '=':
+ case '{':
+ case '}':
+ case ',':
+ lexptr++;
+ return c;
+
+ case '"':
+ yyerror ("double quoted strings not allowed in #if expressions");
+ return ERROR;
+ }
+ if (c >= '0' && c <= '9') {
+ /* It's a number */
+ for (namelen = 0;
+ c = tokstart[namelen], is_idchar[c] || c == '.';
+ namelen++)
+ ;
+ return parse_number (namelen);
+ }
+
+ if (!is_idstart[c]) {
+ yyerror ("Invalid token in expression");
+ return ERROR;
+ }
+
+ /* It is a name. See how long it is. */
+
+ for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++)
+ ;
+
+ lexptr += namelen;
+ return NAME;
+}
+
+
+/* Parse a C escape sequence. STRING_PTR points to a variable
+ containing a pointer to the string to parse. That pointer
+ is updated past the characters we use. The value of the
+ escape sequence is returned.
+
+ A negative value means the sequence \ newline was seen,
+ which is supposed to be equivalent to nothing at all.
+
+ If \ is followed by a null character, we return a negative
+ value and leave the string pointer pointing at the null character.
+
+ If \ is followed by 000, we return 0 and leave the string pointer
+ after the zeros. A value of 0 does not mean end of string. */
+
+static int
+parse_escape (string_ptr)
+ char **string_ptr;
+{
+ register int c = *(*string_ptr)++;
+ switch (c)
+ {
+ case 'a':
+ return '\a';
+ case 'b':
+ return '\b';
+ case 'e':
+ return 033;
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case 'v':
+ return '\v';
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+ case '^':
+ c = *(*string_ptr)++;
+ if (c == '\\')
+ c = parse_escape (string_ptr);
+ if (c == '?')
+ return 0177;
+ return (c & 0200) | (c & 037);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ register int i = c - '0';
+ register int count = 0;
+ while (++count < 3)
+ {
+ if ((c = *(*string_ptr)++) >= '0' && c <= '7')
+ {
+ i *= 8;
+ i += c - '0';
+ }
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ return i;
+ }
+ default:
+ return c;
+ }
+}
+
+static
+yyerror (s)
+ char *s;
+{
+ error (s);
+ longjmp (parse_return_error, 1);
+}
+
+/* This page contains the entry point to this file. */
+
+/* Parse STRING as an expression, and complain if this fails
+ to use up all of the contents of STRING. */
+int
+parse_c_expression (string)
+ char *string;
+{
+ lexptr = string;
+
+ if (lexptr == 0 || *lexptr == 0) {
+ error ("empty #if expression");
+ return 0; /* don't include the #if group */
+ }
+
+ /* if there is some sort of scanning error, just return 0 and assume
+ the parsing routine has printed an error message somewhere.
+ there is surely a better thing to do than this. */
+ if (setjmp(parse_return_error))
+ return 0;
+
+ if (yyparse ())
+ return 0; /* actually this is never reached
+ the way things stand. */
+ if (*lexptr)
+ error ("Junk after end of expression.");
+
+ return expression_value; /* set by yyparse() */
+}
+
+#ifdef TEST_EXP_READER
+/* main program, for testing purposes. */
+main()
+{
+ int n;
+ char buf[1024];
+ extern int yydebug;
+/*
+ yydebug = 1;
+*/
+ initialize_random_junk ();
+
+ for (;;) {
+ printf("enter expression: ");
+ n = 0;
+ while ((buf[n] = getchar()) != '\n')
+ n++;
+ buf[n] = '\0';
+ printf("parser returned %d\n", parse_c_expression(buf));
+ }
+}
+
+/* table to tell if char can be part of a C identifier. */
+char is_idchar[256];
+/* table to tell if char can be first char of a c identifier. */
+char is_idstart[256];
+/* table to tell if c is horizontal space. isspace() thinks that
+ newline is space; this is not a good idea for this program. */
+char is_hor_space[256];
+
+/*
+ * initialize random junk in the hash table and maybe other places
+ */
+initialize_random_junk()
+{
+ register int i;
+
+ /*
+ * Set up is_idchar and is_idstart tables. These should be
+ * faster than saying (is_alpha(c) || c == '_'), etc.
+ * Must do set up these things before calling any routines tthat
+ * refer to them.
+ */
+ for (i = 'a'; i <= 'z'; i++) {
+ ++is_idchar[i - 'a' + 'A'];
+ ++is_idchar[i];
+ ++is_idstart[i - 'a' + 'A'];
+ ++is_idstart[i];
+ }
+ for (i = '0'; i <= '9'; i++)
+ ++is_idchar[i];
+ ++is_idchar['_'];
+ ++is_idstart['_'];
+
+ /* horizontal space table */
+ ++is_hor_space[' '];
+ ++is_hor_space['\t'];
+}
+
+error (msg)
+{
+ printf("error: %s\n", msg);
+}
+#endif