xref: /Universal-ctags/parsers/cobol.c (revision bcc2ead480f5ab6b9974f8441d08fd601d36d4bf)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO *   Copyright (c) 2000-2003, Darren Hiebert
33ae02089SMasatake YAMATO *
43ae02089SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
63ae02089SMasatake YAMATO *
73ae02089SMasatake YAMATO *   This module contains functions for generating tags for COBOL language
83ae02089SMasatake YAMATO *   files.
93ae02089SMasatake YAMATO */
103ae02089SMasatake YAMATO 
11*bcc2ead4SColomban Wendling /* Some references:
12*bcc2ead4SColomban Wendling  * - https://www.cs.vu.nl/grammarware/browsable/cobol/
13*bcc2ead4SColomban Wendling  * - https://www.cs.vu.nl/grammarware/browsable/vs-cobol-ii/
14*bcc2ead4SColomban Wendling  * - https://open-cobol.sourceforge.io/guides/grammar.pdf
15*bcc2ead4SColomban Wendling  * - http://mapage.noos.fr/~bpinon/a_cobol_parser.htm
16*bcc2ead4SColomban Wendling  * - https://en.wikipedia.org/wiki/COBOL
17*bcc2ead4SColomban Wendling  */
18*bcc2ead4SColomban Wendling 
193ae02089SMasatake YAMATO /*
203ae02089SMasatake YAMATO *   INCLUDE FILES
213ae02089SMasatake YAMATO */
223ae02089SMasatake YAMATO #include "general.h"	/* must always come first */
2306def60bSColomban Wendling #include "debug.h"
24e57cf27dSColomban Wendling #include "entry.h"
2595ecd0e1SMasatake YAMATO #include "keyword.h"
26e57cf27dSColomban Wendling #include "nestlevel.h"
273ae02089SMasatake YAMATO #include "parse.h"
28e57cf27dSColomban Wendling #include "read.h"
293db72c21SMasatake YAMATO #include "routines.h"
303ae02089SMasatake YAMATO 
3195ecd0e1SMasatake YAMATO typedef enum {
32e57cf27dSColomban Wendling 	K_FILE,
33e57cf27dSColomban Wendling 	K_GROUP,
34e57cf27dSColomban Wendling 	K_PROGRAM,
35e57cf27dSColomban Wendling 	K_SECTION,
36e57cf27dSColomban Wendling 	K_DIVISION,
3795ecd0e1SMasatake YAMATO 	K_PARAGRAPH,
38176ada67SMasatake YAMATO 	K_DATA,
39e167948bSMasatake YAMATO 	K_SOURCEFILE,
4095ecd0e1SMasatake YAMATO } cobolKind;
4195ecd0e1SMasatake YAMATO 
42e167948bSMasatake YAMATO typedef enum {
43db025d38SMasatake YAMATO 	COBOL_SOURCEFILE_COPIED,
44e167948bSMasatake YAMATO } cobolSourcefileRole;
45e167948bSMasatake YAMATO 
4613457258SMasatake YAMATO static roleDefinition CobolSourcefileRoles [] = {
47db025d38SMasatake YAMATO 	{ true, "copied", "copied in source file" },
48e167948bSMasatake YAMATO };
49e167948bSMasatake YAMATO 
50e112e8abSMasatake YAMATO static kindDefinition CobolKinds[] = {
51e57cf27dSColomban Wendling 	{ true, 'f', "fd", "file descriptions (FD, SD, RD)" },
52e57cf27dSColomban Wendling 	{ true, 'g', "group", "group items" },
53e57cf27dSColomban Wendling 	{ true, 'P', "program", "program ids" },
54e57cf27dSColomban Wendling 	{ true, 's', "section", "sections" },
55e57cf27dSColomban Wendling 	{ true, 'D', "division", "divisions" },
5695ecd0e1SMasatake YAMATO 	{ true, 'p', "paragraph", "paragraphs" },
57176ada67SMasatake YAMATO 	{ true, 'd', "data", "data items"      },
58e167948bSMasatake YAMATO 	{ true, 'S', "sourcefile", "source code file",
59e167948bSMasatake YAMATO 	  .referenceOnly = true, ATTACH_ROLES(CobolSourcefileRoles)},
6095ecd0e1SMasatake YAMATO };
6195ecd0e1SMasatake YAMATO 
62e57cf27dSColomban Wendling static langType Lang_cobol;
63dc0f490fSMasatake YAMATO 
64e57cf27dSColomban Wendling enum {
65e57cf27dSColomban Wendling 	KEYWORD_FD,
66e57cf27dSColomban Wendling 	KEYWORD_SD,
67e57cf27dSColomban Wendling 	KEYWORD_RD,
68e57cf27dSColomban Wendling 	KEYWORD_SECTION,
69e57cf27dSColomban Wendling 	KEYWORD_DIVISION,
70e57cf27dSColomban Wendling 	KEYWORD_CONTINUE,
71e57cf27dSColomban Wendling 	KEYWORD_END_EXEC,
72e57cf27dSColomban Wendling 	KEYWORD_FILLER,
73e57cf27dSColomban Wendling 	KEYWORD_BLANK,
74e57cf27dSColomban Wendling 	KEYWORD_OCCURS,
75e57cf27dSColomban Wendling 	KEYWORD_IS,
76e57cf27dSColomban Wendling 	KEYWORD_JUST,
77e57cf27dSColomban Wendling 	KEYWORD_PIC,
78e57cf27dSColomban Wendling 	KEYWORD_REDEFINES,
79e57cf27dSColomban Wendling 	KEYWORD_RENAMES,
80e57cf27dSColomban Wendling 	KEYWORD_SIGN,
81e57cf27dSColomban Wendling 	KEYWORD_SYNC,
82e57cf27dSColomban Wendling 	KEYWORD_USAGE,
83e57cf27dSColomban Wendling 	KEYWORD_VALUE,
84e57cf27dSColomban Wendling 	KEYWORD_PROGRAM_ID,
85e57cf27dSColomban Wendling 	KEYWORD_EXIT,
86e57cf27dSColomban Wendling 	KEYWORD_COPY,
87e57cf27dSColomban Wendling };
8895ecd0e1SMasatake YAMATO 
8995ecd0e1SMasatake YAMATO static const keywordTable cobolKeywordTable[] = {
90e57cf27dSColomban Wendling #define DEFINE_KEYWORD(n) { #n, KEYWORD_##n }
91e57cf27dSColomban Wendling 	DEFINE_KEYWORD (FD),
92e57cf27dSColomban Wendling 	DEFINE_KEYWORD (SD),
93e57cf27dSColomban Wendling 	DEFINE_KEYWORD (RD),
94e57cf27dSColomban Wendling 	DEFINE_KEYWORD (SECTION),
95e57cf27dSColomban Wendling 	DEFINE_KEYWORD (DIVISION),
96e57cf27dSColomban Wendling 	DEFINE_KEYWORD (CONTINUE),
97e57cf27dSColomban Wendling 	{ "END-EXEC", KEYWORD_END_EXEC },
98e57cf27dSColomban Wendling 	DEFINE_KEYWORD (EXIT),
99e57cf27dSColomban Wendling 	DEFINE_KEYWORD (FILLER),
100e57cf27dSColomban Wendling 	DEFINE_KEYWORD (BLANK),
101e57cf27dSColomban Wendling 	DEFINE_KEYWORD (OCCURS),
102e57cf27dSColomban Wendling 	DEFINE_KEYWORD (IS),
103e57cf27dSColomban Wendling 	DEFINE_KEYWORD (JUST),
104e57cf27dSColomban Wendling 	DEFINE_KEYWORD (PIC),
1050b3cdb6aSColomban Wendling 	{ "PICTURE", KEYWORD_PIC },
106e57cf27dSColomban Wendling 	DEFINE_KEYWORD (REDEFINES),
107e57cf27dSColomban Wendling 	DEFINE_KEYWORD (RENAMES),
108e57cf27dSColomban Wendling 	DEFINE_KEYWORD (SIGN),
109e57cf27dSColomban Wendling 	DEFINE_KEYWORD (SYNC),
110e57cf27dSColomban Wendling 	DEFINE_KEYWORD (USAGE),
111e57cf27dSColomban Wendling 	DEFINE_KEYWORD (VALUE),
1120b3cdb6aSColomban Wendling 	{ "VALUES", KEYWORD_VALUE },
113e57cf27dSColomban Wendling 	{ "PROGRAM-ID", KEYWORD_PROGRAM_ID },
114e57cf27dSColomban Wendling 	DEFINE_KEYWORD (COPY),
11595ecd0e1SMasatake YAMATO };
11695ecd0e1SMasatake YAMATO 
1173303a28cSColomban Wendling #define INDICATOR_COLUMN 7
1183303a28cSColomban Wendling #define PROGRAM_NAME_AREA_COLUMN 73
1193ae02089SMasatake YAMATO 
120e57cf27dSColomban Wendling #define isIdentifierChar(c) (isalnum(c) || (c) == '-')
1218ccb114eSColomban Wendling #define isQuote(c) ((c) == '\'' || (c) == '"')
122176ada67SMasatake YAMATO 
12306def60bSColomban Wendling typedef enum {
12406def60bSColomban Wendling 	/* Fixed: program starts at column 8, ends at column 72 */
12506def60bSColomban Wendling 	FORMAT_FIXED	= 0x1,
12606def60bSColomban Wendling 	/* Free: program starts at column 1, no specific end */
12706def60bSColomban Wendling 	FORMAT_FREE		= 0x2,
12806def60bSColomban Wendling 	/* Variable: program starts at column 8, no specific end */
12906def60bSColomban Wendling 	FORMAT_VARIABLE	= FORMAT_FIXED | FORMAT_FREE
13006def60bSColomban Wendling } CobolFormat;
13106def60bSColomban Wendling 
13206def60bSColomban Wendling static struct {
1333303a28cSColomban Wendling 	vString *line;
1343303a28cSColomban Wendling 	unsigned long int lineNumber;
1353303a28cSColomban Wendling 	MIOPos filePosition;
1363303a28cSColomban Wendling 	const char *nextLine;
13706def60bSColomban Wendling 	CobolFormat format;
13806def60bSColomban Wendling } CblInputState;
13906def60bSColomban Wendling 
cblppInit(const CobolFormat format)14006def60bSColomban Wendling static void cblppInit (const CobolFormat format)
14106def60bSColomban Wendling {
1423303a28cSColomban Wendling 	CblInputState.line = vStringNew ();
1433303a28cSColomban Wendling 	CblInputState.lineNumber = 0;
1443303a28cSColomban Wendling 	CblInputState.nextLine = NULL;
14506def60bSColomban Wendling 	CblInputState.format = format;
14606def60bSColomban Wendling }
14706def60bSColomban Wendling 
cblppDeinit(void)1483303a28cSColomban Wendling static void cblppDeinit (void)
14906def60bSColomban Wendling {
1503303a28cSColomban Wendling 	vStringDelete (CblInputState.line);
1513303a28cSColomban Wendling }
15206def60bSColomban Wendling 
cblppGetColumn(const char * line,const unsigned int column)1533303a28cSColomban Wendling static const char *cblppGetColumn (const char *line,
1543303a28cSColomban Wendling 								   const unsigned int column)
15506def60bSColomban Wendling {
1563303a28cSColomban Wendling 	unsigned int col = 0;
1573303a28cSColomban Wendling 
1583303a28cSColomban Wendling 	for (; *line; line++)
1593303a28cSColomban Wendling 	{
1603303a28cSColomban Wendling 		col += (*line == '\t') ? 8 : 1;
1613303a28cSColomban Wendling 		if (col >= column)
1623303a28cSColomban Wendling 			return line;
1633303a28cSColomban Wendling 	}
1643303a28cSColomban Wendling 
1653303a28cSColomban Wendling 	return NULL;
1663303a28cSColomban Wendling }
1673303a28cSColomban Wendling 
cblppAppendLine(vString * buffer,const char * line)1683303a28cSColomban Wendling static void cblppAppendLine (vString *buffer,
1693303a28cSColomban Wendling 							 const char *line)
1703303a28cSColomban Wendling {
1713303a28cSColomban Wendling 	if (CblInputState.format & FORMAT_FIXED)
1723303a28cSColomban Wendling 	{
1733303a28cSColomban Wendling 		const char *indicator = cblppGetColumn (line, INDICATOR_COLUMN);
1743303a28cSColomban Wendling 
1753303a28cSColomban Wendling 		if (indicator && *indicator && *indicator != '*' && *indicator != '/')
1763303a28cSColomban Wendling 		{
1773303a28cSColomban Wendling 			const char *lineStart = indicator + 1;
1783303a28cSColomban Wendling 			const char *lineEnd = cblppGetColumn (line, PROGRAM_NAME_AREA_COLUMN);
1793303a28cSColomban Wendling 
1803303a28cSColomban Wendling 			if (*indicator == '-')
1813303a28cSColomban Wendling 			{
1823303a28cSColomban Wendling 				vStringStripTrailing (buffer);
1833303a28cSColomban Wendling 				while (isspace (*lineStart))
1843303a28cSColomban Wendling 					lineStart++;
1853303a28cSColomban Wendling 			}
1863303a28cSColomban Wendling 
1873303a28cSColomban Wendling 			if (CblInputState.format == FORMAT_FIXED)
1883303a28cSColomban Wendling 				vStringNCatS (buffer, lineStart, lineEnd - lineStart);
18906def60bSColomban Wendling 			else
1903303a28cSColomban Wendling 				vStringCatS (buffer, lineStart);
19106def60bSColomban Wendling 		}
19206def60bSColomban Wendling 	}
1933303a28cSColomban Wendling 	else if (line[0] != '*' && line[0] != '/')
1943303a28cSColomban Wendling 		vStringCatS (buffer, line);
195e57cf27dSColomban Wendling }
196e57cf27dSColomban Wendling 
1973303a28cSColomban Wendling /* TODO: skip *> comments */
cblppGetLine(void)1983303a28cSColomban Wendling static const char *cblppGetLine (void)
199e57cf27dSColomban Wendling {
2003303a28cSColomban Wendling 	const char *line;
2013303a28cSColomban Wendling 
2023303a28cSColomban Wendling 	if (CblInputState.nextLine)
203e57cf27dSColomban Wendling 	{
2043303a28cSColomban Wendling 		line = CblInputState.nextLine;
2053303a28cSColomban Wendling 		CblInputState.nextLine = NULL;
206e57cf27dSColomban Wendling 	}
207e57cf27dSColomban Wendling 	else
2083303a28cSColomban Wendling 		line = (const char *) readLineFromInputFile ();
2093303a28cSColomban Wendling 
2103303a28cSColomban Wendling 	CblInputState.lineNumber = getInputLineNumber ();
2113303a28cSColomban Wendling 	CblInputState.filePosition = getInputFilePosition ();
2123303a28cSColomban Wendling 
2133303a28cSColomban Wendling 	if (!line)
2143303a28cSColomban Wendling 		return NULL;
2153303a28cSColomban Wendling 
2163303a28cSColomban Wendling 	vStringClear (CblInputState.line);
2173303a28cSColomban Wendling 	cblppAppendLine (CblInputState.line, line);
2183303a28cSColomban Wendling 
2193303a28cSColomban Wendling 	/* check for continuation lines */
220ed9c07abSColomban Wendling 	if (CblInputState.format & FORMAT_FIXED)
221ed9c07abSColomban Wendling 	{
222ed9c07abSColomban Wendling 		while (true)
223e57cf27dSColomban Wendling 		{
2243303a28cSColomban Wendling 			const char *indicator;
2253303a28cSColomban Wendling 			line = (const char *) readLineFromInputFile ();
2263303a28cSColomban Wendling 			if (! line)
2273303a28cSColomban Wendling 				break;
2283303a28cSColomban Wendling 			indicator = cblppGetColumn (line, INDICATOR_COLUMN);
2293303a28cSColomban Wendling 			if (indicator && *indicator == '-')
2303303a28cSColomban Wendling 				cblppAppendLine (CblInputState.line, line);
2313303a28cSColomban Wendling 			else
232e57cf27dSColomban Wendling 				break;
233e57cf27dSColomban Wendling 		}
234e57cf27dSColomban Wendling 
2353303a28cSColomban Wendling 		CblInputState.nextLine = line;
236ed9c07abSColomban Wendling 	}
2373303a28cSColomban Wendling 
2383303a28cSColomban Wendling 	return vStringValue (CblInputState.line);
239e57cf27dSColomban Wendling }
240e57cf27dSColomban Wendling 
initCOBOLRefTagEntry(tagEntryInfo * e,const char * name,const cobolKind kind,const int role)2413303a28cSColomban Wendling static void initCOBOLRefTagEntry (tagEntryInfo *e, const char *name,
2423303a28cSColomban Wendling 								  const cobolKind kind, const int role)
243e57cf27dSColomban Wendling {
2443303a28cSColomban Wendling 	initRefTagEntry (e, name, kind, role);
2453303a28cSColomban Wendling 	e->lineNumber = CblInputState.lineNumber;
2463303a28cSColomban Wendling 	e->filePosition = CblInputState.filePosition;
247176ada67SMasatake YAMATO }
248176ada67SMasatake YAMATO 
initCOBOLTagEntry(tagEntryInfo * e,const char * name,const cobolKind kind)2493303a28cSColomban Wendling static void initCOBOLTagEntry (tagEntryInfo *e, const char *name, const cobolKind kind)
2503303a28cSColomban Wendling {
2513303a28cSColomban Wendling 	initCOBOLRefTagEntry (e, name, kind, ROLE_DEFINITION_INDEX);
2523303a28cSColomban Wendling }
2533303a28cSColomban Wendling 
makeCOBOLRefTag(const char * name,const cobolKind kind,const int role)2543303a28cSColomban Wendling static int makeCOBOLRefTag (const char *name, const cobolKind kind, const int role)
255176ada67SMasatake YAMATO {
256e57cf27dSColomban Wendling 	if (CobolKinds[kind].enabled)
2573303a28cSColomban Wendling 	{
2583303a28cSColomban Wendling 		tagEntryInfo e;
2593303a28cSColomban Wendling 
2603303a28cSColomban Wendling 		initCOBOLRefTagEntry (&e, name, kind, role);
2613303a28cSColomban Wendling 
2623303a28cSColomban Wendling 		return makeTagEntry (&e);
2633303a28cSColomban Wendling 	}
2643303a28cSColomban Wendling 
265e57cf27dSColomban Wendling 	return CORK_NIL;
266176ada67SMasatake YAMATO }
267176ada67SMasatake YAMATO 
makeCOBOLTag(const char * name,const cobolKind kind)2683303a28cSColomban Wendling static int makeCOBOLTag (const char *name, const cobolKind kind)
26995ecd0e1SMasatake YAMATO {
2703303a28cSColomban Wendling 	return makeCOBOLRefTag (name, kind, ROLE_DEFINITION_INDEX);
27195ecd0e1SMasatake YAMATO }
27295ecd0e1SMasatake YAMATO 
2733303a28cSColomban Wendling #define CBL_NL(nl) (*((unsigned int *) (nestingLevelGetUserData (nl))))
274ec945a05SColomban Wendling 
popNestingLevelsToLevelNumber(NestingLevels * levels,const unsigned int levelNumber)2753303a28cSColomban Wendling static NestingLevel *popNestingLevelsToLevelNumber (NestingLevels *levels, const unsigned int levelNumber)
276ec945a05SColomban Wendling {
277ec945a05SColomban Wendling 	NestingLevel *nl;
278ec945a05SColomban Wendling 
279ec945a05SColomban Wendling 	while (true)
280ec945a05SColomban Wendling 	{
281ec945a05SColomban Wendling 		nl = nestingLevelsGetCurrent (levels);
282ec945a05SColomban Wendling 		if (! nl || CBL_NL (nl) < levelNumber)
283ec945a05SColomban Wendling 			break;
284ec945a05SColomban Wendling 		nestingLevelsPop (levels);
285ec945a05SColomban Wendling 	}
286ec945a05SColomban Wendling 
287ec945a05SColomban Wendling 	return nl;
288ec945a05SColomban Wendling }
289ec945a05SColomban Wendling 
isNumeric(const char * nptr,unsigned long int * num)2903303a28cSColomban Wendling static bool isNumeric (const char *nptr, unsigned long int *num)
2913303a28cSColomban Wendling {
2923303a28cSColomban Wendling 	char *endptr;
2933303a28cSColomban Wendling 	unsigned long int v;
2943303a28cSColomban Wendling 
2953303a28cSColomban Wendling 	v = strtoul (nptr, &endptr, 10);
2963303a28cSColomban Wendling 	if (nptr != endptr && *endptr == 0)
2973303a28cSColomban Wendling 	{
2983303a28cSColomban Wendling 		if (num)
2993303a28cSColomban Wendling 			*num = v;
3003303a28cSColomban Wendling 		return true;
3013303a28cSColomban Wendling 	}
3023303a28cSColomban Wendling 	return false;
3033303a28cSColomban Wendling }
3043303a28cSColomban Wendling 
findCOBOLTags(const CobolFormat format)305174851b3SColomban Wendling static void findCOBOLTags (const CobolFormat format)
306e167948bSMasatake YAMATO {
307ec945a05SColomban Wendling 	NestingLevels *levels;
3083303a28cSColomban Wendling 	const char *line;
309e167948bSMasatake YAMATO 
310174851b3SColomban Wendling 	cblppInit (format);
31106def60bSColomban Wendling 
3123303a28cSColomban Wendling 	levels = nestingLevelsNew (sizeof (unsigned int));
3133303a28cSColomban Wendling 
3143303a28cSColomban Wendling 	while ((line = cblppGetLine ()) != NULL)
315e57cf27dSColomban Wendling 	{
3163303a28cSColomban Wendling 		char word[64];
3173303a28cSColomban Wendling 		int keyword;
3183303a28cSColomban Wendling 		unsigned long int levelNumber;
319e57cf27dSColomban Wendling 
3208ccb114eSColomban Wendling #define READ_WHILE(word, cond) \
321e57cf27dSColomban Wendling 	do { \
3223303a28cSColomban Wendling 		unsigned int i; \
3238ccb114eSColomban Wendling 		for (i = 0; i < (ARRAY_SIZE (word) - 1) && *line && (cond); line++) \
3243303a28cSColomban Wendling 			word[i++] = *line; \
3253303a28cSColomban Wendling 		word[i] = 0; \
3268ccb114eSColomban Wendling 	} while (0)
3278ccb114eSColomban Wendling #define READ_LITERAL(word) \
3288ccb114eSColomban Wendling 	do { \
3298ccb114eSColomban Wendling 		const char READ_LITERAL__q = isQuote (*line) ? *line++ : 0; \
3308ccb114eSColomban Wendling 		READ_WHILE (word, (READ_LITERAL__q && READ_LITERAL__q != *line) || \
3318ccb114eSColomban Wendling 		                   isIdentifierChar (*line)); \
3328ccb114eSColomban Wendling 		if (READ_LITERAL__q && READ_LITERAL__q == *line) \
3338ccb114eSColomban Wendling 			line++; \
3348ccb114eSColomban Wendling 		keyword = lookupCaseKeyword (word, Lang_cobol); \
3358ccb114eSColomban Wendling 	} while (0)
3368ccb114eSColomban Wendling #define READ_WORD(word, keyword) \
3378ccb114eSColomban Wendling 	do { \
3388ccb114eSColomban Wendling 		READ_WHILE (word, isIdentifierChar (*line)); \
3393303a28cSColomban Wendling 		keyword = lookupCaseKeyword (word, Lang_cobol); \
340e57cf27dSColomban Wendling 	} while (0)
3413303a28cSColomban Wendling #define READ_KEYWORD(keyword) \
3423303a28cSColomban Wendling 	do { \
3433303a28cSColomban Wendling 		char READ_KEYWORD__word[64]; \
3443303a28cSColomban Wendling 		READ_WORD (READ_KEYWORD__word, keyword); \
3453303a28cSColomban Wendling 	} while (0)
3463303a28cSColomban Wendling #define SKIP_SPACES() do { while (isspace (*line)) line++; } while (0)
347e57cf27dSColomban Wendling 
3483303a28cSColomban Wendling 		SKIP_SPACES ();
3493303a28cSColomban Wendling 		READ_WORD (word, keyword);
3503303a28cSColomban Wendling 		SKIP_SPACES ();
351e57cf27dSColomban Wendling 
3523303a28cSColomban Wendling 		switch (keyword)
353e57cf27dSColomban Wendling 		{
3543303a28cSColomban Wendling 		case KEYWORD_FD:
3553303a28cSColomban Wendling 		case KEYWORD_SD:
3563303a28cSColomban Wendling 		case KEYWORD_RD:
3573303a28cSColomban Wendling 			READ_WORD (word, keyword);
3583303a28cSColomban Wendling 			SKIP_SPACES ();
3593303a28cSColomban Wendling 			if (*word && *line == '.')
3603303a28cSColomban Wendling 				makeCOBOLTag (word, K_FILE);
3613303a28cSColomban Wendling 			break;
362e57cf27dSColomban Wendling 
3633303a28cSColomban Wendling 		case KEYWORD_PROGRAM_ID:
3643303a28cSColomban Wendling 			if (*line == '.')
365e57cf27dSColomban Wendling 			{
3663303a28cSColomban Wendling 				line++;
3673303a28cSColomban Wendling 				SKIP_SPACES ();
368e57cf27dSColomban Wendling 			}
3698ccb114eSColomban Wendling 			READ_LITERAL (word);
3703303a28cSColomban Wendling 			if (*word)
3713303a28cSColomban Wendling 				makeCOBOLTag (word, K_PROGRAM);
3723303a28cSColomban Wendling 			break;
373ec945a05SColomban Wendling 
3743303a28cSColomban Wendling 		case KEYWORD_COPY:
3753303a28cSColomban Wendling 			READ_WORD (word, keyword); // FIXME: also allow LITERAL
3763303a28cSColomban Wendling 			if (*word)
3773303a28cSColomban Wendling 				makeCOBOLRefTag (word, K_SOURCEFILE, COBOL_SOURCEFILE_COPIED);
3783303a28cSColomban Wendling 			break;
3793303a28cSColomban Wendling 
3803303a28cSColomban Wendling 		case KEYWORD_CONTINUE:
3813303a28cSColomban Wendling 		case KEYWORD_END_EXEC:
3823303a28cSColomban Wendling 		case KEYWORD_EXIT:
3833303a28cSColomban Wendling 		case KEYWORD_FILLER:
3843303a28cSColomban Wendling 			/* nothing, just ignore those in following cases */;
3853303a28cSColomban Wendling 			break;
3863303a28cSColomban Wendling 
3873303a28cSColomban Wendling 		default:
3883303a28cSColomban Wendling 			if (isNumeric (word, &levelNumber))
3893303a28cSColomban Wendling 			{
3903303a28cSColomban Wendling 				READ_WORD (word, keyword);
3913303a28cSColomban Wendling 				SKIP_SPACES ();
3923303a28cSColomban Wendling 
3933303a28cSColomban Wendling 				if (*word && keyword != KEYWORD_FILLER)
394e57cf27dSColomban Wendling 				{
395ec945a05SColomban Wendling 					int kind = KIND_GHOST_INDEX;
396ec945a05SColomban Wendling 
3973303a28cSColomban Wendling 					if (*line == '.')
398ec945a05SColomban Wendling 						kind = K_GROUP;
3993303a28cSColomban Wendling 					else
400e57cf27dSColomban Wendling 					{
4013303a28cSColomban Wendling 						int keyword2;
4023303a28cSColomban Wendling 
4033303a28cSColomban Wendling 						READ_KEYWORD (keyword2);
4043303a28cSColomban Wendling 						switch (keyword2)
405e57cf27dSColomban Wendling 						{
406e57cf27dSColomban Wendling 						case KEYWORD_BLANK:
407e57cf27dSColomban Wendling 						case KEYWORD_OCCURS:
408e57cf27dSColomban Wendling 						case KEYWORD_IS:
409e57cf27dSColomban Wendling 						case KEYWORD_JUST:
410e57cf27dSColomban Wendling 						case KEYWORD_PIC:
411e57cf27dSColomban Wendling 						case KEYWORD_REDEFINES:
412e57cf27dSColomban Wendling 						case KEYWORD_RENAMES:
413e57cf27dSColomban Wendling 						case KEYWORD_SIGN:
414e57cf27dSColomban Wendling 						case KEYWORD_SYNC:
415e57cf27dSColomban Wendling 						case KEYWORD_USAGE:
416e57cf27dSColomban Wendling 						case KEYWORD_VALUE:
417ec945a05SColomban Wendling 							kind = K_DATA;
418e57cf27dSColomban Wendling 						}
419e57cf27dSColomban Wendling 					}
420ec945a05SColomban Wendling 
421ec945a05SColomban Wendling 					if (kind != KIND_GHOST_INDEX)
422ec945a05SColomban Wendling 					{
423ec945a05SColomban Wendling 						NestingLevel *nl;
424ec945a05SColomban Wendling 						tagEntryInfo entry;
425ec945a05SColomban Wendling 						int r;
426407b0a02SColomban Wendling 						unsigned int nestingLevelNumber;
427ec945a05SColomban Wendling 
428407b0a02SColomban Wendling 						/* for nesting purposes, level 77 is identical to 1,
429407b0a02SColomban Wendling 						 * and 66 to 2 */
430407b0a02SColomban Wendling 						switch (levelNumber)
431407b0a02SColomban Wendling 						{
432407b0a02SColomban Wendling 						default: nestingLevelNumber = levelNumber; break;
433407b0a02SColomban Wendling 						case 77: nestingLevelNumber = 1; break;
434407b0a02SColomban Wendling 						case 66: nestingLevelNumber = 2; break;
435407b0a02SColomban Wendling 						}
436407b0a02SColomban Wendling 
437407b0a02SColomban Wendling 						nl = popNestingLevelsToLevelNumber (levels, nestingLevelNumber);
4383303a28cSColomban Wendling 						initCOBOLTagEntry (&entry, word, kind);
439407b0a02SColomban Wendling 						if (nl && CBL_NL (nl) < nestingLevelNumber)
440ec945a05SColomban Wendling 							entry.extensionFields.scopeIndex = nl->corkIndex;
441ec945a05SColomban Wendling 						r = makeTagEntry (&entry);
442407b0a02SColomban Wendling 						if (levelNumber < 50 /* exclude special levels */)
443407b0a02SColomban Wendling 						{
444ec945a05SColomban Wendling 							nl = nestingLevelsPush (levels, r);
4453303a28cSColomban Wendling 							CBL_NL (nl) = levelNumber;
4463303a28cSColomban Wendling 						}
4473303a28cSColomban Wendling 					}
4483303a28cSColomban Wendling 				}
449407b0a02SColomban Wendling 			}
4503303a28cSColomban Wendling 			else if (*word && *line == '.')
4513303a28cSColomban Wendling 				makeCOBOLTag (word, K_PARAGRAPH);
4523303a28cSColomban Wendling 			else
4533303a28cSColomban Wendling 			{
4543303a28cSColomban Wendling 				int keyword2;
455ec945a05SColomban Wendling 
4563303a28cSColomban Wendling 				READ_KEYWORD (keyword2);
4573303a28cSColomban Wendling 				SKIP_SPACES ();
4583303a28cSColomban Wendling 
4593303a28cSColomban Wendling 				if (keyword2 == KEYWORD_DIVISION && *line == '.')
4603303a28cSColomban Wendling 					makeCOBOLTag (word, K_DIVISION);
4613303a28cSColomban Wendling 				else if (keyword2 == KEYWORD_SECTION && *line == '.')
4623303a28cSColomban Wendling 					makeCOBOLTag (word, K_SECTION);
463ec945a05SColomban Wendling 			}
464e57cf27dSColomban Wendling 		}
465e57cf27dSColomban Wendling 	}
466e57cf27dSColomban Wendling 
467ec945a05SColomban Wendling 	nestingLevelsFree (levels);
4683303a28cSColomban Wendling 	cblppDeinit ();
469e167948bSMasatake YAMATO }
470e167948bSMasatake YAMATO 
findCOBOLFixedTags(void)471174851b3SColomban Wendling static void findCOBOLFixedTags (void)
472174851b3SColomban Wendling {
473174851b3SColomban Wendling 	findCOBOLTags (FORMAT_FIXED);
474174851b3SColomban Wendling }
475174851b3SColomban Wendling 
findCOBOLFreeTags(void)476174851b3SColomban Wendling static void findCOBOLFreeTags (void)
477174851b3SColomban Wendling {
478174851b3SColomban Wendling 	findCOBOLTags (FORMAT_FREE);
479174851b3SColomban Wendling }
480174851b3SColomban Wendling 
findCOBOLVariableTags(void)481174851b3SColomban Wendling static void findCOBOLVariableTags (void)
482174851b3SColomban Wendling {
483174851b3SColomban Wendling 	findCOBOLTags (FORMAT_VARIABLE);
484174851b3SColomban Wendling }
485174851b3SColomban Wendling 
initializeCobolParser(langType language)48695ecd0e1SMasatake YAMATO static void initializeCobolParser (langType language)
48795ecd0e1SMasatake YAMATO {
488e57cf27dSColomban Wendling 	Lang_cobol = language;
48995ecd0e1SMasatake YAMATO }
49095ecd0e1SMasatake YAMATO 
commonCobolParserDefinition(const char * name,simpleParser parser)491174851b3SColomban Wendling static parserDefinition* commonCobolParserDefinition (const char *name,
492174851b3SColomban Wendling 													  simpleParser parser)
4933ae02089SMasatake YAMATO {
494174851b3SColomban Wendling 	parserDefinition* def = parserNew (name);
49595ecd0e1SMasatake YAMATO 	def->initialize = initializeCobolParser;
496174851b3SColomban Wendling 	def->parser = parser;
49709ae690fSMasatake YAMATO 	def->kindTable = CobolKinds;
49895ecd0e1SMasatake YAMATO 	def->kindCount = ARRAY_SIZE(CobolKinds);
49995ecd0e1SMasatake YAMATO 	def->keywordTable = cobolKeywordTable;
50095ecd0e1SMasatake YAMATO 	def->keywordCount = ARRAY_SIZE(cobolKeywordTable);
501ec945a05SColomban Wendling 	def->useCork = CORK_QUEUE;
5023ae02089SMasatake YAMATO 	return def;
5033ae02089SMasatake YAMATO }
504174851b3SColomban Wendling 
CobolParser(void)505174851b3SColomban Wendling extern parserDefinition* CobolParser (void)
506174851b3SColomban Wendling {
507174851b3SColomban Wendling 	static const char *const extensions [] = {
508174851b3SColomban Wendling 			"cbl", "cob", "CBL", "COB", NULL };
509174851b3SColomban Wendling 	parserDefinition* def = commonCobolParserDefinition ("Cobol",
510174851b3SColomban Wendling 														 findCOBOLFixedTags);
511174851b3SColomban Wendling 	def->extensions = extensions;
512174851b3SColomban Wendling 	return def;
513174851b3SColomban Wendling }
514174851b3SColomban Wendling 
CobolFreeParser(void)515174851b3SColomban Wendling extern parserDefinition* CobolFreeParser (void)
516174851b3SColomban Wendling {
517174851b3SColomban Wendling 	return commonCobolParserDefinition ("CobolFree", findCOBOLFreeTags);
518174851b3SColomban Wendling }
519174851b3SColomban Wendling 
CobolVariableParser(void)520174851b3SColomban Wendling extern parserDefinition* CobolVariableParser (void)
521174851b3SColomban Wendling {
522174851b3SColomban Wendling 	return commonCobolParserDefinition ("CobolVariable", findCOBOLVariableTags);
523174851b3SColomban Wendling }
524