Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dthelp / parser / pass1 / util / context.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: context.c /main/3 1995/11/08 10:29:06 rswiston $ */
24 /*
25               Copyright 1986 Tandem Computers Incorporated.
26 This product and information is proprietary of Tandem Computers Incorporated.
27                Copyright (c) 1986, 1987, 1988, 1989 Hewlett-Packard Co.
28 */
29
30 /*
31 Context.c contains the main procedure for program CONTEXT.
32
33 CONTEXT builds scanning and parsing tables for a simple
34 state-transition recognizer.  Input consists of two files, delimiter
35 declarations in file "delim.dat" and state tables with corresponding
36 actions in file "context.dat". If a parameter is present on the
37 command line, a sparse matrix technique is used to encode some of the
38 output arrays.
39
40 Data lines in "delim.dat" contain the name of the delimiter followed
41 by the text of the delimiter (one or more non-white space
42 characters).  The delimiter name must begin in the first column.  
43 Lines with white-space in the first column are considered comments.
44
45 Data in "context.dat" consists of free-form multi-line declarations.
46 Each declaration is terminated by a semi-colon. It begins with the
47 name of a token followed by any number of pairs of contexts (parser
48 states).  The context pairs are separated by a colon and may
49 optionally be followed by some C code enclosed in braces.  In each
50 pair, the first context is one in which the delimiter is recognized,
51 the second is the state that will result from an occurrence of the
52 delimiter in the first context. If code is specified, it is to be
53 executed by the parser when the delimiter occurs in the first context
54 of the pair. If successive pairs of contexts are separated by a
55 comma, code which follows is common to all the pairs.
56
57 The tokens specified in "context.dat" can either be delimiters defined in
58 "delim.dat" or other tokens (e.g., number, name, end_of_file) that will
59 be recognized by the user-defined scanner.
60
61 For example, suppose "delim.dat" contains the line
62
63                grpo (
64
65 and "context.dat" includes
66
67                grpo element:namegroup
68                     content:model {openmod() ;}
69                     excon:openex
70                     pcon:type ;
71
72                name namegroup:namesep {eltname() ;}
73                     model:connector,
74                     model2:connector
75                       {storemod(nstring) ;}
76
77 These declarations specify that the "grpo" delimiter is "(" and is
78 recognized in contexts "element", "content", "excon", and "pcon". 
79 Procedure openmod() is called when "grpo" occurs in "content" and,
80 beyond the state change, no code is executed in other contexts when
81 "grpo" occurs.  The "name" token is valid in contexts "namegroup",
82 "model", and "model2"; in the first, the context is set to "namesep"
83 and procedure eltname() is called, in the last two, the context is
84 set to "connector" and storemod(nstring) is called.
85
86 The program has several output files: case.c, delim.h, context.h, and
87 error.  Case.c contains nested switch statements to execute the code
88 specified with the context transitions.  Delim.h contains C
89 declarations related to delimiters; context.h has declarations
90 related to contexts.  Programs that include delim.h should define
91 M_DELIMDEF for definition form of the declarations and not define it
92 for the declaration form.  Programs that include context.h should
93 define M_CONDEF analogously.
94
95 The program numbers the delimiter names and the contexts as
96 encountered and outputs corresponding #define instructions with all
97 letters in the names forced to uppercase to delim.h and context.h.
98 In addition, an array named for each delimiter (with all letters
99 forced to lowercase) is initialized to the delimiter text.  The first
100 declaration in the above example, for instance, would result in the
101 following lines written to delim.h:
102
103                #define GRPO 1
104                M_DELIMEXTERN char grpo[] M_DELIMINIT("(") ;
105
106 These lines would be written to context.h:
107
108                #define ELEMENT 1
109                #define NAMEGROUP 2
110                #define CONTENT 3
111                #define MODEL 4
112                #define EXCON 5
113                #define OPENEX 6
114                #define PCON 7
115                #define TYPE 8
116                #define NAMESEP 9
117                #define CONNECTOR 10
118                #define MODEL2 11
119
120 Delim.h also contains an array, m_dlmptr, which contains pointers to the
121 names of all the defined delimiters.  In addition, delim.h contains the
122 declaration of a tree representation of the delimiters allowed in each
123 context. Internally, the program represents the delimiter strings with a
124 tree.  The children of the root of this tree represent the set of characters
125 with which delimiters can start. Children of other nodes represent
126 characters that can follow the character of their parent.  Leaf nodes
127 are associated with the null character, indicating the end of a
128 delimiter.  A path from the root to a leaf thus represents a valid
129 delimiter.
130
131 The form in which the tree is represented within this program is not
132 quite the same as the output data structure.  In the latter, each
133 element consists of a flag called 'more' indicating whether it is the last
134 child of its parent; a character, called 'symbol'; and an integer,
135 called 'index'. All sons of a node are stored in adjacent elements
136 ordered in increaing value of their 'symbol' fields. 'Symbol'
137 contains the character associated with the node (0 if the node is a
138 leaf node), with the sign bit turned on if the node is the last child
139 of its parent.  'Index' contains the array index of the first son of
140 the node, if the node is not a leaf.  If the node is a leaf, 'index'
141 is the number of the represented delimiter (i.e., 1 for "grpo" in the
142 above example).
143
144 As the tree is constructed, it is not feasible to store brothers in adjacent
145 elements, so the internal data structure is different.  It contains a 'next'
146 field which points to the first brother of a given node. Because the 'next'
147 field can be used to detect the last child of a parent, it is not necessary
148 to use the sign bit of 'symbol' to indicate this special case.
149
150 Two other arrays are written to context.h.  Contree[i] points to the root
151 of the delimiter tree for the ith context within the array tree whose
152 declaration is in delim.h; nextcon[i][j] indicates the state
153 resulting from an occurrence of delimiter j+1 in state i+1.  Finally,
154 a #define of MAXD to the length of the longest delimiter is written to
155 delim.h.
156 */
157
158 #include <stdio.h>
159 #include <malloc.h>
160 #if defined(MSDOS)
161 #include <process.h>
162 #endif
163 #include "basic.h"
164 #include "trie.h"
165
166 #include "common.h"
167 #include "chartype.h"
168 #define CONTDEF 1
169 #include "cont.h"
170
171 /* Main procedure */
172 void main(argc, argv)
173   int argc ;
174   char **argv ;
175 {
176 int n ;
177
178 m_openchk(&delim, "delim.h", "w") ;
179 m_openchk(&context, "context.h", "w") ;
180 m_openchk(&fcase, "case.c", "w") ;
181 m_openchk(&cdat, "context.dat", "r") ;
182 m_openchk(&ddat, "delim.dat", "r") ;
183 m_openchk(&m_errfile, "error", "w") ;
184 fputs("    switch(m_token) {\n", fcase) ; /* keep the "}" balanced */
185
186 fputs("#if defined(M_DELIMDEF)\n", delim) ;
187 fputs("#define M_DELIMEXTERN\n", delim) ;
188 fputs("#define M_DELIMINIT(a) = a\n", delim) ;
189 fputs("#else\n", delim) ;
190 fputs("#define M_DELIMEXTERN extern\n", delim) ;
191 fputs("#define M_DELIMINIT(a)\n", delim) ;
192 fputs("#endif\n\n", delim) ;
193
194 fputs("#if defined(M_CONDEF)\n", context) ;
195 fputs("#define M_CONEXTERN\n", context) ;
196 fputs("#else\n", context) ;
197 fputs("#define M_CONEXTERN extern\n", context) ;
198 fputs("#endif\n\n", context) ;
199
200 contree = (M_TRIE **) calloc(NUMCON, sizeof(M_TRIE *)) ;
201 xtransit = (int *) calloc(NUMCON * NUMDELIM, sizeof(int)) ;
202 contexts = (M_WCHAR **) calloc(NUMCON, sizeof(char *)) ;
203 dlmptr = (char**) calloc(NUMDELIM, sizeof(char*)) ;
204
205 loaddelim() ;
206 while (getdname())
207     {
208     casestarted = FALSE ;
209     while ((n = getContext()) >= 0)
210         {
211         if (withdelim) enterdelim(n) ;
212         getcolon() ;
213         if (transit(n, curdelim))
214             {
215             if (! withdelim) 
216                 {
217                 char *mb_dname, *mb_contexts;
218
219                 mb_dname = MakeMByteString(dname);
220                 mb_contexts = MakeMByteString(contexts[n]);
221                 warning2(
222                     "Duplicate assignment to token \"%s\" in context \"%s\"",
223                          mb_dname,
224                          mb_contexts) ;
225                 m_free(mb_dname,"multi-byte string");
226                 m_free(mb_contexts,"multi-byte string");
227                 }
228             }
229         transit(n, curdelim) = getContext() + 1 ;
230         getcode(n) ;
231         }
232     if (casestarted)
233         {
234         fprintf(fcase, "          default:\n            break ;\n") ;
235         /* keep the "{" balanced */
236         fprintf(fcase, "          }\n        break ;\n") ;
237         }
238     }
239 /* keep the "{" balanced */
240 fprintf(fcase, "      default:\n        break ;\n      }\n") ;
241 fprintf(context, "#define MAXD %d\n", maxd) ;
242 dumptree((LOGICAL) (argc > 1)) ;
243 fprintf(stderr, "NUMCON set to %d\n", NUMCON) ;
244 fprintf(stderr, "NUMDELIM set to %d\n", NUMDELIM) ;
245 exit(errexit) ;
246 }