%top{ /* * Scanner for C declarations. * Copyright © 2011, 2021, 2023 Nick Bowler * * 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 3 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, see . */ #include #include "parse.h" } %option nodefault noyywrap bison-locations reentrant never-interactive %option extra-type="_Bool" %option prefix="cdecl__yy" %{ #include #include "cdecl-internal.h" #include "cdecl.h" #include "errmsg.h" #if HAVE_STRTOUMAX /* Best case, implementation provides strtoumax. */ # define STRTOUMAX strtoumax #elif HAVE_STRTOULL /* Fall back to strtoull, with possibly reduced range. */ #define STRTOUMAX strtoull #elif HAVE___STRTOULL /* HP-UX 11 has __strtoull in */ #define STRTOUMAX __strtoull #else /* Fall back to strtoul, with possibly reduced range. */ #define STRTOUMAX strtoul #endif #define dup_token() do { \ yylval->strval = malloc(yyleng+1); \ if (!yylval->strval) { \ cdecl__errmsg(CDECL__ENOMEM); \ return T_LEX_ERROR; \ } \ strcpy(yylval->strval, yytext); \ } while(0) static char *to_octal(char *dst, unsigned val) { unsigned i; for (i = 0; i < 3; i++) { *dst++ = '0' + ((val >> 6) & 7u); val <<= 3; } return dst; } /* * Convert a single character to a C-style character constant, including quote * characters. At most 7 bytes are written to the buffer for the longest * octal encoding, e.g., '\177' */ static void to_readable_ch(char *dst, char c) { unsigned char uc = c; unsigned i; char esc; /* * The 7 standard C control characters are contiguous in ASCII, * permitting a simple and compact lookup table; separating their * handling from backslash and quote characters hopefully allows * the compiler to recognize that. */ switch (c) { case '\a': i = 0; break; case '\b': i = 1; break; case '\t': i = 2; break; case '\n': i = 3; break; case '\v': i = 4; break; case '\f': i = 5; break; case '\r': i = 6; break; default: i = 7; break; } esc = "abtnvfr"[i]; /* Otherwise printable characters that should still be escaped. */ switch (c) { case '\\': case '\'': esc = c; break; } *dst++ = '\''; if (esc) { *dst++ = '\\'; *dst++ = esc; } else if (isprint(uc)) { *dst++ = c; } else { *dst++ = '\\'; dst = to_octal(dst, uc); } *dst++ = '\''; *dst++ = 0; } %} %s ENGLISH IDENT [_[:alpha:]][_[:alnum:]]* INTEGER 0x[[:xdigit:]]+|0[0-7]+|[[:digit:]]+ %% %{ if (yyextra) { yyextra = 0; BEGIN(ENGLISH); return T_ENGLISH; } %} "..." return T_ELLIPSIS; ";" return T_SEMICOLON; "*" return T_ASTERISK; "(" return T_LPAREN; ")" return T_RPAREN; "[" return T_LBRACKET; "]" return T_RBRACKET; "," return T_COMMA; "typedef" return T_TYPEDEF; "extern" return T_EXTERN; "static" return T_STATIC; "auto" return T_AUTO; "register" return T_REGISTER; "restrict" return T_RESTRICT; "volatile" return T_VOLATILE; "const" return T_CONST; "inline" return T_INLINE; "void" return T_VOID; "char" return T_CHAR; "short" return T_SHORT; "int" return T_INT; "long" return T_LONG; "float" return T_FLOAT; "double" return T_DOUBLE; "signed" return T_SIGNED; "unsigned" return T_UNSIGNED; "_Bool" return T_BOOL; "_Complex" return T_COMPLEX; "_Imaginary" return T_IMAGINARY; "struct" return T_STRUCT; "union" return T_UNION; "enum" return T_ENUM; {INTEGER} { char *end; errno = 0; yylval->uintval = STRTOUMAX(yytext, &end, 0); if (errno == ERANGE) { cdecl__errmsg(CDECL__ERANGE); return T_LEX_ERROR; } if (*end) { cdecl__errmsg(CDECL__EBADINT); return T_LEX_ERROR; } return T_UINT; } { "variable-length" return T_VLA; "type" return T_TYPE; "declare" return T_DECLARE; "pointer" return T_POINTER; "function" return T_FUNCTION; "returning" return T_RETURNING; "array" return T_ARRAY; "to" return T_TO; "of" return T_OF; "as" return T_AS; } {IDENT} { dup_token(); return T_IDENT; } [[:space:]]+ . { char buf[8]; to_readable_ch(buf, yytext[0]); cdecl__err(CDECL_ENOPARSE, _("syntax error, unexpected %s"), buf); return T_LEX_ERROR; }