File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / confuse / src / lexer.l
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:49:17 2021 UTC (4 years, 1 month ago) by misho
Branches: confuse, MAIN
CVS tags: v3_3, HEAD
confuse 3.3

    1: %{
    2: /*
    3:  * Copyright (c) 2002-2017  Martin Hedenfalk <martin@bzero.se>
    4:  *
    5:  * Permission to use, copy, modify, and/or distribute this software for any
    6:  * purpose with or without fee is hereby granted, provided that the above
    7:  * copyright notice and this permission notice appear in all copies.
    8:  *
    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16:  */
   17: 
   18: #include <assert.h>
   19: #include <ctype.h>
   20: #include <errno.h>
   21: 
   22: #ifdef HAVE_CONFIG_H
   23: # include <config.h>
   24: #endif
   25: 
   26: #ifndef HAVE_UNISTD_H
   27: # define YY_NO_UNISTD_H
   28: #else
   29: # include <unistd.h>			/* isatty() */
   30: #endif
   31: 
   32: #ifdef HAVE_STRING_H
   33: # include <string.h>
   34: #endif
   35: 
   36: /* Defines isatty() for non UNIX systems */
   37: #include "confuse.h"
   38: 
   39: #if defined(ENABLE_NLS) && defined(HAVE_GETTEXT)
   40: # include <libintl.h>
   41: # define _(str) dgettext(PACKAGE, str)
   42: #else
   43: # define _(str) str
   44: #endif
   45: #define N_(str) str
   46: 
   47: /*
   48:  * Prevent compilation of static input() function in generated code
   49:  * This function is never used but GCC 4.3 will warn about it.
   50:  */
   51: #define YY_NO_INPUT
   52: 
   53: typedef char * YYSTYPE;
   54: extern YYSTYPE cfg_yylval;
   55: 
   56: #define YY_DECL int cfg_yylex ( cfg_t *cfg )
   57: 
   58: /* temporary buffer for the quoted strings scanner
   59:  */
   60: #define CFG_QSTRING_BUFSIZ 32
   61: char *cfg_qstring = NULL;
   62: static size_t qstring_index = 0;
   63: static size_t qstring_len = 0;
   64: static void qputc(char ch);
   65: static void qput(cfg_t *cfg, char skip);
   66: static void qbeg(int state);
   67: static int  qend(cfg_t *cfg, int trim, int ret);
   68: static int  qstr(cfg_t *cfg, char skip, int ret);
   69: 
   70: #define MAX_INCLUDE_DEPTH 10
   71: struct {
   72:     FILE *fp;
   73:     char *filename;
   74:     unsigned int line;
   75: } cfg_include_stack[MAX_INCLUDE_DEPTH];
   76: int cfg_include_stack_ptr = 0;
   77: 
   78: void cfg_scan_fp_begin(FILE *fp);
   79: void cfg_scan_fp_end(void);
   80: 
   81: %}
   82: 
   83: %option noyywrap
   84: 
   85:  /* start conditions
   86:   */
   87: %x comment
   88: %x dq_str
   89: %x sq_str
   90: 
   91: %%
   92: 
   93: [ \t]+    /* eat up whitespace */
   94: 
   95: \n   cfg->line++; /* keep track of line number */
   96: 
   97:  /*
   98:   * handle one-line comments
   99:   *
  100:   * Note: Comments with lots of leading #### or //// are fully
  101:   *       consumed and are not included in CFGT_COMMENT yylval
  102:   */
  103: "#"{1,}.*   return qstr(cfg, '#', CFGT_COMMENT);
  104: "/"{2,}.*   return qstr(cfg, '/', CFGT_COMMENT);
  105: 
  106:  /* special keywords/symbols
  107:   */
  108: "{"         { cfg_yylval = yytext; return '{'; }
  109: "}"         { cfg_yylval = yytext; return '}'; }
  110: "("         { cfg_yylval = yytext; return '('; }
  111: ")"         { cfg_yylval = yytext; return ')'; }
  112: "="         { cfg_yylval = yytext; return '='; }
  113: "+="        { cfg_yylval = yytext; return '+'; }
  114: ","         { cfg_yylval = yytext; return ','; }
  115: 
  116:  /* handle multi-line C-style comments
  117:   */
  118: "/*"                    qbeg(comment);
  119: <comment>[^*\n]*        qput(NULL, 0);  /* anything that's not a '*' */
  120: <comment>"*"+[^*/\n]*   qput(NULL, 0);  /* '*'s not followed by '/'s */
  121: <comment>\n             qput(cfg, 0);
  122: <comment>[ \t]*"*"+"/"  return qend(cfg, 1, CFGT_COMMENT);
  123: 
  124:  /* handle C-style strings
  125:   */
  126: "\""    {
  127:     qstring_index = 0;
  128:     BEGIN(dq_str);
  129: }
  130: <dq_str>\"  { /* saw closing quote - all done */
  131:     BEGIN(INITIAL);
  132:     qputc('\0');
  133:     cfg_yylval = cfg_qstring;
  134:     return CFGT_STR;
  135: }
  136: <dq_str>$\{[^}]*\} { /* environment variable substitution */
  137:     char *var;
  138:     char *e;
  139:     yytext[strlen(yytext) - 1] = 0;
  140:     e = strchr(yytext+2, ':');
  141:     if(e && e[1] == '-')
  142:         *e = 0;
  143:     else
  144:         e = 0;
  145:     var = getenv(yytext+2);
  146:     if(!var && e)
  147:         var = e+2;
  148:     while(var && *var)
  149:         qputc(*var++);
  150: }
  151: <dq_str>\n   {
  152:     qputc('\n');
  153:     cfg->line++;
  154: }
  155: <dq_str>\\\n { /* allow continuing on next line */
  156:     /* no-op */
  157:     cfg->line++;
  158: }
  159: <dq_str>\\[0-7]{1,3} {  /* octal escape sequence */
  160:     unsigned int result;
  161:     sscanf(yytext + 1, "%o", &result);
  162:     if(result > 0xFF) {
  163:         cfg_error(cfg, _("invalid octal number '%s'"), yytext);
  164:         return 0;
  165:     }
  166:     qputc(result);
  167:  }
  168: <dq_str>\\[0-9]+   {
  169:     cfg_error(cfg, _("bad escape sequence '%s'"), yytext);
  170:     return 0;
  171: }
  172: <dq_str>"\\x"[0-9A-Fa-f]{1,2} { /* hexadecimal escape sequence */
  173:     unsigned int result;
  174:     sscanf(yytext + 2, "%x", &result);
  175:     qputc(result);
  176: }
  177: <dq_str>\\n  {
  178:     qputc('\n');
  179: }
  180: <dq_str>\\r  {
  181:     qputc('\r');
  182: }
  183: <dq_str>\\b  {
  184:     qputc('\b');
  185: }
  186: <dq_str>\\f  {
  187:     qputc('\f');
  188: }
  189: <dq_str>\\a  {
  190:     qputc('\007');
  191: }
  192: <dq_str>\\e  {
  193:     qputc('\033');
  194: }
  195: <dq_str>\\t  {
  196:     qputc('\t');
  197: }
  198: <dq_str>\\v  {
  199:     qputc('\v');
  200: }
  201: <dq_str>\\.  {
  202:     qputc(yytext[1]);
  203: }
  204: <dq_str>[^\\\"\n]  {
  205:     qputc(yytext[0]);
  206: }
  207: 
  208:     /* single-quoted string ('...') */
  209: "\'" {
  210:     qstring_index = 0;
  211:     BEGIN(sq_str);
  212: }
  213: <sq_str>\' { /* saw closing quote - all done */
  214:     BEGIN(INITIAL);
  215:     qputc('\0');
  216:     cfg_yylval = cfg_qstring;
  217:     return CFGT_STR;
  218: }
  219: <sq_str>\n   {
  220:     qputc('\n');
  221:     cfg->line++;
  222: }
  223: <sq_str>\\\n { /* allow continuing on next line */
  224:     /* no-op */
  225:     cfg->line++;
  226: }
  227: <sq_str>\\[\\\'] {
  228:     qputc(yytext[1]);
  229: }
  230: <sq_str>\\[^\\\'] {
  231:     qputc(yytext[0]);
  232:     qputc(yytext[1]);
  233: }
  234: <sq_str>[^\\\'\n]+ {
  235:     char *cp = yytext;
  236:     while (*cp != '\0')
  237:         qputc(*cp++);
  238: }
  239: <sq_str><<EOF>> {
  240:     cfg_error(cfg, _("unterminated string constant"));
  241:     return 0;
  242: }
  243: 
  244: <<EOF>> {
  245:     if (cfg_include_stack_ptr > 0)
  246:     {
  247:         --cfg_include_stack_ptr;
  248:         /* fp opened by cfg_lexer_include()? */
  249:         if (cfg_include_stack[cfg_include_stack_ptr].fp != cfg_yyin) {
  250:             ++cfg_include_stack_ptr;
  251:             return EOF;
  252:         }
  253:         free(cfg->filename);
  254:         cfg->filename = cfg_include_stack[cfg_include_stack_ptr].filename;
  255:         cfg->line = cfg_include_stack[cfg_include_stack_ptr].line;
  256:         fclose(cfg_yyin);
  257:         cfg_scan_fp_end();
  258:     }
  259:     else
  260:     {
  261:         return EOF;
  262:     }
  263: }
  264: 
  265: $\{[^}]*\} {
  266:     char *var;
  267:     char *e;
  268: 
  269:     yytext[strlen(yytext) - 1] = 0;
  270:     e = strchr(yytext+2, ':');
  271:     if (e && e[1] == '-')
  272:         *e = 0;
  273:     else
  274:         e = 0;
  275:     var = getenv(yytext+2);
  276:     if (!var && e)
  277:         var = e+2;
  278:     if (!var)
  279:         var = "";
  280:     cfg_yylval = var;
  281: 
  282:     return CFGT_STR;
  283: }
  284: 
  285:  /* an unquoted string
  286:   * a slash can't be followed by another slash (c++
  287:   * comment) or an asterisk (C multi-line comment)
  288:   */
  289: (\/[^ #\"\'\t\n\r={}()+,\/*]|[^ #\"\'\t\n\r={}()+,\*])+ {
  290:     cfg_yylval = yytext;
  291:     return CFGT_STR;
  292:  }
  293: 
  294: . /* eat any non-matching characters */
  295: 
  296: %%
  297: 
  298: void cfg_dummy_function(void)
  299: {
  300:     /* please compiler :-)
  301:      * otherwise "defined but not used" warning
  302:      */
  303:     yyunput(0, 0);
  304: }
  305: 
  306: int cfg_lexer_include(cfg_t *cfg, const char *filename)
  307: {
  308:     FILE *fp;
  309:     char *xfilename;
  310: 
  311:     if (cfg_include_stack_ptr >= MAX_INCLUDE_DEPTH)
  312:     {
  313:         cfg_error(cfg, _("includes nested too deeply"));
  314:         return CFG_PARSE_ERROR;
  315:     }
  316: 
  317:     cfg_include_stack[cfg_include_stack_ptr].filename = cfg->filename;
  318:     cfg_include_stack[cfg_include_stack_ptr].line = cfg->line;
  319: 
  320:     if (cfg->path)
  321:     {
  322:         xfilename = cfg_searchpath(cfg->path, filename);
  323:         if (!xfilename)
  324:         {
  325:             cfg_error(cfg, _("%s: Not found in search path"), filename);
  326:             return CFG_PARSE_ERROR;
  327:         }
  328:     }
  329:     else
  330:     {
  331:         xfilename = cfg_tilde_expand(filename);
  332:         if (!xfilename)
  333:         {
  334:             cfg_error(cfg, _("%s: Failed tilde expand"), filename);
  335:             return CFG_PARSE_ERROR;
  336:         }
  337:     }
  338: 
  339:     fp = fopen(xfilename, "r");
  340:     if (!fp)
  341:     {
  342:         cfg_error(cfg, "%s: %s", xfilename, strerror(errno));
  343:         free(xfilename);
  344:         return CFG_PARSE_ERROR;
  345:     }
  346: 
  347:     cfg_include_stack[cfg_include_stack_ptr].fp = fp;
  348:     cfg_include_stack_ptr++;
  349:     cfg->filename = xfilename;
  350:     cfg->line = 1;
  351:     cfg_scan_fp_begin(fp);
  352: 
  353:     return CFG_SUCCESS;
  354: }
  355: 
  356: /* write a character to the quoted string buffer, and reallocate as
  357:  * necessary
  358:  */
  359: static void qputc(char ch)
  360: {
  361:     if (qstring_index >= qstring_len) {
  362:         qstring_len += CFG_QSTRING_BUFSIZ;
  363:         cfg_qstring = (char *)realloc(cfg_qstring, qstring_len + 1);
  364:         assert(cfg_qstring);
  365:         memset(cfg_qstring + qstring_index, 0, CFG_QSTRING_BUFSIZ + 1);
  366:     }
  367:     cfg_qstring[qstring_index++] = ch;
  368: }
  369: 
  370: static void qput(cfg_t *cfg, char skip)
  371: {
  372:     char *cp;
  373: 
  374:     if (cfg)
  375: 	cfg->line++;
  376: 
  377:     cp = yytext;
  378: 
  379:     while (skip && *cp == skip)
  380: 	cp++;
  381: 
  382:     while (*cp)
  383:         qputc(*cp++);
  384: }
  385: 
  386: static void qbeg(int state)
  387: {
  388:     BEGIN(state);
  389:     qstring_index = 0;
  390:     if (cfg_qstring)
  391: 	memset(cfg_qstring, 0, qstring_len);
  392: }
  393: 
  394: static char *trim_whitespace(char *str, unsigned int len)
  395: {
  396:     if (!str || !str[0])
  397: 	return str;
  398: 
  399:     while (len > 1) {
  400: 	if ((str[len] == 0 || isspace(str[len])) && isspace(str[len - 1]))
  401: 	    len--;
  402: 	else
  403: 	    break;
  404:     }
  405:     str[len] = 0;
  406: 
  407:     while (isspace(*str))
  408: 	str++;
  409: 
  410:     return str;
  411: }
  412: 
  413: static int qend(cfg_t *cfg, int trim, int ret)
  414: {
  415:     char *ptr = cfg_qstring;
  416: 
  417:     BEGIN(INITIAL);
  418:     if (cfg)
  419: 	cfg->line++;
  420: 
  421:     if (trim)
  422: 	ptr = trim_whitespace(cfg_qstring, qstring_index);
  423:     else
  424: 	qputc('\0');
  425: 
  426:     cfg_yylval = ptr;
  427: 
  428:     return ret;
  429: }
  430: 
  431: static int qstr(cfg_t *cfg, char skip, int ret)
  432: {
  433:     qbeg(comment);
  434:     qput(cfg, skip);
  435: 
  436:     return qend(cfg, 1, ret);
  437: }
  438: 
  439: void cfg_scan_fp_begin(FILE *fp)
  440: {
  441:     cfg_yypush_buffer_state(cfg_yy_create_buffer(fp, YY_BUF_SIZE));
  442: }
  443: 
  444: void cfg_scan_fp_end(void)
  445: {
  446:     if (cfg_qstring)
  447: 	    free(cfg_qstring);
  448:     cfg_qstring = NULL;
  449:     qstring_index = qstring_len = 0;
  450:     cfg_yypop_buffer_state();
  451: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>