50
  	   =ˆÄÊ0¿Ç     ?ˆËÊƒ|A¿Ç #ú    ?/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
 */
%option nostdinit noyywrap never-interactive full ecs
%option 8bit nodefault yylineno
%x ASSIGN_VAL HELP STRING
%{

#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <xalloc.h>
#include "lkc.h"
#include "parser.tab.h"

#define YY_DECL		static int yylex1(void)

#define START_STRSIZE	16

static struct {
	struct file *file;
	int lineno;
} current_pos;

static int prev_prev_token = T_EOL;
static int prev_token = T_EOL;
static char *text;
static int text_size, text_asize;

struct buffer {
	struct buffer *parent;
	YY_BUFFER_STATE state;
};

static struct buffer *current_buf;

static int last_ts, first_ts;

static char *expand_token(const char *in, size_t n);
static void append_expanded_string(const char *in);
static void zconf_endhelp(void);
static void zconf_endfile(void);

static void new_string(void)
{
	text = xmalloc(START_STRSIZE);
	text_asize = START_STRSIZE;
	text_size = 0;
	*text = 0;
}

static void append_string(const char *str, int size)
{
	int new_size = text_size + size + 1;
	if (new_size > text_asize) {
		new_size += START_STRSIZE - 1;
		new_size &= -START_STRSIZE;
		text = xrealloc(text, new_size);
		text_asize = new_size;
	}
	memcpy(text + text_size, str, size);
	text_size += size;
	text[text_size] = 0;
}

static void alloc_string(const char *str, int size)
{
	text = xmalloc(size + 1);
	memcpy(text, str, size);
	text[size] = 0;
}

static void warn_ignored_character(char chr)
{
	fprintf(stderr,
	        "%s:%d:warning: ignoring unsupported character '%c'\n",
	        current_file->name, yylineno, chr);
}
%}

n	[A-Za-z0-9_-]

%%
	int str = 0;
	int ts, i;

#.*			/* ignore comment */
[ \t]*			/* whitespaces */
\\\n			/* escaped new line */
\n			return T_EOL;
"bool"			return T_BOOL;
"choice"		return T_CHOICE;
"comment"		return T_COMMENT;
"config"		return T_CONFIG;
"def_bool"		return T_DEF_BOOL;
"def_tristate"		return T_DEF_TRISTATE;
"default"		return T_DEFAULT;
"depends"		return T_DEPENDS;
"endchoice"		return T_ENDCHOICE;
"endif"			return T_ENDIF;
"endmenu"		return T_ENDMENU;
"help"			return T_HELP;
"hex"			return T_HEX;
"if"			return T_IF;
"imply"			return T_IMPLY;
"int"			return T_INT;
"mainmenu"		return T_MAINMENU;
"menu"			return T_MENU;
"menuconfig"		return T_MENUCONFIG;
"modules"		return T_MODULES;
"on"			return T_ON;
"optional"		return T_OPTIONAL;
"prompt"		return T_PROMPT;
"range"			return T_RANGE;
"select"		return T_SELECT;
"source"		return T_SOURCE;
"string"		return T_STRING;
"tristate"		return T_TRISTATE;
"visible"		return T_VISIBLE;
"||"			return T_OR;
"&&"			return T_AND;
"="			return T_EQUAL;
"!="			return T_UNEQUAL;
"<"			return T_LESS;
"<="			return T_LESS_EQUAL;
">"			return T_GREATER;
">="			return T_GREATER_EQUAL;
"!"			return T_NOT;
"("			return T_OPEN_PAREN;
")"			return T_CLOSE_PAREN;
":="			return T_COLON_EQUAL;
"+="			return T_PLUS_EQUAL;
\"|\'			{
				str = yytext[0];
				new_string();
				BEGIN(STRING);
			}
{n}+			{
				alloc_string(yytext, yyleng);
				yylval.string = text;
				return T_WORD;
			}
({n}|$)+		{
				/* this token includes at least one '$' */
				yylval.string = expand_token(yytext, yyleng);
				if (strlen(yylval.string))
					return T_WORD;
				free(yylval.string);
			}
.			warn_ignored_character(*yytext);

<ASSIGN_VAL>{
	[^[:blank:]\n]+.*	{
		alloc_string(yytext, yyleng);
		yylval.string = text;
		return T_ASSIGN_VAL;
	}
	\n	{ BEGIN(INITIAL); return T_EOL; }
	.
}

<STRING>{
	"$".*	append_expanded_string(yytext);
	[^$'"\\\n]+	{
		append_string(yytext, yyleng);
	}
	\\.?	{
		append_string(yytext + 1, yyleng - 1);
	}
	\'|\"	{
		if (str == yytext[0]) {
			BEGIN(INITIAL);
			yylval.string = text;
			return T_WORD_QUOTE;
		} else
			append_string(yytext, 1);
	}
	\n	{
		fprintf(stderr,
			"%s:%d:warning: multi-line strings not supported\n",
			zconf_curname(), zconf_lineno());
		unput('\n');
		BEGIN(INITIAL);
		yylval.string = text;
		return T_WORD_QUOTE;
	}
	<<EOF>>	{
		B