xref: /Universal-ctags/parsers/tex.c (revision add23eb154df7c5e18d3c031dcb2076050775f3d)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO  *	 Copyright (c) 2008, David Fishburn
33ae02089SMasatake YAMATO  *	 Copyright (c) 2012, Jan Larres
43ae02089SMasatake YAMATO  *
53ae02089SMasatake YAMATO  *	 This source code is released for free distribution under the terms of the
60ce38835Sviccuad  *	 GNU General Public License version 2 or (at your option) any later version.
73ae02089SMasatake YAMATO  *
83ae02089SMasatake YAMATO  *	 This module contains functions for generating tags for TeX language files.
93ae02089SMasatake YAMATO  *
103ae02089SMasatake YAMATO  *	 Tex language reference:
113ae02089SMasatake YAMATO  *		 http://en.wikibooks.org/wiki/TeX#The_Structure_of_TeX
123ae02089SMasatake YAMATO  */
133ae02089SMasatake YAMATO 
143ae02089SMasatake YAMATO /*
153ae02089SMasatake YAMATO  *	 INCLUDE FILES
163ae02089SMasatake YAMATO  */
173ae02089SMasatake YAMATO #include "general.h"	/* must always come first */
183ae02089SMasatake YAMATO #include <ctype.h>	/* to define isalpha () */
193ae02089SMasatake YAMATO #ifdef DEBUG
203ae02089SMasatake YAMATO #include <stdio.h>
213ae02089SMasatake YAMATO #endif
22015ab54cSMasatake YAMATO #include <string.h>
233ae02089SMasatake YAMATO 
243ae02089SMasatake YAMATO #include "debug.h"
253ae02089SMasatake YAMATO #include "entry.h"
263ae02089SMasatake YAMATO #include "keyword.h"
273ae02089SMasatake YAMATO #include "parse.h"
283ae02089SMasatake YAMATO #include "read.h"
293ae02089SMasatake YAMATO #include "routines.h"
303ae02089SMasatake YAMATO #include "vstring.h"
313ae02089SMasatake YAMATO 
323b13813cSMasatake YAMATO #include "tex.h"
333b13813cSMasatake YAMATO 
343ae02089SMasatake YAMATO /*
353ae02089SMasatake YAMATO  *	 MACROS
363ae02089SMasatake YAMATO  */
37ce990805SThomas Braun #define isType(token,t)		(bool) ((token)->type == (t))
38ce990805SThomas Braun #define isKeyword(token,k)	(bool) ((token)->keyword == (k))
392b28d0e0SJiří Techet #define isIdentChar(c) \
40b2e27320SColomban Wendling 	(isalpha (c) || isdigit (c) || (c) >= 0x80 || (c) == '$' || \
412b28d0e0SJiří Techet 		(c) == '_' || (c) == '#' || (c) == '-' || (c) == '.' || (c) == ':')
423ae02089SMasatake YAMATO 
433ae02089SMasatake YAMATO /*
443ae02089SMasatake YAMATO  *	 DATA DECLARATIONS
453ae02089SMasatake YAMATO  */
463ae02089SMasatake YAMATO 
473ae02089SMasatake YAMATO /*
483ae02089SMasatake YAMATO  * Used to specify type of keyword.
493ae02089SMasatake YAMATO  */
504faa2076SColomban Wendling enum eKeywordId {
513ae02089SMasatake YAMATO 	KEYWORD_part,
523ae02089SMasatake YAMATO 	KEYWORD_chapter,
533ae02089SMasatake YAMATO 	KEYWORD_section,
543ae02089SMasatake YAMATO 	KEYWORD_subsection,
553ae02089SMasatake YAMATO 	KEYWORD_subsubsection,
563ae02089SMasatake YAMATO 	KEYWORD_paragraph,
573ae02089SMasatake YAMATO 	KEYWORD_subparagraph,
583ae02089SMasatake YAMATO 	KEYWORD_label,
591cfa869bSMasatake YAMATO 	KEYWORD_include,
60f7be3a35SMasatake YAMATO 	KEYWORD_input,
611cfa869bSMasatake YAMATO 	KEYWORD_begin,
621cfa869bSMasatake YAMATO 	KEYWORD_end,
63b3ac7a43SMasatake YAMATO 	KEYWORD_bibitem,
6447b7253cSMasatake YAMATO 	KEYWORD_bibliography,
653e2c7ce9SMasatake YAMATO 	KEYWORD_newcommand,
66c359e13dSJiří Techet 	KEYWORD_renewcommand,
67c359e13dSJiří Techet 	KEYWORD_providecommand,
6804d5c984SJiří Techet 	KEYWORD_def,
69952983dbSJiří Techet 	KEYWORD_declaremathoperator,
70bcf90eddSJiří Techet 	KEYWORD_newenvironment,
71bcf90eddSJiří Techet 	KEYWORD_renewenvironment,
72aa63a3eaSJiří Techet 	KEYWORD_newtheorem,
733859e610SMasatake YAMATO 	KEYWORD_newcounter,
744faa2076SColomban Wendling };
754faa2076SColomban Wendling typedef int keywordId; /* to allow KEYWORD_NONE */
763ae02089SMasatake YAMATO 
7774756360SColomban Wendling enum eTokenType {
7874756360SColomban Wendling 	/* 0..255 are the byte's value.  Some are named for convenience */
7974756360SColomban Wendling 	TOKEN_OPEN_PAREN = '(',
8074756360SColomban Wendling 	TOKEN_CLOSE_PAREN = ')',
8174756360SColomban Wendling 	TOKEN_OPEN_CURLY = '{',
8274756360SColomban Wendling 	TOKEN_CLOSE_CURLY = '}',
8374756360SColomban Wendling 	TOKEN_OPEN_SQUARE = '[',
8474756360SColomban Wendling 	TOKEN_CLOSE_SQUARE = ']',
8574756360SColomban Wendling 	TOKEN_STAR = '*',
8674756360SColomban Wendling 	/* above is special types */
8774756360SColomban Wendling 	TOKEN_UNDEFINED = 256,
883ae02089SMasatake YAMATO 	TOKEN_KEYWORD,
893ae02089SMasatake YAMATO 	TOKEN_IDENTIFIER,
903ae02089SMasatake YAMATO 	TOKEN_STRING,
9174756360SColomban Wendling };
9274756360SColomban Wendling typedef int tokenType;
933ae02089SMasatake YAMATO 
943ae02089SMasatake YAMATO typedef struct sTokenInfo {
953ae02089SMasatake YAMATO 	tokenType		type;
963ae02089SMasatake YAMATO 	keywordId		keyword;
973ae02089SMasatake YAMATO 	vString *		string;
983ae02089SMasatake YAMATO 	vString *		scope;
993ae02089SMasatake YAMATO 	unsigned long 	lineNumber;
100509a47dbSJiří Techet 	MIOPos 			filePosition;
1013ae02089SMasatake YAMATO } tokenInfo;
1023ae02089SMasatake YAMATO 
1033ae02089SMasatake YAMATO /*
1043ae02089SMasatake YAMATO  *	DATA DEFINITIONS
1053ae02089SMasatake YAMATO  */
1063ae02089SMasatake YAMATO 
107970f6116SJiří Techet static langType Lang_tex;
1083ae02089SMasatake YAMATO 
1093ae02089SMasatake YAMATO static vString *lastPart;
1103ae02089SMasatake YAMATO static vString *lastChapter;
1113ae02089SMasatake YAMATO static vString *lastSection;
1123ae02089SMasatake YAMATO static vString *lastSubS;
1133ae02089SMasatake YAMATO static vString *lastSubSubS;
1143ae02089SMasatake YAMATO 
1153ae02089SMasatake YAMATO typedef enum {
1163ae02089SMasatake YAMATO 	TEXTAG_PART,
1173ae02089SMasatake YAMATO 	TEXTAG_CHAPTER,
1183ae02089SMasatake YAMATO 	TEXTAG_SECTION,
1193ae02089SMasatake YAMATO 	TEXTAG_SUBSECTION,
1203ae02089SMasatake YAMATO 	TEXTAG_SUBSUBSECTION,
1213ae02089SMasatake YAMATO 	TEXTAG_PARAGRAPH,
1223ae02089SMasatake YAMATO 	TEXTAG_SUBPARAGRAPH,
1233ae02089SMasatake YAMATO 	TEXTAG_LABEL,
124f7be3a35SMasatake YAMATO 	TEXTAG_XINPUT,
125b3ac7a43SMasatake YAMATO 	TEXTAG_BIBITEM,
1263e2c7ce9SMasatake YAMATO 	TEXTAG_COMMAND,
127952983dbSJiří Techet 	TEXTAG_OPERATOR,
128bcf90eddSJiří Techet 	TEXTAG_ENVIRONMENT,
129aa63a3eaSJiří Techet 	TEXTAG_THEOREM,
1303859e610SMasatake YAMATO 	TEXTAG_COUNTER,
1313ae02089SMasatake YAMATO 	TEXTAG_COUNT
1323ae02089SMasatake YAMATO } texKind;
1333ae02089SMasatake YAMATO 
134f7be3a35SMasatake YAMATO typedef enum {
135f7be3a35SMasatake YAMATO 	TEX_XINPUT_INCLUDED,
136f7be3a35SMasatake YAMATO 	TEX_XINPUT_INPUT,
13747b7253cSMasatake YAMATO 	TEX_XINPUT_BIBLIOGRAPHY,
138f7be3a35SMasatake YAMATO } texInputRole;
139f7be3a35SMasatake YAMATO 
1406e18762eSJiří Techet typedef enum {
1416e18762eSJiří Techet 	TEX_ENVIRONMENT_USED,
1426e18762eSJiří Techet } texEnvironmentRole;
1436e18762eSJiří Techet 
144f7be3a35SMasatake YAMATO static roleDefinition TexInputRoles [] = {
145f7be3a35SMasatake YAMATO 	{ true, "included",
146f7be3a35SMasatake YAMATO 	  "external input file specified with \\include" },
147f7be3a35SMasatake YAMATO 	{ true, "input",
148f7be3a35SMasatake YAMATO 	  "external input file specified with \\input" },
14947b7253cSMasatake YAMATO 	{ true, "bibliography",
15047b7253cSMasatake YAMATO 	  "bibliography (.bib) file" },
151f7be3a35SMasatake YAMATO };
152f7be3a35SMasatake YAMATO 
1536e18762eSJiří Techet static roleDefinition TexEnvironmentRoles [] = {
1546e18762eSJiří Techet 	{ false, "used", "environment usage introduced by \\begin{MyEnv}" },
1556e18762eSJiří Techet };
1566e18762eSJiří Techet 
157e112e8abSMasatake YAMATO static kindDefinition TexKinds [] = {
158ce990805SThomas Braun 	{ true,  'p', "part",			  "parts"			   },
159ce990805SThomas Braun 	{ true,  'c', "chapter",		  "chapters"		   },
160ce990805SThomas Braun 	{ true,  's', "section",		  "sections"		   },
161ce990805SThomas Braun 	{ true,  'u', "subsection",		  "subsections"		   },
162ce990805SThomas Braun 	{ true,  'b', "subsubsection",	  "subsubsections"	   },
163ce990805SThomas Braun 	{ true,  'P', "paragraph",		  "paragraphs"		   },
164ce990805SThomas Braun 	{ true,  'G', "subparagraph",	  "subparagraphs"	   },
165ce990805SThomas Braun 	{ true,  'l', "label",			  "labels"			   },
166f7be3a35SMasatake YAMATO 	{ true,  'i', "xinput",			  "external input files",
167f7be3a35SMasatake YAMATO 	  .referenceOnly = true, ATTACH_ROLES(TexInputRoles)   },
168b3ac7a43SMasatake YAMATO 	{ true,  'B', "bibitem",		  "bibliography items" },
1693e2c7ce9SMasatake YAMATO 	{ true,  'C', "command",		  "command created with \\newcommand" },
170952983dbSJiří Techet 	{ true,  'o', "operator",		  "math operator created with \\DeclareMathOperator" },
1716e18762eSJiří Techet 	{ true,  'e', "environment",	  "environment created with \\newenvironment",
1726e18762eSJiří Techet 	  .referenceOnly = false, ATTACH_ROLES(TexEnvironmentRoles) },
173aa63a3eaSJiří Techet 	{ true,  't', "theorem",		  "theorem created with \\newtheorem" },
1743859e610SMasatake YAMATO 	{ true,  'N', "counter",		  "counter created with \\newcounter" },
1753ae02089SMasatake YAMATO };
1763ae02089SMasatake YAMATO 
17782c11d8cSRich Siegel static const keywordTable TexKeywordTable [] = {
1783ae02089SMasatake YAMATO 	/* keyword			keyword ID */
1793ae02089SMasatake YAMATO 	{ "part",			KEYWORD_part				},
1803ae02089SMasatake YAMATO 	{ "chapter",		KEYWORD_chapter				},
1813ae02089SMasatake YAMATO 	{ "section",		KEYWORD_section				},
1823ae02089SMasatake YAMATO 	{ "subsection",		KEYWORD_subsection			},
1833ae02089SMasatake YAMATO 	{ "subsubsection",	KEYWORD_subsubsection		},
1843ae02089SMasatake YAMATO 	{ "paragraph",		KEYWORD_paragraph			},
1853ae02089SMasatake YAMATO 	{ "subparagraph",	KEYWORD_subparagraph		},
1863ae02089SMasatake YAMATO 	{ "label",			KEYWORD_label				},
1871cfa869bSMasatake YAMATO 	{ "include",		KEYWORD_include				},
188f7be3a35SMasatake YAMATO 	{ "input",			KEYWORD_input				},
1891cfa869bSMasatake YAMATO 	{ "begin",			KEYWORD_begin				},
1901cfa869bSMasatake YAMATO 	{ "end",			KEYWORD_end					},
191b3ac7a43SMasatake YAMATO 	{ "bibitem",		KEYWORD_bibitem				},
19247b7253cSMasatake YAMATO 	{ "bibliography",	KEYWORD_bibliography		},
1933e2c7ce9SMasatake YAMATO 	{ "newcommand",		KEYWORD_newcommand			},
194c359e13dSJiří Techet 	{ "renewcommand",	KEYWORD_renewcommand		},
195c359e13dSJiří Techet 	{ "providecommand",	KEYWORD_providecommand		},
19604d5c984SJiří Techet 	{ "def",			KEYWORD_def					},
197952983dbSJiří Techet 	{ "DeclareMathOperator",	KEYWORD_declaremathoperator	},
198bcf90eddSJiří Techet 	{ "newenvironment",	KEYWORD_newenvironment		},
199bcf90eddSJiří Techet 	{ "renewenvironment",	KEYWORD_renewenvironment},
200aa63a3eaSJiří Techet 	{ "newtheorem",		KEYWORD_newtheorem			},
2013859e610SMasatake YAMATO 	{ "newcounter",		KEYWORD_newcounter			},
2023ae02089SMasatake YAMATO };
2033ae02089SMasatake YAMATO 
2043ae02089SMasatake YAMATO /*
2053b13813cSMasatake YAMATO  * FUNCTION DECLARATIONS
2063b13813cSMasatake YAMATO  */
2073b13813cSMasatake YAMATO 
2083b13813cSMasatake YAMATO static bool notifyReadingIdentifier  (tokenInfo *id_token, bool *tokenUnprocessed);
2091cfa869bSMasatake YAMATO static bool notifyReadingBeginEnvironment (tokenInfo *token, vString *envName, bool *tokenUnprocessed);
2101cfa869bSMasatake YAMATO static bool notifyReadingEndEnvironment (vString *envName);
2113b13813cSMasatake YAMATO 
2123b13813cSMasatake YAMATO 
2133b13813cSMasatake YAMATO /*
2143ae02089SMasatake YAMATO  *	 FUNCTION DEFINITIONS
2153ae02089SMasatake YAMATO  */
2163ae02089SMasatake YAMATO 
newToken(void)2173ae02089SMasatake YAMATO static tokenInfo *newToken (void)
2183ae02089SMasatake YAMATO {
2193ae02089SMasatake YAMATO 	tokenInfo *const token = xMalloc (1, tokenInfo);
2203ae02089SMasatake YAMATO 
2213ae02089SMasatake YAMATO 	token->type			= TOKEN_UNDEFINED;
2223ae02089SMasatake YAMATO 	token->keyword		= KEYWORD_NONE;
2233ae02089SMasatake YAMATO 	token->string		= vStringNew ();
2243ae02089SMasatake YAMATO 	token->scope		= vStringNew ();
225a31b37dcSMasatake YAMATO 	token->lineNumber   = getInputLineNumber ();
2263ae02089SMasatake YAMATO 	token->filePosition = getInputFilePosition ();
2273ae02089SMasatake YAMATO 
2283ae02089SMasatake YAMATO 	return token;
2293ae02089SMasatake YAMATO }
2303ae02089SMasatake YAMATO 
deleteToken(tokenInfo * const token)2313ae02089SMasatake YAMATO static void deleteToken (tokenInfo *const token)
2323ae02089SMasatake YAMATO {
2333ae02089SMasatake YAMATO 	vStringDelete (token->string);
2343ae02089SMasatake YAMATO 	vStringDelete (token->scope);
2353ae02089SMasatake YAMATO 	eFree (token);
2363ae02089SMasatake YAMATO }
2373ae02089SMasatake YAMATO 
getScopeInfo(texKind kind,vString * const parentName)238f92e6bf2SMasatake YAMATO static int getScopeInfo(texKind kind, vString *const parentName)
2393ae02089SMasatake YAMATO {
240f92e6bf2SMasatake YAMATO 	int parentKind = KIND_GHOST_INDEX;
2413ae02089SMasatake YAMATO 	int i;
2423ae02089SMasatake YAMATO 
2433ae02089SMasatake YAMATO 	/*
2443ae02089SMasatake YAMATO 	 * Put labels separately instead of under their scope.
2453ae02089SMasatake YAMATO 	 * Is this The Right Thing To Do?
2463ae02089SMasatake YAMATO 	 */
2473ae02089SMasatake YAMATO 	if (kind >= TEXTAG_LABEL) {
248f92e6bf2SMasatake YAMATO 		goto out;
2493ae02089SMasatake YAMATO 	}
2503ae02089SMasatake YAMATO 
2513ae02089SMasatake YAMATO 	/*
2523ae02089SMasatake YAMATO 	 * This abuses the enum internals somewhat, but it should be ok in this
2533ae02089SMasatake YAMATO 	 * case.
2543ae02089SMasatake YAMATO 	 */
255f92e6bf2SMasatake YAMATO 	/* TODO: This loop and conditions can be squashed. */
2563ae02089SMasatake YAMATO 	for (i = kind - 1; i >= TEXTAG_PART; --i) {
2573ae02089SMasatake YAMATO 		if (i == TEXTAG_SUBSECTION && vStringLength(lastSubS) > 0) {
258f92e6bf2SMasatake YAMATO 			parentKind = i;
2593ae02089SMasatake YAMATO 			break;
2603ae02089SMasatake YAMATO 		} else if (i == TEXTAG_SECTION && vStringLength(lastSection) > 0) {
261f92e6bf2SMasatake YAMATO 			parentKind = i;
2623ae02089SMasatake YAMATO 			break;
2633ae02089SMasatake YAMATO 		} else if (i == TEXTAG_CHAPTER && vStringLength(lastChapter) > 0) {
264f92e6bf2SMasatake YAMATO 			parentKind = i;
2653ae02089SMasatake YAMATO 			break;
2663ae02089SMasatake YAMATO 		} else if (i == TEXTAG_PART && vStringLength(lastPart) > 0) {
267f92e6bf2SMasatake YAMATO 			parentKind = i;
2683ae02089SMasatake YAMATO 			break;
2693ae02089SMasatake YAMATO 		}
2703ae02089SMasatake YAMATO 	}
2713ae02089SMasatake YAMATO 
2723ae02089SMasatake YAMATO 	/*
2733ae02089SMasatake YAMATO 	 * Is '""' the best way to separate scopes? It has to be something that
2743ae02089SMasatake YAMATO 	 * should ideally never occur in normal LaTeX text.
2753ae02089SMasatake YAMATO 	 */
2763ae02089SMasatake YAMATO 	for (i = TEXTAG_PART; i < (int)kind; ++i) {
2773ae02089SMasatake YAMATO 		if (i == TEXTAG_PART && vStringLength(lastPart) > 0) {
2783ae02089SMasatake YAMATO 			vStringCat(parentName, lastPart);
2793ae02089SMasatake YAMATO 		} else if (i == TEXTAG_CHAPTER && vStringLength(lastChapter) > 0) {
2803ae02089SMasatake YAMATO 			if (vStringLength(parentName) > 0) {
2813ae02089SMasatake YAMATO 				vStringCatS(parentName, "\"\"");
2823ae02089SMasatake YAMATO 			}
2833ae02089SMasatake YAMATO 			vStringCat(parentName, lastChapter);
2843ae02089SMasatake YAMATO 		} else if (i == TEXTAG_SECTION && vStringLength(lastSection) > 0) {
2853ae02089SMasatake YAMATO 			if (vStringLength(parentName) > 0) {
2863ae02089SMasatake YAMATO 				vStringCatS(parentName, "\"\"");
2873ae02089SMasatake YAMATO 			}
2883ae02089SMasatake YAMATO 			vStringCat(parentName, lastSection);
2893ae02089SMasatake YAMATO 		} else if (i == TEXTAG_SUBSECTION && vStringLength(lastSubS) > 0) {
2903ae02089SMasatake YAMATO 			if (vStringLength(parentName) > 0) {
2913ae02089SMasatake YAMATO 				vStringCatS(parentName, "\"\"");
2923ae02089SMasatake YAMATO 			}
2933ae02089SMasatake YAMATO 			vStringCat(parentName, lastSubS);
2943ae02089SMasatake YAMATO 		}
2953ae02089SMasatake YAMATO 	}
296f92e6bf2SMasatake YAMATO  out:
297f92e6bf2SMasatake YAMATO 	return parentKind;
2983ae02089SMasatake YAMATO }
2993ae02089SMasatake YAMATO 
3003ae02089SMasatake YAMATO /*
3013ae02089SMasatake YAMATO  *	 Tag generation functions
3023ae02089SMasatake YAMATO  */
303f67e271cSMasatake YAMATO 
304f67e271cSMasatake YAMATO struct symbolData {
305f67e271cSMasatake YAMATO 	langType lang;
306f67e271cSMasatake YAMATO 	int kind;
307f67e271cSMasatake YAMATO 	int *corkQueue;
308f67e271cSMasatake YAMATO };
309f67e271cSMasatake YAMATO 
findTheName(int corkIndex,tagEntryInfo * entry,void * data)3103afb5475SMasatake YAMATO static bool findTheName (int corkIndex, tagEntryInfo *entry, void *data)
311f67e271cSMasatake YAMATO {
312f67e271cSMasatake YAMATO 	struct symbolData *symbolData = data;
313f67e271cSMasatake YAMATO 
314f67e271cSMasatake YAMATO 	if (entry->langType == symbolData->lang && entry->kindIndex == symbolData->kind)
315f67e271cSMasatake YAMATO 	{
316f67e271cSMasatake YAMATO 		/* TODO: The case operation should be removed */
3173afb5475SMasatake YAMATO 		*symbolData->corkQueue = corkIndex;
318f67e271cSMasatake YAMATO 		return false;
319f67e271cSMasatake YAMATO 	}
320f67e271cSMasatake YAMATO 	return true;
321f67e271cSMasatake YAMATO }
322f67e271cSMasatake YAMATO 
makeTexTag(tokenInfo * const token,int kind,int roleIndex,bool unique,int scopeIndex)323ed565083SMasatake YAMATO static int makeTexTag (tokenInfo *const token, int kind,
324f67e271cSMasatake YAMATO 					   int roleIndex, bool unique, int scopeIndex)
3253ae02089SMasatake YAMATO {
326c28568d6SMasatake YAMATO 	int corkQueue = CORK_NIL;
3273ae02089SMasatake YAMATO 	const char *const name = vStringValue (token->string);
328f67e271cSMasatake YAMATO 
329f67e271cSMasatake YAMATO 	if (unique)
330f67e271cSMasatake YAMATO 	{
331f67e271cSMasatake YAMATO 		struct symbolData data = {
332f67e271cSMasatake YAMATO 			.lang = getInputLanguage(),
333f67e271cSMasatake YAMATO 			.kind = kind,
334f67e271cSMasatake YAMATO 			.corkQueue = &corkQueue,
335f67e271cSMasatake YAMATO 		};
336f67e271cSMasatake YAMATO 		/* TODO: The case operation should be removed */
3373afb5475SMasatake YAMATO 		if (foreachEntriesInScope (scopeIndex, name, findTheName, (void *)&data) == false)
338f67e271cSMasatake YAMATO 			return *data.corkQueue;
339f67e271cSMasatake YAMATO 	}
340f67e271cSMasatake YAMATO 
3413ae02089SMasatake YAMATO 	tagEntryInfo e;
34216a2541cSMasatake YAMATO 	initTagEntry (&e, name, kind);
3433ae02089SMasatake YAMATO 
3443ae02089SMasatake YAMATO 	e.lineNumber   = token->lineNumber;
3453ae02089SMasatake YAMATO 	e.filePosition = token->filePosition;
3463ae02089SMasatake YAMATO 
347ed565083SMasatake YAMATO 	vString *parentName = NULL;
348ed565083SMasatake YAMATO 
349f67e271cSMasatake YAMATO 
350f67e271cSMasatake YAMATO 	if (unique)
351f67e271cSMasatake YAMATO 		e.extensionFields.scopeIndex = scopeIndex;
352f67e271cSMasatake YAMATO 
353ed565083SMasatake YAMATO 	/* Filling e.extensionFields.scopeKindIndex and
354f67e271cSMasatake YAMATO 	 * e.extensionFields.scopeName can be filled from "kind" parameter
355f67e271cSMasatake YAMATO 	 * of this function only when Tex parser calls this function. The
356f67e271cSMasatake YAMATO 	 * fields cannot be filled with a kind defined in a subparser.
357f67e271cSMasatake YAMATO 	 * Subparsers may fill the scope after running strategy. So in the
358f67e271cSMasatake YAMATO 	 * context of a subparser, filling the scope fields here is not
359f67e271cSMasatake YAMATO 	 * needed.
360ed565083SMasatake YAMATO 	 */
361ed565083SMasatake YAMATO 	if (Lang_tex == getInputLanguage ())
362ed565083SMasatake YAMATO 	{
363ed565083SMasatake YAMATO 		int parentKind = KIND_GHOST_INDEX;
364ed565083SMasatake YAMATO 		parentName = vStringNew();
365f92e6bf2SMasatake YAMATO 		parentKind = getScopeInfo(kind, parentName);
366f92e6bf2SMasatake YAMATO 		if (parentKind != KIND_GHOST_INDEX) {
367f92e6bf2SMasatake YAMATO 			e.extensionFields.scopeKindIndex = parentKind;
368015ab54cSMasatake YAMATO 			e.extensionFields.scopeName = vStringValue(parentName);
3693ae02089SMasatake YAMATO 		}
370ed565083SMasatake YAMATO 	}
3713ae02089SMasatake YAMATO 
372993d4289SMasatake YAMATO 	assignRole (&e, roleIndex);
373993d4289SMasatake YAMATO 
374c28568d6SMasatake YAMATO 	corkQueue = makeTagEntry (&e);
375ed565083SMasatake YAMATO 	vStringDelete (parentName);	/* NULL is o.k. */
376f67e271cSMasatake YAMATO 
3773671ad72SMasatake YAMATO 	if (unique && corkQueue != CORK_NIL)
378f67e271cSMasatake YAMATO 		registerEntry (corkQueue);
379f67e271cSMasatake YAMATO 
380c28568d6SMasatake YAMATO 	return corkQueue;
3813ae02089SMasatake YAMATO }
3823ae02089SMasatake YAMATO 
3833ae02089SMasatake YAMATO /*
3843ae02089SMasatake YAMATO  *	 Parsing functions
3853ae02089SMasatake YAMATO  */
3863ae02089SMasatake YAMATO 
3873ae02089SMasatake YAMATO /*
3883ae02089SMasatake YAMATO  *	Read a C identifier beginning with "firstChar" and places it into
3893ae02089SMasatake YAMATO  *	"name".
3903ae02089SMasatake YAMATO  */
parseIdentifier(vString * const string,const int firstChar)3913ae02089SMasatake YAMATO static void parseIdentifier (vString *const string, const int firstChar)
3923ae02089SMasatake YAMATO {
3933ae02089SMasatake YAMATO 	int c = firstChar;
3943ae02089SMasatake YAMATO 	Assert (isIdentChar (c));
3953ae02089SMasatake YAMATO 	do
3963ae02089SMasatake YAMATO 	{
3973ae02089SMasatake YAMATO 		vStringPut (string, c);
398018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
399b2e27320SColomban Wendling 	} while (c != EOF && isIdentChar (c));
4003ae02089SMasatake YAMATO 
40174756360SColomban Wendling 	if (c != EOF)
40261f14fa5SMasatake YAMATO 		ungetcToInputFile (c);		/* unget non-identifier character */
4033ae02089SMasatake YAMATO }
4043ae02089SMasatake YAMATO 
readTokenFull(tokenInfo * const token,const bool includeWhitespaces)40574756360SColomban Wendling static bool readTokenFull (tokenInfo *const token, const bool includeWhitespaces)
4063ae02089SMasatake YAMATO {
4073ae02089SMasatake YAMATO 	int c;
40874756360SColomban Wendling 	int whitespaces = -1;
4093ae02089SMasatake YAMATO 
4103ae02089SMasatake YAMATO 	token->type			= TOKEN_UNDEFINED;
4113ae02089SMasatake YAMATO 	token->keyword		= KEYWORD_NONE;
4123ae02089SMasatake YAMATO 	vStringClear (token->string);
4133ae02089SMasatake YAMATO 
4143ae02089SMasatake YAMATO getNextChar:
41574756360SColomban Wendling 
4163ae02089SMasatake YAMATO 	do
4173ae02089SMasatake YAMATO 	{
418018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
41974756360SColomban Wendling 		whitespaces++;
4203ae02089SMasatake YAMATO 	}
4213ae02089SMasatake YAMATO 	while (c == '\t'  ||  c == ' ' ||  c == '\n');
4223ae02089SMasatake YAMATO 
423a0dc727aSColomban Wendling 	token->lineNumber   = getInputLineNumber ();
424a0dc727aSColomban Wendling 	token->filePosition = getInputFilePosition ();
425a0dc727aSColomban Wendling 
42674756360SColomban Wendling 	if (includeWhitespaces && whitespaces > 0 && c != '%' && c != EOF)
42774756360SColomban Wendling 	{
42874756360SColomban Wendling 		ungetcToInputFile (c);
42974756360SColomban Wendling 		c = ' ';
43074756360SColomban Wendling 	}
43174756360SColomban Wendling 
43274756360SColomban Wendling 	token->type = (unsigned char) c;
4333ae02089SMasatake YAMATO 	switch (c)
4343ae02089SMasatake YAMATO 	{
435969a87f4SMasatake YAMATO 		case EOF: return false;
4363ae02089SMasatake YAMATO 
4373ae02089SMasatake YAMATO 		case '\\':
4383ae02089SMasatake YAMATO 				  /*
4393ae02089SMasatake YAMATO 				   * All Tex tags start with a backslash.
4403ae02089SMasatake YAMATO 				   * Check if the next character is an alpha character
4413ae02089SMasatake YAMATO 				   * else it is not a potential tex tag.
4423ae02089SMasatake YAMATO 				   */
443018bce0bSMasatake YAMATO 				  c = getcFromInputFile ();
4443ae02089SMasatake YAMATO 				  if (! isalpha (c))
44561f14fa5SMasatake YAMATO 					  ungetcToInputFile (c);
4463ae02089SMasatake YAMATO 				  else
4473ae02089SMasatake YAMATO 				  {
44874756360SColomban Wendling 					  vStringPut (token->string, '\\');
4493ae02089SMasatake YAMATO 					  parseIdentifier (token->string, c);
45074756360SColomban Wendling 					  token->keyword = lookupKeyword (vStringValue (token->string) + 1, Lang_tex);
4513ae02089SMasatake YAMATO 					  if (isKeyword (token, KEYWORD_NONE))
4523ae02089SMasatake YAMATO 						  token->type = TOKEN_IDENTIFIER;
4533ae02089SMasatake YAMATO 					  else
4543ae02089SMasatake YAMATO 						  token->type = TOKEN_KEYWORD;
4553ae02089SMasatake YAMATO 				  }
4563ae02089SMasatake YAMATO 				  break;
4573ae02089SMasatake YAMATO 
4583ae02089SMasatake YAMATO 		case '%':
4594fffc5afSMasatake YAMATO 				  skipToCharacterInInputFile ('\n'); /* % are single line comments */
4603ae02089SMasatake YAMATO 				  goto getNextChar;
4613ae02089SMasatake YAMATO 				  break;
4623ae02089SMasatake YAMATO 
4633ae02089SMasatake YAMATO 		default:
46474756360SColomban Wendling 				  if (isIdentChar (c))
4653ae02089SMasatake YAMATO 				  {
4663ae02089SMasatake YAMATO 					  parseIdentifier (token->string, c);
4673ae02089SMasatake YAMATO 					  token->type = TOKEN_IDENTIFIER;
4683ae02089SMasatake YAMATO 				  }
4693ae02089SMasatake YAMATO 				  break;
4703ae02089SMasatake YAMATO 	}
471969a87f4SMasatake YAMATO 	return true;
4723ae02089SMasatake YAMATO }
4733ae02089SMasatake YAMATO 
readToken(tokenInfo * const token)47474756360SColomban Wendling static bool readToken (tokenInfo *const token)
47574756360SColomban Wendling {
47674756360SColomban Wendling 	return readTokenFull (token, false);
47774756360SColomban Wendling }
47874756360SColomban Wendling 
copyToken(tokenInfo * const dest,tokenInfo * const src)4793ae02089SMasatake YAMATO static void copyToken (tokenInfo *const dest, tokenInfo *const src)
4803ae02089SMasatake YAMATO {
4813ae02089SMasatake YAMATO 	dest->lineNumber = src->lineNumber;
4823ae02089SMasatake YAMATO 	dest->filePosition = src->filePosition;
4833ae02089SMasatake YAMATO 	dest->type = src->type;
4843ae02089SMasatake YAMATO 	dest->keyword = src->keyword;
4853ae02089SMasatake YAMATO 	vStringCopy (dest->string, src->string);
4863ae02089SMasatake YAMATO 	vStringCopy (dest->scope, src->scope);
4873ae02089SMasatake YAMATO }
4883ae02089SMasatake YAMATO 
updateScopeInfo(texKind kind,vString * fullname)4893566b8ecSMasatake YAMATO static void updateScopeInfo (texKind kind, vString *fullname)
4903566b8ecSMasatake YAMATO {
4913566b8ecSMasatake YAMATO 	switch (kind)
4923566b8ecSMasatake YAMATO 	{
4933566b8ecSMasatake YAMATO 		case TEXTAG_PART:
4943566b8ecSMasatake YAMATO 			vStringCopy(lastPart, fullname);
4953566b8ecSMasatake YAMATO 			vStringClear(lastChapter);
4963566b8ecSMasatake YAMATO 			vStringClear(lastSection);
4973566b8ecSMasatake YAMATO 			vStringClear(lastSubS);
4983566b8ecSMasatake YAMATO 			vStringClear(lastSubSubS);
4993566b8ecSMasatake YAMATO 			break;
5003566b8ecSMasatake YAMATO 		case TEXTAG_CHAPTER:
5013566b8ecSMasatake YAMATO 			vStringCopy(lastChapter, fullname);
5023566b8ecSMasatake YAMATO 			vStringClear(lastSection);
5033566b8ecSMasatake YAMATO 			vStringClear(lastSubS);
5043566b8ecSMasatake YAMATO 			vStringClear(lastSubSubS);
5053566b8ecSMasatake YAMATO 			break;
5063566b8ecSMasatake YAMATO 		case TEXTAG_SECTION:
5073566b8ecSMasatake YAMATO 			vStringCopy(lastSection, fullname);
5083566b8ecSMasatake YAMATO 			vStringClear(lastSubS);
5093566b8ecSMasatake YAMATO 			vStringClear(lastSubSubS);
5103566b8ecSMasatake YAMATO 			break;
5113566b8ecSMasatake YAMATO 		case TEXTAG_SUBSECTION:
5123566b8ecSMasatake YAMATO 			vStringCopy(lastSubS, fullname);
5133566b8ecSMasatake YAMATO 			vStringClear(lastSubSubS);
5143566b8ecSMasatake YAMATO 			break;
5153566b8ecSMasatake YAMATO 		case TEXTAG_SUBSUBSECTION:
5163566b8ecSMasatake YAMATO 			vStringCopy(lastSubSubS, fullname);
5173566b8ecSMasatake YAMATO 			break;
5183566b8ecSMasatake YAMATO 		default:
5193566b8ecSMasatake YAMATO 			break;
5203566b8ecSMasatake YAMATO 	}
5213566b8ecSMasatake YAMATO }
5223566b8ecSMasatake YAMATO 
5233ae02089SMasatake YAMATO /*
5243ae02089SMasatake YAMATO  *	 Scanning functions
5253ae02089SMasatake YAMATO  */
5263ae02089SMasatake YAMATO 
527d0937875SMasatake YAMATO /* STRATEGY array represents the sequence of * expected tokens. If an
528d0937875SMasatake YAMATO  * input token matches the current * expectation (the current strategy),
529d0937875SMasatake YAMATO  * parseWithStrategy() runs * the actions attached to the strategy.
530d0937875SMasatake YAMATO  *
531d0937875SMasatake YAMATO  * The actions are making a tag with the kind specified with kindIndex
532d0937875SMasatake YAMATO  * field of the current strategy and/or storing a name to NAME field
533d0937875SMasatake YAMATO  * of the current strategy.
534d0937875SMasatake YAMATO  *
535d0937875SMasatake YAMATO  * If the input token doesn't much the current strategy, above actions
536d0937875SMasatake YAMATO  * are not run. If TEX_NAME_FLAG_OPTIONAL is specified in FLAGS field
537d0937875SMasatake YAMATO  * of the current specified, parseWithStrategy() tries the next
538d0937875SMasatake YAMATO  * strategy of STRATEGY array without reading a new token.  If
539d0937875SMasatake YAMATO  * TEX_NAME_FLAG_OPTIONAL is not in FLAGS field, parseWithStrategy()
540d0937875SMasatake YAMATO  * returns the control to its caller immediately.
541d0937875SMasatake YAMATO  *
542d0937875SMasatake YAMATO  * TOKENUNPROCESSED is used for both input and output.  As input,
543d0937875SMasatake YAMATO  * TOKENUNPROCESSED tells whether parseWithStrategy() should read a
544d0937875SMasatake YAMATO  * new token before matching the STRATEGY array or not.  If
545d0937875SMasatake YAMATO  * TOKENUNPROCESSED is true, parseWithStrategy function reads a new
546d0937875SMasatake YAMATO  * token before matching.  As output, TOKENUNPROCESSED tells the
547d0937875SMasatake YAMATO  * caller of parseWithStrategy() that a new token is already stored to
548d0937875SMasatake YAMATO  * TOKEN but parseWithStrategy() has not processed yet.
549d0937875SMasatake YAMATO  */
parseWithStrategy(tokenInfo * token,struct TexParseStrategy * strategy,bool * tokenUnprocessed)550d0937875SMasatake YAMATO static bool parseWithStrategy (tokenInfo *token,
551d0937875SMasatake YAMATO 							   struct TexParseStrategy *strategy,
552d0937875SMasatake YAMATO 							   bool *tokenUnprocessed)
5533ae02089SMasatake YAMATO {
554d0937875SMasatake YAMATO 	bool next_token = !*tokenUnprocessed;
555d0937875SMasatake YAMATO 	tokenInfo * name = NULL;
556969a87f4SMasatake YAMATO 	bool eof = false;
557d0937875SMasatake YAMATO 	bool exclusive = false;
5583ae02089SMasatake YAMATO 
559d0937875SMasatake YAMATO 	for (struct TexParseStrategy *s = strategy; s->type != 0; ++s)
560d0937875SMasatake YAMATO 		s->corkIndex = CORK_NIL;
561d0937875SMasatake YAMATO 
562d0937875SMasatake YAMATO 	for (struct TexParseStrategy *s = strategy; !eof && s->type != 0; ++s)
563d0937875SMasatake YAMATO 	{
564d0937875SMasatake YAMATO 		if (s->kindIndex != KIND_GHOST_INDEX || s->name)
565d0937875SMasatake YAMATO 		{
566d0937875SMasatake YAMATO 			name = newToken ();
567d0937875SMasatake YAMATO 			break;
568d0937875SMasatake YAMATO 		}
569d0937875SMasatake YAMATO 	}
570d0937875SMasatake YAMATO 
571d0937875SMasatake YAMATO 	for (struct TexParseStrategy *s = strategy; !eof && s->type != 0; ++s)
572d0937875SMasatake YAMATO 	{
573d0937875SMasatake YAMATO 		bool capture_name = s->kindIndex != KIND_GHOST_INDEX || s->name;
574d0937875SMasatake YAMATO 
575d0937875SMasatake YAMATO 		if (next_token)
576d0937875SMasatake YAMATO 		{
577d0937875SMasatake YAMATO 			if (!readToken (token))
578d0937875SMasatake YAMATO 			{
579d0937875SMasatake YAMATO 				eof = true;
580d0937875SMasatake YAMATO 				break;
581d0937875SMasatake YAMATO 			}
582d0937875SMasatake YAMATO 		}
583d0937875SMasatake YAMATO 
584d0937875SMasatake YAMATO 		if ((s->type == '<' && isType (token, '<'))
585d0937875SMasatake YAMATO 			|| (s->type == '[' && isType (token, '[')))
586d0937875SMasatake YAMATO 		{
587d0937875SMasatake YAMATO 			tokenType terminator = (s->type == '<') ? '>' : ']';
588d0937875SMasatake YAMATO 
589d0937875SMasatake YAMATO 			next_token = true;
590d0937875SMasatake YAMATO 
591d0937875SMasatake YAMATO 
592d0937875SMasatake YAMATO 			if (!readToken (token))
593d0937875SMasatake YAMATO 			{
594d0937875SMasatake YAMATO 				eof = true;
595d0937875SMasatake YAMATO 				break;
596d0937875SMasatake YAMATO 			}
597d0937875SMasatake YAMATO 			if (capture_name)
598d0937875SMasatake YAMATO 			{
599d0937875SMasatake YAMATO 				copyToken (name, token);
600d0937875SMasatake YAMATO 				vStringClear (name->string);
601d0937875SMasatake YAMATO 			}
602d0937875SMasatake YAMATO 
603d0937875SMasatake YAMATO 			while (! isType (token, terminator))
604d0937875SMasatake YAMATO 			{
605d0937875SMasatake YAMATO 				if (capture_name && isType (token, TOKEN_IDENTIFIER))
606d0937875SMasatake YAMATO 				{
607d0937875SMasatake YAMATO 					if (vStringLength (name->string) > 0)
608d0937875SMasatake YAMATO 						vStringPut (name->string, ' ');
609d0937875SMasatake YAMATO 					vStringCat (name->string, token->string);
610d0937875SMasatake YAMATO 				}
611d0937875SMasatake YAMATO 
612d0937875SMasatake YAMATO 				if (!readTokenFull (token,
613d0937875SMasatake YAMATO 									s->flags & TEX_NAME_FLAG_INCLUDING_WHITESPACE))
614d0937875SMasatake YAMATO 				{
615d0937875SMasatake YAMATO 					eof = true;
616d0937875SMasatake YAMATO 					break;
617d0937875SMasatake YAMATO 				}
618d0937875SMasatake YAMATO 			}
619d0937875SMasatake YAMATO 			if (!exclusive && capture_name && vStringLength (name->string) > 0)
620d0937875SMasatake YAMATO 			{
621d0937875SMasatake YAMATO 				if (s->kindIndex != KIND_GHOST_INDEX)
622f67e271cSMasatake YAMATO 					s->corkIndex = makeTexTag (name, s->kindIndex, s->roleIndex,
623f67e271cSMasatake YAMATO 											   s->unique, s->scopeIndex);
624d0937875SMasatake YAMATO 
625d0937875SMasatake YAMATO 				if (s->name)
626d0937875SMasatake YAMATO 					vStringCopy(s->name, name->string);
627d0937875SMasatake YAMATO 
628d0937875SMasatake YAMATO 				if (s->flags & TEX_NAME_FLAG_EXCLUSIVE)
629d0937875SMasatake YAMATO 					exclusive = true;
630d0937875SMasatake YAMATO 			}
631d0937875SMasatake YAMATO 		}
632d0937875SMasatake YAMATO 		else if (s->type == '*' && isType (token, '*'))
633d0937875SMasatake YAMATO 			next_token = true;
634c6cbaf9cSJiří Techet 		else if (((s->type == '{' || s->type == '\\') && isType (token, '{')) ||
635c6cbaf9cSJiří Techet 			(s->type == '\\' && isType (token, TOKEN_IDENTIFIER)))
636d0937875SMasatake YAMATO 		{
637d0937875SMasatake YAMATO 			int depth = 1;
638c6cbaf9cSJiří Techet 			bool missing_parens = isType (token, TOKEN_IDENTIFIER);
639d0937875SMasatake YAMATO 
640d0937875SMasatake YAMATO 			next_token = true;
641d0937875SMasatake YAMATO 
642c6cbaf9cSJiří Techet 			if (!missing_parens && !readToken (token))
643d0937875SMasatake YAMATO 			{
644d0937875SMasatake YAMATO 				eof = true;
645d0937875SMasatake YAMATO 				break;
646d0937875SMasatake YAMATO 			}
647d0937875SMasatake YAMATO 			if (capture_name)
648d0937875SMasatake YAMATO 			{
649d0937875SMasatake YAMATO 				copyToken (name, token);
650d0937875SMasatake YAMATO 				vStringClear (name->string);
651d0937875SMasatake YAMATO 			}
652c6cbaf9cSJiří Techet 			if (missing_parens)
65304d5c984SJiří Techet 			{
65404d5c984SJiří Techet 				vStringCat (name->string, token->string);
65504d5c984SJiří Techet 				depth = 0;
65604d5c984SJiří Techet 			}
657d0937875SMasatake YAMATO 
658d0937875SMasatake YAMATO 			/* Handle the case the code like \section{} */
659d0937875SMasatake YAMATO 			if (isType (token, '}'))
660d0937875SMasatake YAMATO 				break;
661d0937875SMasatake YAMATO 			while (depth > 0)
662d0937875SMasatake YAMATO 			{
663d0937875SMasatake YAMATO 				if (capture_name)
664d0937875SMasatake YAMATO 				{
665d0937875SMasatake YAMATO 					if (isType (token, TOKEN_IDENTIFIER) || isType (token, TOKEN_KEYWORD))
666d0937875SMasatake YAMATO 						vStringCat (name->string, token->string);
667d0937875SMasatake YAMATO 					else
668d0937875SMasatake YAMATO 						vStringPut (name->string, token->type);
669d0937875SMasatake YAMATO 				}
670d0937875SMasatake YAMATO 				if (!readTokenFull (token,
671d0937875SMasatake YAMATO 									s->flags & TEX_NAME_FLAG_INCLUDING_WHITESPACE))
672d0937875SMasatake YAMATO 				{
673d0937875SMasatake YAMATO 					eof = true;
674d0937875SMasatake YAMATO 					break;
675d0937875SMasatake YAMATO 				}
676d0937875SMasatake YAMATO 				else if (isType (token, TOKEN_OPEN_CURLY))
677d0937875SMasatake YAMATO 					depth++;
678d0937875SMasatake YAMATO 				else if (isType (token, TOKEN_CLOSE_CURLY))
679d0937875SMasatake YAMATO 					depth--;
680d0937875SMasatake YAMATO 			}
681d0937875SMasatake YAMATO 			if (!exclusive && depth == 0 && capture_name && vStringLength (name->string) > 0)
682d0937875SMasatake YAMATO 			{
683d0937875SMasatake YAMATO 				vStringStripTrailing (name->string);
684d0937875SMasatake YAMATO 
685d0937875SMasatake YAMATO 				if (s->kindIndex != KIND_GHOST_INDEX)
686f67e271cSMasatake YAMATO 					s->corkIndex = makeTexTag (name, s->kindIndex, s->roleIndex,
687f67e271cSMasatake YAMATO 											   s->unique, s->scopeIndex);
688d0937875SMasatake YAMATO 
689d0937875SMasatake YAMATO 				if (s->name)
690d0937875SMasatake YAMATO 					vStringCopy(s->name, name->string);
691d0937875SMasatake YAMATO 
692d0937875SMasatake YAMATO 				if (s->flags & TEX_NAME_FLAG_EXCLUSIVE)
693d0937875SMasatake YAMATO 					exclusive = true;
694d0937875SMasatake YAMATO 
695d0937875SMasatake YAMATO 			}
696d0937875SMasatake YAMATO 		}
697d0937875SMasatake YAMATO 		else if (s->flags & TEX_NAME_FLAG_OPTIONAL)
698d0937875SMasatake YAMATO 			/* Apply next strategy to the same token */
699d0937875SMasatake YAMATO 			next_token = false;
700d0937875SMasatake YAMATO 		else
701d0937875SMasatake YAMATO 		{
702d0937875SMasatake YAMATO 			*tokenUnprocessed = true;
703d0937875SMasatake YAMATO 			break;
704d0937875SMasatake YAMATO 		}
705d0937875SMasatake YAMATO 	}
706d0937875SMasatake YAMATO 
707af6af4ddSJiří Techet 	/* The last token is optional and not present - let the caller know */
708af6af4ddSJiří Techet 	if (!next_token)
709af6af4ddSJiří Techet 		*tokenUnprocessed = true;
710af6af4ddSJiří Techet 
711d0937875SMasatake YAMATO 	if (name)
712d0937875SMasatake YAMATO 		deleteToken (name);
713d0937875SMasatake YAMATO 
714d0937875SMasatake YAMATO 	return eof;
715d0937875SMasatake YAMATO }
716d0937875SMasatake YAMATO 
parseTagFull(tokenInfo * const token,texKind kind,int roleIndex,bool enterSquare,bool * tokenUnprocessed)717f7be3a35SMasatake YAMATO static bool parseTagFull (tokenInfo *const token, texKind kind, int roleIndex, bool enterSquare, bool *tokenUnprocessed)
718d0937875SMasatake YAMATO {
719d0937875SMasatake YAMATO 	bool eof = false;
720d0937875SMasatake YAMATO 	vString *taggedName = vStringNew();
7213ae02089SMasatake YAMATO 
7223ae02089SMasatake YAMATO 	/*
7233ae02089SMasatake YAMATO 	 * Tex tags are of these formats:
7243ae02089SMasatake YAMATO 	 *   \keyword{any number of words}
7253ae02089SMasatake YAMATO 	 *   \keyword[short desc]{any number of words}
7263ae02089SMasatake YAMATO 	 *   \keyword*[short desc]{any number of words}
7273ae02089SMasatake YAMATO 	 *
7283ae02089SMasatake YAMATO 	 * When a keyword is found, loop through all words within
7293ae02089SMasatake YAMATO 	 * the curly braces for the tag name.
7305100d567SMasatake YAMATO 	 *
7315100d567SMasatake YAMATO 	 * If the keyword is label like \label, words in the square
7329173df85SMasatake YAMATO 	 * brackets should be skipped. This can be controlled
7339173df85SMasatake YAMATO 	 * with `enterSquare' parameter; true is for tagging, and
7349173df85SMasatake YAMATO 	 * false is for skipping.
7353ae02089SMasatake YAMATO 	 */
7363ae02089SMasatake YAMATO 
737d0937875SMasatake YAMATO 	struct TexParseStrategy strategy [] = {
7383ae02089SMasatake YAMATO 		{
739d0937875SMasatake YAMATO 			.type = '[',
740d0937875SMasatake YAMATO 			.flags = TEX_NAME_FLAG_OPTIONAL,
741d0937875SMasatake YAMATO 			/* .kindIndex is initialized dynamically. */
742d0937875SMasatake YAMATO 		},
743969a87f4SMasatake YAMATO 		{
744d0937875SMasatake YAMATO 			.type = '*',
745d0937875SMasatake YAMATO 			.flags = TEX_NAME_FLAG_OPTIONAL,
746d0937875SMasatake YAMATO 			.kindIndex = KIND_GHOST_INDEX,
747d0937875SMasatake YAMATO 			.name = NULL,
748d0937875SMasatake YAMATO 		},
749d0937875SMasatake YAMATO 		{
750d0937875SMasatake YAMATO 			.type = '{',
751d0937875SMasatake YAMATO 			.flags = TEX_NAME_FLAG_INCLUDING_WHITESPACE,
752d0937875SMasatake YAMATO 			.kindIndex = kind,
753f7be3a35SMasatake YAMATO 			.roleIndex = roleIndex,
754d0937875SMasatake YAMATO 			.name = taggedName,
755f67e271cSMasatake YAMATO 			.unique = false,
756d0937875SMasatake YAMATO 		},
757d0937875SMasatake YAMATO 		{
758d0937875SMasatake YAMATO 			.type = 0
759969a87f4SMasatake YAMATO 		}
760d0937875SMasatake YAMATO 	};
7613ae02089SMasatake YAMATO 
7623ae02089SMasatake YAMATO 
7635100d567SMasatake YAMATO 	if (enterSquare)
7645100d567SMasatake YAMATO 	{
765d0937875SMasatake YAMATO 		strategy [0].kindIndex = kind;
766f7be3a35SMasatake YAMATO 		strategy [0].roleIndex = roleIndex;
767d0937875SMasatake YAMATO 		strategy [0].flags |= TEX_NAME_FLAG_EXCLUSIVE;
768d0937875SMasatake YAMATO 		strategy [0].name = taggedName;
769f67e271cSMasatake YAMATO 		strategy [0].unique = false;
7703ae02089SMasatake YAMATO 	}
77174756360SColomban Wendling 	else
772d0937875SMasatake YAMATO 	{
773d0937875SMasatake YAMATO 		strategy [0].kindIndex = KIND_GHOST_INDEX;
774d0937875SMasatake YAMATO 		strategy [0].name = NULL;
7753ae02089SMasatake YAMATO 	}
776d0937875SMasatake YAMATO 
777d0937875SMasatake YAMATO 	if (parseWithStrategy (token, strategy, tokenUnprocessed))
778969a87f4SMasatake YAMATO 	{
779969a87f4SMasatake YAMATO 		eof = true;
780969a87f4SMasatake YAMATO 		goto out;
781969a87f4SMasatake YAMATO 	}
7823ae02089SMasatake YAMATO 
7833ae02089SMasatake YAMATO 	/*
7843ae02089SMasatake YAMATO 	 * save the name of the last section definitions for scope-resolution
7853ae02089SMasatake YAMATO 	 * later
7863ae02089SMasatake YAMATO 	 */
787d0937875SMasatake YAMATO 	if (vStringLength (taggedName) > 0)
788d0937875SMasatake YAMATO 		updateScopeInfo (kind, taggedName);
7893ae02089SMasatake YAMATO 
790969a87f4SMasatake YAMATO  out:
791d0937875SMasatake YAMATO 	vStringDelete (taggedName);
792d0937875SMasatake YAMATO 
793969a87f4SMasatake YAMATO 	return eof;
7943ae02089SMasatake YAMATO }
7953ae02089SMasatake YAMATO 
parseTag(tokenInfo * const token,texKind kind,bool enterSquare,bool * tokenUnprocessed)796f7be3a35SMasatake YAMATO static bool parseTag (tokenInfo *const token, texKind kind,
797f7be3a35SMasatake YAMATO 					  bool enterSquare, bool *tokenUnprocessed)
798f7be3a35SMasatake YAMATO {
799f7be3a35SMasatake YAMATO 	return parseTagFull (token, kind, ROLE_DEFINITION_INDEX,
800f7be3a35SMasatake YAMATO 						 enterSquare, tokenUnprocessed);
801f7be3a35SMasatake YAMATO }
802f7be3a35SMasatake YAMATO 
parseEnv(tokenInfo * const token,bool begin,bool * tokenUnprocessed)8031cfa869bSMasatake YAMATO static bool parseEnv (tokenInfo *const token, bool begin, bool *tokenUnprocessed)
8041cfa869bSMasatake YAMATO {
8051cfa869bSMasatake YAMATO 	bool eof = false;
8061cfa869bSMasatake YAMATO 	vString *envName = vStringNew ();
8071cfa869bSMasatake YAMATO 	struct TexParseStrategy strategy [] = {
8081cfa869bSMasatake YAMATO 		{
8091cfa869bSMasatake YAMATO 			.type = '{',
8101cfa869bSMasatake YAMATO 			.flags = TEX_NAME_FLAG_INCLUDING_WHITESPACE,
8116e18762eSJiří Techet 			.kindIndex = begin ? TEXTAG_ENVIRONMENT : KIND_GHOST_INDEX,
8126e18762eSJiří Techet 			.roleIndex = TEX_ENVIRONMENT_USED,
8131cfa869bSMasatake YAMATO 			.name = envName,
8141cfa869bSMasatake YAMATO 		},
8151cfa869bSMasatake YAMATO 		{
8161cfa869bSMasatake YAMATO 			.type = 0
8171cfa869bSMasatake YAMATO 		}
8181cfa869bSMasatake YAMATO 	};
8191cfa869bSMasatake YAMATO 
8201cfa869bSMasatake YAMATO 	if (parseWithStrategy (token, strategy, tokenUnprocessed))
8211cfa869bSMasatake YAMATO 	{
8221cfa869bSMasatake YAMATO 		eof = true;
8231cfa869bSMasatake YAMATO 		goto out;
8241cfa869bSMasatake YAMATO 	}
8251cfa869bSMasatake YAMATO 
8261cfa869bSMasatake YAMATO 
8271cfa869bSMasatake YAMATO 	if (vStringLength (envName) > 0)
8281cfa869bSMasatake YAMATO 	{
8291cfa869bSMasatake YAMATO 		if (begin)
8301cfa869bSMasatake YAMATO 			eof = notifyReadingBeginEnvironment (token, envName, tokenUnprocessed);
8311cfa869bSMasatake YAMATO 		else
8321cfa869bSMasatake YAMATO 			eof = notifyReadingEndEnvironment (envName);
8331cfa869bSMasatake YAMATO 	}
8341cfa869bSMasatake YAMATO 
8351cfa869bSMasatake YAMATO  out:
8361cfa869bSMasatake YAMATO 	vStringDelete (envName);
8371cfa869bSMasatake YAMATO 
8381cfa869bSMasatake YAMATO 	return eof;
8391cfa869bSMasatake YAMATO 
8401cfa869bSMasatake YAMATO }
8411cfa869bSMasatake YAMATO 
parseNewcommandFull(tokenInfo * const token,bool * tokenUnprocessed,texKind kind)842952983dbSJiří Techet static bool parseNewcommandFull (tokenInfo *const token, bool *tokenUnprocessed, texKind kind)
8433e2c7ce9SMasatake YAMATO {
8443e2c7ce9SMasatake YAMATO 	bool eof = false;
8453e2c7ce9SMasatake YAMATO 
8463e2c7ce9SMasatake YAMATO 	/* \newcommand{cmd}[args][opt]{def} */
847c6cbaf9cSJiří Techet 	/* \newcommand\cmd[args][opt]{def} */
848c6cbaf9cSJiří Techet 	/* \def\cmd{replacement} */
8493e2c7ce9SMasatake YAMATO 	struct TexParseStrategy strategy [] = {
8503e2c7ce9SMasatake YAMATO 		{
851c6cbaf9cSJiří Techet 			.type = '\\',
8523e2c7ce9SMasatake YAMATO 			.flags = 0,
853952983dbSJiří Techet 			.kindIndex = kind,
8543e2c7ce9SMasatake YAMATO 			.roleIndex = ROLE_DEFINITION_INDEX,
8553e2c7ce9SMasatake YAMATO 			.name = NULL,
856f67e271cSMasatake YAMATO 			.unique = false,
8573e2c7ce9SMasatake YAMATO 		},
8583e2c7ce9SMasatake YAMATO 		{
8593e2c7ce9SMasatake YAMATO 			.type = '[',
8603e2c7ce9SMasatake YAMATO 			.flags = TEX_NAME_FLAG_OPTIONAL,
8613e2c7ce9SMasatake YAMATO 			.kindIndex = KIND_GHOST_INDEX,
8623e2c7ce9SMasatake YAMATO 			.name = NULL,
8633e2c7ce9SMasatake YAMATO 		},
8643e2c7ce9SMasatake YAMATO 		{
8653e2c7ce9SMasatake YAMATO 			.type = '[',
8663e2c7ce9SMasatake YAMATO 			.flags = TEX_NAME_FLAG_OPTIONAL,
8673e2c7ce9SMasatake YAMATO 			.kindIndex = KIND_GHOST_INDEX,
8683e2c7ce9SMasatake YAMATO 			.name = NULL,
8693e2c7ce9SMasatake YAMATO 		},
8703e2c7ce9SMasatake YAMATO 		{
8713e2c7ce9SMasatake YAMATO 			.type = '{',
8723e2c7ce9SMasatake YAMATO 			.flags = 0,
8733e2c7ce9SMasatake YAMATO 			.kindIndex = KIND_GHOST_INDEX,
8743e2c7ce9SMasatake YAMATO 			.name = NULL,
8753e2c7ce9SMasatake YAMATO 		},
8763e2c7ce9SMasatake YAMATO 		{
8773e2c7ce9SMasatake YAMATO 			.type = 0
8783e2c7ce9SMasatake YAMATO 		}
8793e2c7ce9SMasatake YAMATO 	};
8803e2c7ce9SMasatake YAMATO 
8813e2c7ce9SMasatake YAMATO 	if (parseWithStrategy (token, strategy, tokenUnprocessed))
8823e2c7ce9SMasatake YAMATO 		eof = true;
8833e2c7ce9SMasatake YAMATO 
8843e2c7ce9SMasatake YAMATO 	return eof;
8853e2c7ce9SMasatake YAMATO }
8863e2c7ce9SMasatake YAMATO 
parseNewcommand(tokenInfo * const token,bool * tokenUnprocessed)887952983dbSJiří Techet static bool parseNewcommand (tokenInfo *const token, bool *tokenUnprocessed)
888952983dbSJiří Techet {
889952983dbSJiří Techet 	return parseNewcommandFull (token, tokenUnprocessed, TEXTAG_COMMAND);
890952983dbSJiří Techet }
891952983dbSJiří Techet 
parseNewEnvironment(tokenInfo * const token,bool * tokenUnprocessed)892bcf90eddSJiří Techet static bool parseNewEnvironment (tokenInfo *const token, bool *tokenUnprocessed)
893bcf90eddSJiří Techet {
894bcf90eddSJiří Techet 	bool eof = false;
895bcf90eddSJiří Techet 	/* \newenvironment{nam}[args]{begdef}{enddef} */
896bcf90eddSJiří Techet 	struct TexParseStrategy strategy [] = {
897bcf90eddSJiří Techet 		{
898bcf90eddSJiří Techet 			.type = '{',
899bcf90eddSJiří Techet 			.flags = 0,
900bcf90eddSJiří Techet 			.kindIndex = TEXTAG_ENVIRONMENT,
901bcf90eddSJiří Techet 			.roleIndex = ROLE_DEFINITION_INDEX,
902bcf90eddSJiří Techet 			.name = NULL,
903bcf90eddSJiří Techet 			.unique = false,
904bcf90eddSJiří Techet 		},
905bcf90eddSJiří Techet 		{
906bcf90eddSJiří Techet 			.type = '[',
907bcf90eddSJiří Techet 			.flags = TEX_NAME_FLAG_OPTIONAL,
908bcf90eddSJiří Techet 			.kindIndex = KIND_GHOST_INDEX,
909bcf90eddSJiří Techet 			.name = NULL,
910bcf90eddSJiří Techet 		},
911bcf90eddSJiří Techet 		{
912bcf90eddSJiří Techet 			.type = '{',
913bcf90eddSJiří Techet 			.flags = 0,
914bcf90eddSJiří Techet 			.kindIndex = KIND_GHOST_INDEX,
915bcf90eddSJiří Techet 			.name = NULL,
916bcf90eddSJiří Techet 		},
917bcf90eddSJiří Techet 		{
918bcf90eddSJiří Techet 			.type = '{',
919bcf90eddSJiří Techet 			.flags = 0,
920bcf90eddSJiří Techet 			.kindIndex = KIND_GHOST_INDEX,
921bcf90eddSJiří Techet 			.name = NULL,
922bcf90eddSJiří Techet 		},
923bcf90eddSJiří Techet 		{
924bcf90eddSJiří Techet 			.type = 0
925bcf90eddSJiří Techet 		}
926bcf90eddSJiří Techet 	};
927bcf90eddSJiří Techet 
928bcf90eddSJiří Techet 	if (parseWithStrategy (token, strategy, tokenUnprocessed))
929bcf90eddSJiří Techet 		eof = true;
930bcf90eddSJiří Techet 
931bcf90eddSJiří Techet 	return eof;
932bcf90eddSJiří Techet }
933bcf90eddSJiří Techet 
parseNewTheorem(tokenInfo * const token,bool * tokenUnprocessed)934aa63a3eaSJiří Techet static bool parseNewTheorem (tokenInfo *const token, bool *tokenUnprocessed)
935aa63a3eaSJiří Techet {
936aa63a3eaSJiří Techet 	bool eof = false;
937aa63a3eaSJiří Techet 	/*	\newtheorem{name}{title}
938aa63a3eaSJiří Techet 		\newtheorem{name}{title}[numbered_within]
939aa63a3eaSJiří Techet 		\newtheorem{name}[numbered_like]{title} */
940aa63a3eaSJiří Techet 	struct TexParseStrategy strategy [] = {
941aa63a3eaSJiří Techet 		{
942aa63a3eaSJiří Techet 			.type = '{',
943aa63a3eaSJiří Techet 			.flags = 0,
944aa63a3eaSJiří Techet 			.kindIndex = TEXTAG_THEOREM,
945aa63a3eaSJiří Techet 			.roleIndex = ROLE_DEFINITION_INDEX,
946aa63a3eaSJiří Techet 			.name = NULL,
947aa63a3eaSJiří Techet 			.unique = false,
948aa63a3eaSJiří Techet 		},
949aa63a3eaSJiří Techet 		{
950aa63a3eaSJiří Techet 			.type = '[',
951aa63a3eaSJiří Techet 			.flags = TEX_NAME_FLAG_OPTIONAL,
952aa63a3eaSJiří Techet 			.kindIndex = KIND_GHOST_INDEX,
953aa63a3eaSJiří Techet 			.name = NULL,
954aa63a3eaSJiří Techet 		},
955aa63a3eaSJiří Techet 		{
956aa63a3eaSJiří Techet 			.type = '{',
957aa63a3eaSJiří Techet 			.flags = 0,
958aa63a3eaSJiří Techet 			.kindIndex = KIND_GHOST_INDEX,
959aa63a3eaSJiří Techet 			.name = NULL,
960aa63a3eaSJiří Techet 		},
961aa63a3eaSJiří Techet 		{
962aa63a3eaSJiří Techet 			.type = '[',
963aa63a3eaSJiří Techet 			.flags = TEX_NAME_FLAG_OPTIONAL,
964aa63a3eaSJiří Techet 			.kindIndex = KIND_GHOST_INDEX,
965aa63a3eaSJiří Techet 			.name = NULL,
966aa63a3eaSJiří Techet 		},
967aa63a3eaSJiří Techet 		{
968aa63a3eaSJiří Techet 			.type = 0
969aa63a3eaSJiří Techet 		}
970aa63a3eaSJiří Techet 	};
971aa63a3eaSJiří Techet 
972aa63a3eaSJiří Techet 	if (parseWithStrategy (token, strategy, tokenUnprocessed))
973aa63a3eaSJiří Techet 		eof = true;
974aa63a3eaSJiří Techet 
975aa63a3eaSJiří Techet 	return eof;
976aa63a3eaSJiří Techet }
977aa63a3eaSJiří Techet 
parseNewcounter(tokenInfo * const token,bool * tokenUnprocessed)9783859e610SMasatake YAMATO static bool parseNewcounter (tokenInfo *const token, bool *tokenUnprocessed)
9793859e610SMasatake YAMATO {
9803859e610SMasatake YAMATO 	bool eof = false;
981af6af4ddSJiří Techet 	/* \newcounter {counter}[parentCounter] */
9823859e610SMasatake YAMATO 	struct TexParseStrategy strategy [] = {
9833859e610SMasatake YAMATO 		{
9843859e610SMasatake YAMATO 			.type = '{',
9853859e610SMasatake YAMATO 			.flags = 0,
9863859e610SMasatake YAMATO 			.kindIndex = TEXTAG_COUNTER,
9873859e610SMasatake YAMATO 			.roleIndex = ROLE_DEFINITION_INDEX,
9883859e610SMasatake YAMATO 			.name = NULL,
989f67e271cSMasatake YAMATO 			.unique = false,
9903859e610SMasatake YAMATO 		},
9913859e610SMasatake YAMATO 		{
9923859e610SMasatake YAMATO 			.type = '[',
993af6af4ddSJiří Techet 			.flags = TEX_NAME_FLAG_OPTIONAL,
9943859e610SMasatake YAMATO 			.kindIndex = KIND_GHOST_INDEX,
9953859e610SMasatake YAMATO 			.name = NULL,
9963859e610SMasatake YAMATO 		},
9973859e610SMasatake YAMATO 		{
9983859e610SMasatake YAMATO 			.type = 0
9993859e610SMasatake YAMATO 		}
10003859e610SMasatake YAMATO 	};
10013859e610SMasatake YAMATO 
10023859e610SMasatake YAMATO 	if (parseWithStrategy (token, strategy, tokenUnprocessed))
10033859e610SMasatake YAMATO 		eof = true;
10043859e610SMasatake YAMATO 
10053859e610SMasatake YAMATO 	return eof;
10063859e610SMasatake YAMATO }
1007bcf90eddSJiří Techet 
parseTexFile(tokenInfo * const token)10083ae02089SMasatake YAMATO static void parseTexFile (tokenInfo *const token)
10093ae02089SMasatake YAMATO {
1010969a87f4SMasatake YAMATO 	bool eof = false;
1011d0937875SMasatake YAMATO 	bool tokenUnprocessed = false;
1012969a87f4SMasatake YAMATO 
10133ae02089SMasatake YAMATO 	do
10143ae02089SMasatake YAMATO 	{
1015d0937875SMasatake YAMATO 		if (!tokenUnprocessed)
1016d0937875SMasatake YAMATO 		{
1017969a87f4SMasatake YAMATO 			if (!readToken (token))
1018969a87f4SMasatake YAMATO 				break;
1019d0937875SMasatake YAMATO 		}
1020d0937875SMasatake YAMATO 		tokenUnprocessed = false;
10213ae02089SMasatake YAMATO 
10223ae02089SMasatake YAMATO 		if (isType (token, TOKEN_KEYWORD))
10233ae02089SMasatake YAMATO 		{
10243ae02089SMasatake YAMATO 			switch (token->keyword)
10253ae02089SMasatake YAMATO 			{
10263ae02089SMasatake YAMATO 				case KEYWORD_part:
1027d0937875SMasatake YAMATO 					eof = parseTag (token, TEXTAG_PART, true, &tokenUnprocessed);
10283ae02089SMasatake YAMATO 					break;
10293ae02089SMasatake YAMATO 				case KEYWORD_chapter:
1030d0937875SMasatake YAMATO 					eof = parseTag (token, TEXTAG_CHAPTER, true, &tokenUnprocessed);
10313ae02089SMasatake YAMATO 					break;
10323ae02089SMasatake YAMATO 				case KEYWORD_section:
1033d0937875SMasatake YAMATO 					eof = parseTag (token, TEXTAG_SECTION, true, &tokenUnprocessed);
10343ae02089SMasatake YAMATO 					break;
10353ae02089SMasatake YAMATO 				case KEYWORD_subsection:
1036d0937875SMasatake YAMATO 					eof = parseTag (token, TEXTAG_SUBSECTION, true, &tokenUnprocessed);
10373ae02089SMasatake YAMATO 					break;
10383ae02089SMasatake YAMATO 				case KEYWORD_subsubsection:
1039d0937875SMasatake YAMATO 					eof = parseTag (token, TEXTAG_SUBSUBSECTION, true, &tokenUnprocessed);
10403ae02089SMasatake YAMATO 					break;
10413ae02089SMasatake YAMATO 				case KEYWORD_paragraph:
1042d0937875SMasatake YAMATO 					eof = parseTag (token, TEXTAG_PARAGRAPH, true, &tokenUnprocessed);
10433ae02089SMasatake YAMATO 					break;
10443ae02089SMasatake YAMATO 				case KEYWORD_subparagraph:
1045d0937875SMasatake YAMATO 					eof = parseTag (token, TEXTAG_SUBPARAGRAPH, true, &tokenUnprocessed);
10463ae02089SMasatake YAMATO 					break;
10473ae02089SMasatake YAMATO 				case KEYWORD_label:
1048d0937875SMasatake YAMATO 					eof = parseTag (token, TEXTAG_LABEL, false, &tokenUnprocessed);
10493ae02089SMasatake YAMATO 					break;
10503ae02089SMasatake YAMATO 				case KEYWORD_include:
1051f7be3a35SMasatake YAMATO 					eof = parseTagFull (token, TEXTAG_XINPUT, TEX_XINPUT_INCLUDED,
1052f7be3a35SMasatake YAMATO 										false, &tokenUnprocessed);
1053f7be3a35SMasatake YAMATO 					break;
1054f7be3a35SMasatake YAMATO 				case KEYWORD_input:
1055f7be3a35SMasatake YAMATO 					eof = parseTagFull (token, TEXTAG_XINPUT, TEX_XINPUT_INPUT,
1056f7be3a35SMasatake YAMATO 										false, &tokenUnprocessed);
10573ae02089SMasatake YAMATO 					break;
10581cfa869bSMasatake YAMATO 				case KEYWORD_begin:
10591cfa869bSMasatake YAMATO 					eof = parseEnv (token, true, &tokenUnprocessed);
10601cfa869bSMasatake YAMATO 					break;
10611cfa869bSMasatake YAMATO 				case KEYWORD_end:
10621cfa869bSMasatake YAMATO 					eof = parseEnv (token, false, &tokenUnprocessed);
10631cfa869bSMasatake YAMATO 					break;
1064b3ac7a43SMasatake YAMATO 				case KEYWORD_bibitem:
1065b3ac7a43SMasatake YAMATO 					eof = parseTag (token, TEXTAG_BIBITEM, false, &tokenUnprocessed);
1066b3ac7a43SMasatake YAMATO 					break;
106747b7253cSMasatake YAMATO 				case KEYWORD_bibliography:
106847b7253cSMasatake YAMATO 					eof = parseTagFull (token, TEXTAG_XINPUT, TEX_XINPUT_BIBLIOGRAPHY,
106947b7253cSMasatake YAMATO 										false, &tokenUnprocessed);
1070be0f06e7SAvinash Sonawane 					break;
10713e2c7ce9SMasatake YAMATO 				case KEYWORD_newcommand:
1072c359e13dSJiří Techet 				case KEYWORD_renewcommand:
1073c359e13dSJiří Techet 				case KEYWORD_providecommand:
107404d5c984SJiří Techet 				case KEYWORD_def:
1075c6cbaf9cSJiří Techet 					eof = parseNewcommand (token, &tokenUnprocessed);
107604d5c984SJiří Techet 					break;
1077952983dbSJiří Techet 				case KEYWORD_declaremathoperator:
1078952983dbSJiří Techet 					eof = parseNewcommandFull (token, &tokenUnprocessed, TEXTAG_OPERATOR);
1079952983dbSJiří Techet 					break;
1080bcf90eddSJiří Techet 				case KEYWORD_newenvironment:
1081bcf90eddSJiří Techet 				case KEYWORD_renewenvironment:
1082bcf90eddSJiří Techet 					eof = parseNewEnvironment (token, &tokenUnprocessed);
1083bcf90eddSJiří Techet 					break;
1084aa63a3eaSJiří Techet 				case KEYWORD_newtheorem:
1085aa63a3eaSJiří Techet 					eof = parseNewTheorem (token, &tokenUnprocessed);
1086aa63a3eaSJiří Techet 					break;
10873859e610SMasatake YAMATO 				case KEYWORD_newcounter:
10883859e610SMasatake YAMATO 					eof = parseNewcounter (token, &tokenUnprocessed);
10893859e610SMasatake YAMATO 					break;
10903ae02089SMasatake YAMATO 				default:
10913ae02089SMasatake YAMATO 					break;
10923ae02089SMasatake YAMATO 			}
10933ae02089SMasatake YAMATO 		}
10943b13813cSMasatake YAMATO 		else if (isType (token, TOKEN_IDENTIFIER))
10953b13813cSMasatake YAMATO 			eof = notifyReadingIdentifier (token, &tokenUnprocessed);
1096969a87f4SMasatake YAMATO 		if (eof)
1097969a87f4SMasatake YAMATO 			break;
1098ce990805SThomas Braun 	} while (true);
10993ae02089SMasatake YAMATO }
11003ae02089SMasatake YAMATO 
initialize(const langType language)11013ae02089SMasatake YAMATO static void initialize (const langType language)
11023ae02089SMasatake YAMATO {
1103158a3387SMasatake YAMATO 	Assert (ARRAY_SIZE (TexKinds) == TEXTAG_COUNT);
1104970f6116SJiří Techet 	Lang_tex = language;
11053ae02089SMasatake YAMATO 
11063ae02089SMasatake YAMATO 	lastPart    = vStringNew();
11073ae02089SMasatake YAMATO 	lastChapter = vStringNew();
11083ae02089SMasatake YAMATO 	lastSection = vStringNew();
11093ae02089SMasatake YAMATO 	lastSubS    = vStringNew();
11103ae02089SMasatake YAMATO 	lastSubSubS = vStringNew();
11113ae02089SMasatake YAMATO }
11123ae02089SMasatake YAMATO 
finalize(const langType language CTAGS_ATTR_UNUSED,bool initialized)11138ccb7ee9SJiří Techet static void finalize (const langType language CTAGS_ATTR_UNUSED,
1114ce990805SThomas Braun 		      bool initialized)
111519e4de57SMasatake YAMATO {
111619e4de57SMasatake YAMATO 	if (initialized)
11173ae02089SMasatake YAMATO 	{
11183ae02089SMasatake YAMATO 		vStringDelete(lastPart);
11193ae02089SMasatake YAMATO 		lastPart = NULL;
11203ae02089SMasatake YAMATO 		vStringDelete(lastChapter);
11213ae02089SMasatake YAMATO 		lastChapter = NULL;
11223ae02089SMasatake YAMATO 		vStringDelete(lastSection);
11233ae02089SMasatake YAMATO 		lastSection = NULL;
11243ae02089SMasatake YAMATO 		vStringDelete(lastSubS);
11253ae02089SMasatake YAMATO 		lastSubS = NULL;
11263ae02089SMasatake YAMATO 		vStringDelete(lastSubSubS);
11273ae02089SMasatake YAMATO 		lastSubSubS = NULL;
11283ae02089SMasatake YAMATO 	}
112919e4de57SMasatake YAMATO }
11303ae02089SMasatake YAMATO 
findTexTags(void)11313ae02089SMasatake YAMATO static void findTexTags (void)
11323ae02089SMasatake YAMATO {
11333ae02089SMasatake YAMATO 	tokenInfo *const token = newToken ();
11343ae02089SMasatake YAMATO 
1135*add23eb1SJiří Techet 	vStringClear(lastPart);
1136*add23eb1SJiří Techet 	vStringClear(lastChapter);
1137*add23eb1SJiří Techet 	vStringClear(lastSection);
1138*add23eb1SJiří Techet 	vStringClear(lastSubS);
1139*add23eb1SJiří Techet 	vStringClear(lastSubSubS);
1140*add23eb1SJiří Techet 
11413ae02089SMasatake YAMATO 	parseTexFile (token);
11423ae02089SMasatake YAMATO 
11433ae02089SMasatake YAMATO 	deleteToken (token);
11443ae02089SMasatake YAMATO }
11453ae02089SMasatake YAMATO 
notifyReadingIdentifier(tokenInfo * id_token,bool * tokenUnprocessed)11463b13813cSMasatake YAMATO static bool notifyReadingIdentifier (tokenInfo *id_token, bool *tokenUnprocessed)
11473b13813cSMasatake YAMATO {
11483b13813cSMasatake YAMATO 	subparser *sub;
11493b13813cSMasatake YAMATO 	bool eof = false;
11503b13813cSMasatake YAMATO 
11513b13813cSMasatake YAMATO 	foreachSubparser (sub, false)
11523b13813cSMasatake YAMATO 	{
11533b13813cSMasatake YAMATO 		texSubparser *texsub = (texSubparser *)sub;
11543b13813cSMasatake YAMATO 
11553b13813cSMasatake YAMATO 		if (texsub->readIdentifierNotify)
11563b13813cSMasatake YAMATO 		{
11573b13813cSMasatake YAMATO 			struct TexParseStrategy *strategy;
11583b13813cSMasatake YAMATO 
11593b13813cSMasatake YAMATO 			enterSubparser(sub);
11603b13813cSMasatake YAMATO 
11613b13813cSMasatake YAMATO 			strategy = texsub->readIdentifierNotify (texsub, id_token->string);
11623b13813cSMasatake YAMATO 
11633b13813cSMasatake YAMATO 			if (strategy)
1164f03d2abaSMasatake YAMATO 			{
11653b13813cSMasatake YAMATO 				eof = parseWithStrategy (id_token, strategy, tokenUnprocessed);
1166f03d2abaSMasatake YAMATO 				if (texsub->reportStrategicParsing)
1167f03d2abaSMasatake YAMATO 					texsub->reportStrategicParsing (texsub, strategy);
1168f03d2abaSMasatake YAMATO 			}
11693b13813cSMasatake YAMATO 
11703b13813cSMasatake YAMATO 			leaveSubparser();
11713b13813cSMasatake YAMATO 
11723b13813cSMasatake YAMATO 			if (strategy)
11733b13813cSMasatake YAMATO 				break;
11743b13813cSMasatake YAMATO 		}
11753b13813cSMasatake YAMATO 	}
11763b13813cSMasatake YAMATO 
11773b13813cSMasatake YAMATO 	return eof;
11783b13813cSMasatake YAMATO }
11793b13813cSMasatake YAMATO 
notifyReadingBeginEnvironment(tokenInfo * token,vString * envName,bool * tokenUnprocessed)11801cfa869bSMasatake YAMATO static bool notifyReadingBeginEnvironment (tokenInfo *token,
11811cfa869bSMasatake YAMATO 										   vString *envName,
11821cfa869bSMasatake YAMATO 										   bool *tokenUnprocessed)
11831cfa869bSMasatake YAMATO {
11841cfa869bSMasatake YAMATO 	subparser *sub;
11851cfa869bSMasatake YAMATO 	bool eof = false;
11861cfa869bSMasatake YAMATO 
11871cfa869bSMasatake YAMATO 	foreachSubparser (sub, false)
11881cfa869bSMasatake YAMATO 	{
11891cfa869bSMasatake YAMATO 		texSubparser *texsub = (texSubparser *)sub;
11901cfa869bSMasatake YAMATO 
11911cfa869bSMasatake YAMATO 		if (texsub->readEnviromentBeginNotify)
11921cfa869bSMasatake YAMATO 		{
11931cfa869bSMasatake YAMATO 			struct TexParseStrategy *strategy;
11941cfa869bSMasatake YAMATO 
11951cfa869bSMasatake YAMATO 			enterSubparser (sub);
11961cfa869bSMasatake YAMATO 			strategy = texsub->readEnviromentBeginNotify (texsub, envName);
11971cfa869bSMasatake YAMATO 			if (strategy)
1198f03d2abaSMasatake YAMATO 			{
11991cfa869bSMasatake YAMATO 				eof = parseWithStrategy (token, strategy, tokenUnprocessed);
1200f03d2abaSMasatake YAMATO 				if (texsub->reportStrategicParsing)
1201f03d2abaSMasatake YAMATO 					texsub->reportStrategicParsing (texsub, strategy);
1202f03d2abaSMasatake YAMATO 			}
12031cfa869bSMasatake YAMATO 			leaveSubparser ();
12041cfa869bSMasatake YAMATO 			if (strategy)
12051cfa869bSMasatake YAMATO 				break;
12061cfa869bSMasatake YAMATO 		}
12071cfa869bSMasatake YAMATO 	}
12081cfa869bSMasatake YAMATO 
12091cfa869bSMasatake YAMATO 	return eof;
12101cfa869bSMasatake YAMATO }
12111cfa869bSMasatake YAMATO 
notifyReadingEndEnvironment(vString * envName)12121cfa869bSMasatake YAMATO static bool notifyReadingEndEnvironment (vString  *envName)
12131cfa869bSMasatake YAMATO {
12141cfa869bSMasatake YAMATO 	subparser *sub;
12151cfa869bSMasatake YAMATO 
12161cfa869bSMasatake YAMATO 	foreachSubparser (sub, false)
12171cfa869bSMasatake YAMATO 	{
12181cfa869bSMasatake YAMATO 		texSubparser *texsub = (texSubparser *)sub;
12191cfa869bSMasatake YAMATO 
12201cfa869bSMasatake YAMATO 		if (texsub->readEnviromentEndNotify)
12211cfa869bSMasatake YAMATO 		{
12221cfa869bSMasatake YAMATO 			bool consuming;
12231cfa869bSMasatake YAMATO 
12241cfa869bSMasatake YAMATO 			enterSubparser (sub);
12251cfa869bSMasatake YAMATO 			consuming = texsub->readEnviromentEndNotify (texsub, envName);
12261cfa869bSMasatake YAMATO 			leaveSubparser ();
12271cfa869bSMasatake YAMATO 			if (consuming)
12281cfa869bSMasatake YAMATO 				break;
12291cfa869bSMasatake YAMATO 		}
12301cfa869bSMasatake YAMATO 	}
12311cfa869bSMasatake YAMATO 
12321cfa869bSMasatake YAMATO 	return false;
12331cfa869bSMasatake YAMATO }
12341cfa869bSMasatake YAMATO 
1235137eb990SK.Takata /* Create parser definition structure */
TexParser(void)12363ae02089SMasatake YAMATO extern parserDefinition* TexParser (void)
12373ae02089SMasatake YAMATO {
12383ae02089SMasatake YAMATO 	static const char *const extensions [] = { "tex", NULL };
12393ae02089SMasatake YAMATO 	parserDefinition *const def = parserNew ("Tex");
12403ae02089SMasatake YAMATO 	def->extensions = extensions;
12413ae02089SMasatake YAMATO 	/*
12423ae02089SMasatake YAMATO 	 * New definitions for parsing instead of regex
12433ae02089SMasatake YAMATO 	 */
124409ae690fSMasatake YAMATO 	def->kindTable	= TexKinds;
12453db72c21SMasatake YAMATO 	def->kindCount	= ARRAY_SIZE (TexKinds);
12463ae02089SMasatake YAMATO 	def->parser		= findTexTags;
12473ae02089SMasatake YAMATO 	def->initialize = initialize;
12483ae02089SMasatake YAMATO 	def->finalize   = finalize;
1249c379c5d2SMasatake YAMATO 	def->keywordTable =  TexKeywordTable;
12503db72c21SMasatake YAMATO 	def->keywordCount = ARRAY_SIZE (TexKeywordTable);
1251f67e271cSMasatake YAMATO 	def->useCork = CORK_QUEUE  | CORK_SYMTAB;
12523ae02089SMasatake YAMATO 	return def;
12533ae02089SMasatake YAMATO }
1254