Classdesc 3.44
tokeninput.h
1/*
2 @copyright Russell Standish 2000-2013
3 @author Russell Standish
4 This file is part of Classdesc
5
6 Open source licensed under the MIT license. See LICENSE for details.
7*/
8
9#include <stdio.h>
10#include <ctype.h>
11#include <stdio.h>
12#include <iostream>
13#include <string.h>
14
15class mark_t;
16
17#ifdef _MSC_VER
18#define USE_FSEEK
19#endif
20
21
22class tokeninput
23{
24 FILE* inputstream;
25 FILE* outputstream;
26 int c;
27 int lineno;
28 char getnextc()
29 {
30 c=fgetc(inputstream);
31 switch (c)
32 {
33 case '\n':
34 //printf("%d\n",lineno); /* for debugging purposes */
35 lineno++;
36 break;
37
38 case '\\': /* check for and remove any line continuations */
39 c=fgetc(inputstream);
40 if (c=='\n')
41 {
42 c=fgetc(inputstream);
43 if (outputstream) fprintf(outputstream,"\\\n");
44 }
45 else {ungetc(c,inputstream); c='\\';}
46 break;
47
48 case '[':
49 c=fgetc(inputstream);
50 if (c=='[') // attribute leadin - discard attribute
51 {
52 char lc=c;
53 while ((c=fgetc(inputstream)) != ']' || lc!=']') lc=c;
54 getnextc();
55 }
56 else
57 {ungetc(c,inputstream); c='[';}
58 break;
59 case EOF:
60 throw eof();
61 break;
62 }
63 if (outputstream &&!feof(inputstream))
64 fputc(c,outputstream);
65 return c;
66 }
67public:
68 struct eof {}; /* signal end of input */
69 string token, lasttoken, tokenBeforeLast;
70 tokeninput(FILE* in, FILE* out=NULL)
71 {inputstream=in; outputstream=out; getnextc(); lineno=1;}
72
73 int line() const {return lineno;}
74
75 /* support for marking and resetting stream */
76 class mark_t;
77 void operator=(mark_t& x);
78 int operator>(mark_t& x); /* returns whether stream is beyond mark */
79 friend class tokeninput::mark_t ;
80
81 void nexttok()
82 {
83
84 token.swap(lasttoken);
85 token.swap(tokenBeforeLast);
86
87 nexttok_again:
88 token.erase();
89 if (feof(inputstream)) throw eof();
90
91 /* skip white space and # control lines */
92 while (isspace(c)) getnextc();
93 while (c=='#')
94 {
95 while (c!='\n' && !feof(inputstream))
96 {
97 if (c!='\r') token+=c; //ignore '\r' (DOS files)
98 if (c=='/' && getnextc()=='*') /* strip comments */
99 for (char l=getnextc(); l!='*' || c!='/'; l=c, getnextc());
100 getnextc();
101 }
102 if (token.find("#pragma")==0)
103 return; /* parse any pragma omits appearing on stdin */
104 else
105 token.erase();
106 while (isspace(c)) getnextc();
107 }
108 if (feof(inputstream)) throw eof();
109
110 if (c=='"' || c=='\'') /* handle strings and chars */
111 {
112 int escape=0;
113 char terminal=c;
114 do
115 {
116 token+=c;
117 escape=c=='\\' && !escape;
118 getnextc();
119 }
120 while (c!=terminal || escape);
121 token+=c; /* include terminal " */
122 getnextc();
123 }
124 else if (strchr("#\\!@$~(){}[]:;,.?%*|-+=<>^&/",c))
125 /* operator tokens -
126 treat # and \ as operators, although they're stripped from
127 preprocessed code */
128 {
129 char lc;
130 token+=lc=c;
131 getnextc();
132 if (c=='=' && !strchr("#\\!@$~(){}[]:;,.?",lc))
133 { /* compound assignment operator */
134 token+=c;
135 getnextc();
136 }
137 else
138 switch (lc)
139 {
140 case '<': case '>': case '|': case '&':
141 case '+': case '-': case ':':
142 if (c==lc) /* double symbol */
143 {
144 token+=c;
145 getnextc();
146 if ((lc=='<' || lc=='>') && c=='=') /* <<= & >>= */
147 {
148 token+=c;
149 getnextc();
150 }
151 }
152 else if (lc=='-' && c=='>') /* -> and ->* operators */
153 {
154 token+=c;
155 getnextc();
156 if (c=='*')
157 {
158 token+=c;
159 getnextc();
160 }
161 }
162 break;
163
164 case '.':
165 // check for for up to a triple
166 if (c=='.')
167 {
168 token+=c;
169 getnextc();
170 if (c=='.')
171 {
172 token+=c;
173 getnextc();
174 }
175 }
176 break;
177 /* consider the pair [] and () as single token,
178 for use with operator */
179
180 case '[':
181 if (c==']')
182 {
183 token+=c;
184 getnextc();
185 }
186 break;
187
188 case '(':
189 if (c==')')
190 {
191 token+=c;
192 getnextc();
193 }
194 break;
195
196 case '/': /* check for comments, and remove from input stream */
197 if (c=='*')
198 {
199 lc=getnextc();
200 while (lc!='*' || c!='/')
201 {
202 lc=c;
203 getnextc();
204 }
205 getnextc(); /* load up next character from input stream */
206 goto nexttok_again; /* get next token */
207 }
208 else if (c=='/')
209 {
210 while (c!='\n') getnextc();
211 goto nexttok_again; /* get next token */
212 }
213 break;
214 }
215 }
216 else if (!isalnum(c) && c!='_')
217 {
218 getnextc();
219 goto nexttok_again; /* skip non 'C' characters */
220 }
221 else
222 {
223 while (isalnum(c) || c=='_')
224 {
225 token+=c;
226 getnextc();
227 }
228 }
229 }
230};
231
232/* support for marking and resetting stream */
234{
235 friend void tokeninput::operator=(mark_t& x);
236 friend int tokeninput::operator>(mark_t& x);
237 fpos_t fp;
238 long offset;
239 tokeninput tokinp;
240public:
241 mark_t(tokeninput& x): tokinp(x)
242 {
243 // if (fgetpos(x.inputstream,&fp)) throw eof();
244 // Some systems (eg CYGWIN) have trouble with fgetpos/fsetpos ?
245 fgetpos(x.inputstream,&fp);
246
247 offset=ftell(x.inputstream);
248 }
249};
250
251void tokeninput::operator=(mark_t& x)
252{
253 *this=x.tokinp;
254#ifdef USE_FSEEK /* some OSes have buggy fsetpos routines */
255 if (fseek(inputstream,x.offset,SEEK_SET)) throw eof();
256#else
257 if (fsetpos(inputstream,&(x.fp))) throw eof();
258#endif
259}
260
261int tokeninput::operator>(mark_t& x)
262{return ftell(inputstream) > x.offset;}
263
264/* redefine isalpha so that '_' is considered an alphabetic char */
265#undef isalpha
266inline int isalpha(char x)
267{return x=='_' || (x>='a' && x<='z') || (x>='A' && x<= 'Z');}
268
269#include <map>
270#include <set>
271template <class K, class T> class hash_map: public map<K,T> {};
272template <class K> class hash_set: public set<K> {};
273
274
275string gobble_delimited(tokeninput& input, const char *left,
276 const char *right)
277{ string argList = input.lasttoken;
278 argList += " " + input.token + " ";
279 int delim_count=0;
280 string tmp=(string)left+right;
281 if (input.token==tmp) return argList; /* catch the () and [] token cases */
282 for (input.nexttok(); input.token!=right || delim_count>0;
283 input.nexttok())
284 {
285 argList += input.token + " ";
286 if (input.token==left) delim_count++;
287 if (input.token==right) delim_count--;
288 if (input.token==">>" && string(left)=="<")
289 {
290 delim_count-=2;
291 if (delim_count<=0) break;
292 }
293 }
294 return argList;
295}
296
297/* grab arguments to template */
298string get_template_args(tokeninput& input)
299{
300 string targs;
301 size_t angle_count=0;
302 do
303 {
304 /* strip out default arguments */
305 if (input.token[0]=='=')
306 while (!strchr(">,",input.token[0]))
307 {
308 if (input.token[0]=='<') gobble_delimited(input,"<",">");
309 input.nexttok();
310 }
311 targs += input.token;
312 if (input.token!=".") targs+=" ";
313 if (input.token[0]=='<') angle_count+=input.token.length();
314 else if (input.token[0]=='>')
315 angle_count-=input.token.length();
316 input.nexttok();
317 }
318 while (angle_count>0);
319 return targs;
320}
321
322
Definition tokeninput.h:271
Definition tokeninput.h:272
Definition tokeninput.h:234
Definition tokeninput.h:23
Definition tokeninput.h:68