xreftags \\(p?)xref(event|indattr|indevent|(ind)?analyzer|module|(ind)?func|stmt|field|script|var|attr|type|env|config|global(ind)?|utility)(nott)?
indtags  \\(item)?ind(vartype|event(type)?|func|module|weird|attr|analyzer|env|config|utility)
indtags2 \\(item)?ind(predef(func|var))
indtags3 \\(item)?ind(field)

bracearg	"{"[^}]*"}"

tags	{xreftags}|{indtags}
tags2	{indtags2}
tags3	{indtags3}

	void expand(const char* text, int extra);

%option main noyywrap

%x v v2

%%
	int verb_ch = 0;


"\\begin{verbatim}"	ECHO; BEGIN(v);
<v>"\\end{verbatim}"	ECHO; BEGIN(INITIAL);
<v>.|[^\\]*|\n		ECHO;

"\\verb".		{
			ECHO;
			verb_ch = yytext[yyleng - 1];
			BEGIN(v2);
			}
<v2>.|\n		{
			ECHO;
			if ( yytext[0] == verb_ch )
				BEGIN(INITIAL);
			}

{tags}{bracearg}		expand(yytext, 0);
{tags2}{bracearg}{bracearg}	expand(yytext, 1);
{tags3}{bracearg}{bracearg}	expand(yytext, 2);

[^\\]"_"		{
	putchar(yytext[0]);
	fputs("\\_", stdout);
	}

"\\sub"/[^a-zA-Z]	fputs("_", stdout);

%%

const char* expand_arg(const char* cp, char buf1[], char buf2[])
	{
	const char* tag_start = cp;

	while ( *cp != '}' )
		++cp;

	// Now have the whole tag.  Escape the underscores in the tag
	// and create a second, trailing version of the tag with
	// _'s changed to -'s.

	const char* tag_end = cp;
	int bp1 = 0, bp2 = 0;
	for ( cp = tag_start; cp < tag_end; ++cp )
		{
		if ( *cp == '_' )
			{
			buf1[bp1++] = '\\';
			buf1[bp1++] = *cp;

			buf2[bp2++] = '-';
			}

		else
			{
			buf1[bp1++] = buf2[bp2++] = *cp;
			}
		}

	buf1[bp1] = buf2[bp2] = 0;

	return tag_end;
	}

void expand(const char* text, int extra)
	{
	char buf1[512], buf2[512];

	const char* cp = text;

	while ( *cp != '{' )
		++cp;

	++cp;	// Move past '{'.

	const char* tag_start = cp;
	const char* tag_end = expand_arg(cp, buf1, buf2);

	fwrite(text, 1, tag_start - text, stdout);
	fputs(buf1, stdout);
	fputs("}{", stdout);
	fputs(buf2, stdout);
	fputs("}", stdout);

	if ( extra )
		{
		cp = tag_end + 1;	// Move past '}'.
		const char* tag_end = expand_arg(cp, buf1, buf2);

		fputs(buf1, stdout);
		fputs("}", stdout);

		if ( extra > 1 )
			{
			fputs(buf2, stdout);
			fputs("}", stdout);
			}
		}
	}
