Przeglądaj źródła

Added grind support

ceriel 33 lat temu
rodzic
commit
3015fc2542

+ 1 - 0
lang/cem/cemcom/.distr

@@ -98,3 +98,4 @@ type.c
 type.str
 util.str
 util.c
+stab.c

+ 4 - 0
lang/cem/cemcom/BigPars

@@ -143,4 +143,8 @@
 !File: regcount.h
 #undef REGCOUNT		1	/* count occurrences for register messages */
 
+!File: dbsymtab.h
+#define DBSYMTAB	1	/* ability to produce symbol table for debugger
+*/
+
 

+ 5 - 0
lang/cem/cemcom/SmallPars

@@ -144,3 +144,8 @@
 #undef REGCOUNT		1	/* count occurrences for register messages */
 
 
+!File: dbsymtab.h
+#undef DBSYMTAB		1	/* ability to produce symbol table for debugger
+*/
+
+

+ 2 - 0
lang/cem/cemcom/cemcom.1

@@ -29,6 +29,8 @@ the same as \fB\-D\fIname\fR=1.
 insert \fIdirname\fR in the list of include directories.
 .IP \fB\-M\fP\fIn\fP
 set maximum identifier length to \fIn\fP.
+.IP \fB\-g\fP
+produce a DBX-style symbol table.
 .IP \fB\-n\fR
 do not generate EM register messages.
 The user-declared variables are not stored into registers on the target

+ 89 - 10
lang/cem/cemcom/code.c

@@ -3,9 +3,10 @@
  * See the copyright notice in the ACK home directory, in the file "Copyright".
  */
 /* $Header$ */
-/*	C O D E - G E N E R A T I N G   R O U T I N E S		*/
+/*	C O D E - G E N E R A T I N G	R O U T I N E S		*/
 
 #include	"lint.h"
+#include	"dbsymtab.h"
 #ifndef	LINT
 #include	<em.h>
 #else
@@ -34,7 +35,10 @@
 #include	"atw.h"
 #include	"assert.h"
 #include	"noRoption.h"
-#include	"file_info.h"
+#include	"LLlex.h"
+#ifdef DBSYMTAB
+#include	<stb.h>
+#endif /* DBSYMTAB */
 
 label lab_count = 1;
 label datlab_count = 1;
@@ -68,6 +72,24 @@ init_code(dst_file)
 		fatal("cannot write to %s\n", dst_file);
 	C_magic();
 	C_ms_emx(word_size, pointer_size);
+#ifdef DBSYMTAB
+	if (options['g']) {
+		extern char *source;
+
+		C_ms_std(source, N_SO, 0);
+		stb_typedef(int_type, "int");
+		stb_typedef(char_type, "char");
+		stb_typedef(long_type, "long");
+		stb_typedef(short_type, "short");
+		stb_typedef(uchar_type, "unsigned char");
+		stb_typedef(ushort_type, "unsigned short");
+		stb_typedef(ulong_type, "unsigned long");
+		stb_typedef(uint_type, "unsigned int");
+		stb_typedef(float_type, "float");
+		stb_typedef(double_type, "double");
+		stb_typedef(void_type, "void");
+	}
+#endif /* DBSYMTAB */
 #ifdef USE_TMP
 #ifdef PREPEND_SCOPES
 	C_insertpart(tmp_id = C_getid());
@@ -140,7 +162,7 @@ prepend_scopes()
 	while (se != 0)	{
 		register struct idf *id = se->se_idf;
 		register struct def *df = id->id_def;
-		
+
 		if (df && (df->df_initialized || df->df_used || df->df_alloc))
 			code_scope(id->id_text, df);
 		se = se->next;
@@ -159,7 +181,7 @@ code_scope(text, def)
 		as given by def, if meaningful.
 	*/
 	int fund = def->df_type->tp_fund;
-	
+
 	switch (def->df_sc)	{
 	case EXTERN:
 	case GLOBAL:
@@ -257,6 +279,14 @@ begin_proc(ds, idf)		/* to be called when entering a procedure */
 		C_fil_dlb(file_name_label, (arith)0);
 		C_lin((arith)LineNumber);
 	}
+#ifdef DBSYMTAB
+	if (options['g']) {
+		stb_string(def, FUNCTION, name);
+		if (! strcmp(name, "main")) {
+			C_ms_stb_cst(name, N_MAIN, 0, (arith) 0);
+		}
+	}
+#endif
 }
 
 end_proc(fbytes)
@@ -339,6 +369,9 @@ do_return()
 		probably smarter than generating a direct return.
 		Return sequences may be expensive.
 	*/
+#ifdef DBSYMTAB
+	if (options['g']) db_line(dot.tk_file, dot.tk_line);
+#endif /* DBSYMTAB */
 	C_bra(return2_label);
 }
 
@@ -373,7 +406,7 @@ code_declaration(idf, expr, lvl, sc)
 		Since the expression may be modified in the process,
 		code_declaration() frees it after use, as the caller can
 		no longer do so.
-		
+
 		If there is a storage class indication (EXTERN/STATIC),
 		code_declaration() will generate an exa or ina.
 		The sc is the actual storage class, as given in the
@@ -386,9 +419,15 @@ code_declaration(idf, expr, lvl, sc)
 	register struct def *def = idf->id_def;
 	register arith size = def->df_type->tp_size;
 	int def_sc = def->df_sc;
-	
-	if (def_sc == TYPEDEF)	/* no code for typedefs		*/
+
+	if (def_sc == TYPEDEF)	{	/* no code for typedefs		*/
+#ifdef DBSYMTAB
+		if (options['g']) {
+			stb_typedef(def->df_type, idf->id_text);
+		}
+#endif /* DBSYMTAB */
 		return;
+	}
 	if (sc == EXTERN && expr && !is_anon_idf(idf))
 		error("%s is extern; cannot initialize", idf->id_text);
 	if (lvl == L_GLOBAL)	{	/* global variable	*/
@@ -418,6 +457,11 @@ code_declaration(idf, expr, lvl, sc)
 			/*	they are handled on the spot and get an
 				integer label in EM.
 			*/
+#ifdef DBSYMTAB
+			if (options['g'] && ! expr) {
+				stb_string(def, sc, idf->id_text);
+			}
+#endif /* DBSYMTAB */
 			C_df_dlb((label)def->df_address);
 			if (expr) { /* there is an initialisation */
 			}
@@ -436,6 +480,11 @@ code_declaration(idf, expr, lvl, sc)
 			break;
 		case AUTO:
 		case REGISTER:
+#ifdef DBSYMTAB
+			if (options['g']) {
+				stb_string(def, sc, idf->id_text);
+			}
+#endif /* DBSYMTAB */
 			if (expr)
 				loc_init(expr, idf);
 			break;
@@ -456,7 +505,7 @@ loc_init(expr, id)
 	*/
 	register struct expr *e = expr;
 	register struct type *tp = id->id_def->df_type;
-	
+
 	ASSERT(id->id_def->df_sc != STATIC);
 	switch (tp->tp_fund)	{
 	case ARRAY:
@@ -507,17 +556,22 @@ bss(idf)
 	/*	bss() allocates bss space for the global idf.
 	*/
 	arith size = idf->id_def->df_type->tp_size;
-	
+
 #ifndef	PREPEND_SCOPES
 	code_scope(idf->id_text, idf->id_def);
 #endif	PREPEND_SCOPES
+#ifdef DBSYMTAB
+	if (options['g']) {
+		stb_string(idf->id_def, idf->id_def->df_sc, idf->id_text);
+	}
+#endif /* DBSYMTAB */
 	/*	Since bss() is only called if df_alloc is non-zero, and
 		since df_alloc is only non-zero if size >= 0, we have:
 	*/
 	/*	but we already gave a warning at the declaration of the
 		array. Besides, the message given here does not apply to
 		voids
-	
+
 	if (options['R'] && size == 0)
 		warning("actual array of size 0");
 	*/
@@ -558,6 +612,9 @@ code_expr(expr, val, code, tlbl, flbl)
 #ifndef	LINT
 	if (! options['L'])	/* profiling	*/
 		C_lin((arith)(expr->ex_line));
+#ifdef DBSYMTAB
+	if (options['g']) db_line(expr->ex_file, (unsigned int)expr->ex_line);
+#endif
 	EVAL(expr, val, code, tlbl, flbl);
 #else	LINT
 	lint_expr(expr, code ? USED : IGNORED);
@@ -583,6 +640,9 @@ code_break()
 {
 	register struct stmt_block *stmt_block = stmt_stack;
 
+#ifdef DBSYMTAB
+	if (options['g']) db_line(dot.tk_file, dot.tk_line);
+#endif /* DBSYMTAB */
 	if (stmt_block)
 		C_bra(stmt_block->st_break);
 	else
@@ -600,6 +660,9 @@ code_continue()
 
 	while (stmt_block)	{
 		if (stmt_block->st_continue)	{
+#ifdef DBSYMTAB
+			if (options['g']) db_line(dot.tk_file, dot.tk_line);
+#endif /* DBSYMTAB */
 			C_bra(stmt_block->st_continue);
 			return;
 		}
@@ -651,3 +714,19 @@ prc_exit()
 		C_asp(pointer_size);
 	}
 }
+
+#ifdef DBSYMTAB
+db_line(file, line)
+	char		*file;
+	unsigned int	line;
+{
+	static unsigned	oldline;
+	static char	*oldfile;
+
+	if (file != oldfile || line != oldline) {
+		C_ms_std((char *) 0, N_SLINE, (int) line);
+		oldline = line;
+		oldfile = file;
+	}
+}
+#endif /* DBSYMTAB */

+ 27 - 3
lang/cem/cemcom/declar.g

@@ -7,6 +7,7 @@
 
 {
 #include	"lint.h"
+#include	"dbsymtab.h"
 #include	<alloc.h>
 #include	"nobitfield.h"
 #include	"debug.h"
@@ -54,7 +55,7 @@ declaration
 	This means that something like:
 		unsigned extern int short xx;
 	is perfectly good C.
-	
+
 	On top of that, multiple occurrences of storage_class_specifiers,
 	unsigned_specifiers and size_specifiers are errors, but a second
 	type_specifier should end the decl_specifiers and be treated as
@@ -65,7 +66,7 @@ declaration
 	occurrence of the type_specifier in the grammar (we have no choice),
 	collecting all data in a `struct decspecs' and turning that data
 	structure into what we want.
-	
+
 	The existence of declarations like
 		short typedef yepp;
 	makes all hope of writing a specific grammar for typedefs illusory.
@@ -223,8 +224,19 @@ initializer(struct idf *idf; int sc;)
 #ifdef	LINT
 			change_state(idf, SET);
 #endif	LINT
+#ifdef	DBSYMTAB
+			if (options['g'] && level >= L_LOCAL && expr) {
+				db_line(expr->ex_file, (unsigned) expr->ex_line)
+;
+			}
+#endif	/* DBSYMTAB */
 			code_declaration(idf, expr, level, sc);
 		}
+#ifdef	DBSYMTAB
+		if (options['g'] && globalflag) {
+			stb_string(idf->id_def, sc, idf->id_text);
+		}
+#endif	/* DBSYMTAB */
 		init_idf(idf);
 	}
 ;
@@ -295,7 +307,7 @@ formal(struct formal **fmp;)
 	identifier(&idf)
 	{
 		register struct formal *new = new_formal();
-		
+
 		new->fm_idf = idf;
 		new->next = *fmp;
 		*fmp = new;
@@ -318,6 +330,13 @@ enum_specifier(register struct type **tpp;)
 		[
 			{declare_struct(ENUM, idf, tpp);}
 			enumerator_pack(*tpp, &l)
+			{
+#ifdef DBSYMTAB
+				if (options['g']) {
+					stb_tag(idf->id_enum, idf->id_text);
+				}
+#endif /*DBSYMTAB */
+			}
 		|
 			{apply_struct(ENUM, idf, tpp);}
 			empty
@@ -383,6 +402,11 @@ struct_or_union_specifier(register struct type **tpp;)
 			struct_declaration_pack(*tpp)
 			{
 				(idf->id_struct->tg_busy)--;
+#ifdef DBSYMTAB
+				if (options['g']) {
+					stb_tag(idf->id_struct, idf->id_text);
+				}
+#endif /*DBSYMTAB */
 			}
 		|
 			{apply_struct(fund, idf, tpp);}

+ 21 - 9
lang/cem/cemcom/domacro.c

@@ -15,16 +15,22 @@
 #include	"nopp.h"
 
 #ifndef NOPP
-#include	"ifdepth.h"	
-#include	"botch_free.h"	
-#include	"nparams.h"	
-#include	"parbufsize.h"	
-#include	"textsize.h"	
-#include	"idfsize.h"	
+#include	"ifdepth.h"
+#include	"botch_free.h"
+#include	"nparams.h"
+#include	"parbufsize.h"
+#include	"textsize.h"
+#include	"idfsize.h"
 #include	"assert.h"
 #include	<alloc.h>
 #include	"class.h"
 #include	"macro.h"
+#include	"dbsymtab.h"
+#ifdef DBSYMTAB
+#include	<stb.h>
+int		IncludeLevel = 0;
+extern char	options[];
+#endif
 
 IMPORT char **inctable;	/* list of include directories		*/
 IMPORT char *getwdir();
@@ -269,6 +275,12 @@ do_include()
 			FileName = result;
 			LineNumber = 0;
 			nestlow = nestlevel;
+#ifdef DBSYMTAB
+			IncludeLevel++;
+			if (options['g']) {
+				C_ms_std(FileName, N_BINCL, 0);
+			}
+#endif /* DBSYMTAB */
 		}
 	}
 }
@@ -294,7 +306,7 @@ do_define()
 		return;
 	}
 	/*	there is a formal parameter list if the identifier is
-		followed immediately by a '('. 
+		followed immediately by a '('.
 	*/
 	LoadChar(ch);
 	if (ch == '(') {
@@ -500,7 +512,7 @@ macro_def(id, text, nformals, length, flags)
 	else
 		id->id_macro = newdef = new_macro();
 	newdef->mc_text = text;		/* replacement text	*/
-	newdef->mc_nps  = nformals;	/* nr of formals	*/
+	newdef->mc_nps	= nformals;	/* nr of formals	*/
 	newdef->mc_length = length;	/* length of repl. text	*/
 	newdef->mc_flag = flags;	/* special flags	*/
 	newdef->mc_count = 0;
@@ -634,7 +646,7 @@ PRIVATE
 macroeq(s, t)
 	register char *s, *t;
 {
-	
+
 	/* skip leading spaces	*/
 	while (BLANK(*s)) s++;
 	while (BLANK(*t)) t++;

+ 17 - 12
lang/cem/cemcom/idf.c

@@ -100,12 +100,12 @@ hash_stat()
 {
 	if (options['h'])	{
 		register int i;
-		
+
 		print("Hash table tally:\n");
 		for (i = 0; i < HASHSIZE; i++)	{
 			register struct idf *notch = idf_hashtable[i];
 			int cnt = 0;
-	
+
 			while (notch)	{
 				cnt++;
 				notch = notch->next;
@@ -113,7 +113,7 @@ hash_stat()
 			print("%d %d\n", i, cnt);
 		}
 		print("End hash table tally\n");
-	}		
+	}
 }
 #endif	DEBUG
 
@@ -122,7 +122,7 @@ str2idf(tg)
 	char tg[];
 {
 	/*	str2idf() returns an entry in the symbol table for the
-		identifier tg.  If necessary, an entry is created.
+		identifier tg.	If necessary, an entry is created.
 		It is used where the text of the identifier is available
 		but its hash value is not; otherwise idf_hashed() is to
 		be used.
@@ -187,7 +187,7 @@ declare_idf(ds, dc, lvl)
 	register struct type *type;
 	struct stack_level *stl = stack_level_of(lvl);
 	char formal_array = 0;
-	
+
 	/* determine the present type */
 	if (ds->ds_type == 0)	{
 		/*	at the L_FORMAL1 level there is no type specified yet
@@ -276,7 +276,7 @@ declare_idf(ds, dc, lvl)
 	check_hiding(idf, lvl, sc);	/* of some idf by this idf */
 #endif	LINT
 
-	if (def && 
+	if (def &&
 	    ( def->df_level == lvl ||
 	      ( lvl != L_GLOBAL && def->df_level > lvl )
 	    )
@@ -382,7 +382,7 @@ actual_declaration(sc, tp)
 	/*	An actual_declaration needs space, right here and now.
 	*/
 	register int fund = tp->tp_fund;
-	
+
 	if (sc == ENUM || sc == TYPEDEF) /* virtual declarations */
 		return 0;
 	if (fund == FUNCTION || fund == ARRAY)
@@ -569,7 +569,7 @@ declare_params(dc)
 	/*	Declares the formal parameters if they exist.
 	*/
 	register struct formal *fm = dc->dc_formal;
-	
+
 	while (fm)	{
 		declare_parameter(fm->fm_idf);
 		fm = fm->next;
@@ -584,7 +584,7 @@ init_idf(idf)
 	/*	The topmost definition of idf is set to initialized.
 	*/
 	register struct def *def = idf->id_def;	/* the topmost */
-	
+
 	if (def->df_initialized)
 		error("multiple initialization of %s", idf->id_text);
 	if (def->df_sc == TYPEDEF)	{
@@ -630,7 +630,7 @@ declare_formals(fp)
 #endif	DEBUG
 	while (se)	{
 		register struct def *def = se->se_idf->id_def;
-		
+
 		def->df_address = f_offset;
 		/*	the alignment convention for parameters is: align on
 			word boundaries, i.e. take care that the following
@@ -638,11 +638,16 @@ declare_formals(fp)
 		*/
 		f_offset = align(f_offset + def->df_type->tp_size, (int) word_size);
 		formal_cvt(def); /* cvt int to char or short, if necessary */
-		se = se->next;
 		def->df_level = L_FORMAL2;	/* CJ */
 		RegisterAccount(def->df_address, def->df_type->tp_size,
 				regtype(def->df_type),
 				def->df_sc);
+#ifdef DBSYMTAB
+		if (options['g']) {
+			stb_string(def, FORMAL, se->se_idf->id_text);
+		}
+#endif /* DBSYMTAB */
+		se = se->next;
 	}
 	*fp = f_offset;
 }
@@ -721,7 +726,7 @@ init_hmask()
 		described in Knuth, vol 2.
 	*/
 	register int h, rnd = HASH_X;
-	
+
 	for (h = 0; h < IDFSIZE; h++)	{
 		hmask[h] = rnd;
 		rnd = (HASH_A * rnd + HASH_C) & HASHMASK;

+ 12 - 0
lang/cem/cemcom/input.c

@@ -14,7 +14,13 @@ extern int		nestlevel;
 #include "nopp.h"
 #include <inp_pkg.body>
 
+#include	"dbsymtab.h"
 #ifndef NOPP
+#ifdef DBSYMTAB
+#include	<stb.h>
+extern int	IncludeLevel;
+extern char	options[];
+#endif
 char *
 getwdir(fn)
 	register char *fn;
@@ -64,6 +70,12 @@ AtEoIF()
 	if (NoUnstack) lexerror("unexpected EOF");
 #ifndef NOPP
 	nestlevel = nestlow;
+#ifdef DBSYMTAB
+	if (options['g'] && IncludeLevel > 0) {
+		C_ms_std(FileName, N_EINCL, 0);
+	}
+	IncludeLevel--;
+#endif
 #endif
 	return 0;
 }

+ 4 - 2
lang/cem/cemcom/main.c

@@ -265,6 +265,10 @@ compile(argc, argv)
 	init();
 	LineNumber = 0;
 	nestlow = -1;
+#ifndef LINT
+	init_code(destination && strcmp(destination, "-") != 0 ?
+				destination : 0);
+#endif
 #ifndef NOPP
 	WorkingDir = getwdir(source);
 #endif NOPP
@@ -279,8 +283,6 @@ compile(argc, argv)
 #endif DEBUG
 	{
 #ifndef	LINT
-		init_code(destination && strcmp(destination, "-") != 0 ?
-					destination : 0);
 		/* compile the source text			*/
 		C_program();
 #ifdef PREPEND_SCOPES

+ 2 - 1
lang/cem/cemcom/options

@@ -4,12 +4,13 @@ C	while running preprocessor, copy comment
 d	perform a small dataflow analysis
 D	see identifier following as a macro
 E	run preprocessor only
+g	produce symbol table for debugger
 i	suppress /usr/include include files in dependency list
 I	expand include table with directory name following
+L	don't generate linenumbers and filename indications
 m	generate file.o: file1.h format dependency lines
 M	set identifier length
 n	don't generate register messages
-L	don't generate linenumbers and filename indications
 p	trace
 P	in running the preprocessor do not output '# line' lines
 R	restricted C

+ 15 - 8
lang/cem/cemcom/options.c

@@ -3,7 +3,7 @@
  * See the copyright notice in the ACK home directory, in the file "Copyright".
  */
 /* $Header$ */
-/*	U S E R   O P T I O N - H A N D L I N G		*/
+/*	U S E R	  O P T I O N - H A N D L I N G		*/
 
 #include	"lint.h"
 #include	"botch_free.h"
@@ -21,6 +21,7 @@
 #include	"use_tmp.h"
 #include	"dataflow.h"
 #include	"noRoption.h"
+#include	"dbsymtab.h"
 
 #ifndef NOPP
 extern char **inctable;
@@ -91,7 +92,7 @@ next_option:			/* to allow combined one-char options */
 
 #ifndef LINT
 #ifndef NOPP
-	case 'A' :      /* Amake dependency generation */
+	case 'A' :	/* Amake dependency generation */
 		do_dependencies = 1;
 		if (*text) {
 			dep_file = text;
@@ -103,7 +104,13 @@ next_option:			/* to allow combined one-char options */
 		break;
 #endif NOPP
 #endif LINT
-		
+#ifdef DBSYMTAB
+	case 'g':	/* symbol table for debugger */
+		options['g'] = 1;
+		options['n'] = 1;
+		break;
+#endif /* DBSYMTAB */
+
 	case 'R':			/* strict version */
 #ifndef	NOROPTION
 		options[opt] = 1;
@@ -176,15 +183,15 @@ deleted, is now a debug-flag
 		if (*text)	{
 			int i;
 			register char *new = text;
-			
+
 			if (++inc_total > inc_max) {
 				inctable = (char **)
 				  Realloc(inctable,(inc_max+=10)*sizeof(char *));
 			}
-				
+
 			for (i = inc_pos++; i < inc_total; i++) {
 				char *tmp = inctable[i];
-				
+
 				inctable[i] = new;
 				new = tmp;
 			}
@@ -235,7 +242,7 @@ deleted, is now a debug-flag
 #endif USE_TMP
 		break;
 	}
-		
+
 	case 'U' :	{	/* -Uname :	undefine predefined	*/
 #ifndef NOPP
 		register struct idf *idef;
@@ -353,7 +360,7 @@ txt2int(tp)
 		*tp; the resulting value is yielded.
 	*/
 	register int val = 0, ch;
-	
+
 	while (ch = **tp, ch >= '0' && ch <= '9')	{
 		val = val * 10 + ch - '0';
 		(*tp)++;

+ 4 - 2
lang/cem/cemcom/proto.make

@@ -61,7 +61,9 @@ SRC_C = \
 	$(SRC_DIR)/switch.c \
 	$(SRC_DIR)/tokenname.c \
 	$(SRC_DIR)/type.c \
-	$(SRC_DIR)/util.c
+	$(SRC_DIR)/util.c \
+	$(SRC_DIR)/stab.c
+
 GEN_C =	tokenfile.c program.c declar.c expression.c statement.c ival.c \
 	symbol2str.c char.c Lpars.c next.c
 CFILES=	$(SRC_C) $(GEN_C)
@@ -96,7 +98,7 @@ GEN_H = botch_free.h dataflow.h debug.h density.h errout.h \
         regcount.h \
 	code.h declar.h decspecs.h def.h expr.h field.h estack.h util.h \
 	idf.h macro.h stmt.h struct.h switch.h type.h l_brace.h l_state.h \
-	l_outdef.h stack.h lapbuf.h noRoption.h nofloat.h
+	l_outdef.h stack.h lapbuf.h noRoption.h nofloat.h dbsymtab.h
 
 HFILES=	$(GEN_H) $(SRC_H)
 

+ 32 - 1
lang/cem/cemcom/statement.g

@@ -16,6 +16,7 @@
 
 #include	"debug.h"
 #include	"botch_free.h"
+#include	"dbsymtab.h"
 
 #include	"arith.h"
 #include	"LLlex.h"
@@ -26,8 +27,12 @@
 #include	"code.h"
 #include	"stack.h"
 #include	"def.h"
+#ifdef DBSYMTAB
+#include	<stb.h>
+#endif /* DBSYMTAB */
 
 extern int level;
+extern char options[];
 }
 
 /*	Each statement construction is stacked in order to trace a ???
@@ -451,7 +456,14 @@ jump
 		}
 ;
 
-compound_statement:
+compound_statement
+	{
+#ifdef DBSYMTAB
+	static int	brc_level = 1;
+	int		decl_seen = brc_level == 1;
+#endif /* DBSYMTAB */
+	}
+:
 	'{'
 		{
 			stack_level();
@@ -460,13 +472,32 @@ compound_statement:
 		 (DOT == IDENTIFIER && AHEAD == IDENTIFIER))
 			/* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */
 		declaration
+		{
+#ifdef DBSYMTAB
+			decl_seen++;
+#endif /* DBSYMTAB */
+		}
 	]*
+		{
+#ifdef DBSYMTAB
+			++brc_level;
+			if (options['g'] && decl_seen) {
+				C_ms_std((char *) 0, N_LBRAC, brc_level);
+			}
+#endif /* DBSYMTAB */
+		}
 	[%persistent
 		statement
 	]*
 	'}'
 		{
 			unstack_level();
+#ifdef DBSYMTAB
+			if (options['g'] && decl_seen) {
+				C_ms_std((char *) 0, N_RBRAC, brc_level);
+			}
+			brc_level--;
+#endif /* DBSYMTAB */
 		}
 ;
 

+ 4 - 0
lang/cem/cemcom/type.str

@@ -7,6 +7,7 @@
 
 #include	"nofloat.h"
 #include	"nobitfield.h"
+#include	"dbsymtab.h"
 
 struct type	{
 	struct type *next;	/* used only with ARRAY */
@@ -22,6 +23,9 @@ struct type	{
 	struct type *tp_pointer;/* to POINTER */
 	struct type *tp_array;	/* to ARRAY */
 	struct type *tp_function;/* to FUNCTION */
+#ifdef DBSYMTAB
+	int tp_dbindex;
+#endif
 };
 
 extern struct type