source: trunk/src/engine.c @ 7

Last change on this file since 7 was 7, checked in by cameron, 11 years ago

Reference extraction; checking ]]> in text; < in atts.

File size: 12.6 KB
Line 
1/*  engine.c - Parabix XML parsing engine.
2    Copyright (c) 2007, Robert D. Cameron.
3    Licensed to the public under the Open Software License 3.0.
4    Licensed to International Characters, Inc., under the Academic
5    Free License 3.0.
6*/
7
8#include "ilax.h"
9#include "engine.h"
10#include "xmlbuffer.h"
11#include "bitlex.h"
12#include "charsets/ext_ascii_8.h"
13#include "charsets/ext_ascii_16.h"
14
15#include <assert.h>
16#include <stdlib.h>
17#include <errno.h>
18#include <string.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21
22char sentinel[] = "<]]>?>-->'>\">";
23
24ParsingEngine::ParsingEngine (char * filename) {
25#ifdef BUFFER_PROFILING
26        bitstream_timer = init_BOM_timer(BUFFER_BLOCKS * BLOCKSIZE);
27        lextranspose_timer = init_BOM_timer(BUFFER_BLOCKS * BLOCKSIZE);
28        scanner_timer = init_BOM_timer(BUFFER_BLOCKS * BLOCKSIZE);
29#endif
30
31#define OFFSET32_SENTINEL
32#if (BYTE_ORDER == LITTLE_ENDIAN)
33#define bitblock_sfli sisd_slli
34#endif
35
36  /* Install sentinels for every lexical item stream*/
37#ifndef OPTIMIZE_SHORT_SCAN
38  BitBlock sentinel_value = simd_const_1(1);
39#endif
40#ifdef OPTIMIZE_SHORT_SCAN
41  BitBlock sentinel_value = bitblock_sfli(simd_const_1(1), 8*sizeof(unsigned long));
42#endif
43  for (int j = MarkupStart; j < LexicalItemCount; j++) {
44    buf.item_stream[j][BUFFER_BLOCKS] = sentinel_value;
45  }
46  buffer_base_pos = 0;
47  buffer_rel_pos = 0;
48  xml_buf = new XML_Buffer::XML_Buffer(filename, 4*strlen(sentinel));
49}
50
51void ParsingEngine::InitLexer() {
52  unsigned char * XML_signature = xml_buf->GetBytePtr(0);
53  if (xml_buf->PrepareBytes(4) < 4) {
54    printf("No XML input document.\n");
55    exit(-1);
56  }
57  Charset_Family family = Charset_Family_Detect(XML_signature);
58  switch (family) {
59    case Ext_ASCII_8:
60      printf("Ext_ASCII_8 document detected.\n");
61      lex = new Ext_ASCII_8_Lexer::Ext_ASCII_8_Lexer(xml_buf, &buf);
62      //lex = new Lexer::Lexer(xml_buf, &buf);
63      //xml_buf->InstallPadding(sentinel);
64      break;
65    case Ext_ASCII_16BE:
66      printf("Ext_ASCII_16BE document detected.\n");
67      lex = new Ext_ASCII_16BE_Lexer::Ext_ASCII_16BE_Lexer(xml_buf, &buf);
68      break;
69    case Ext_ASCII_16LE:
70      printf("Ext_ASCII_16LE document detected.\n");
71      lex = new Ext_ASCII_16LE_Lexer::Ext_ASCII_16LE_Lexer(xml_buf, &buf);
72      break;
73    default:
74      printf("Error: Charset family %i detected, but not supported.\n", family);
75      exit(-1);
76  }
77  rel_EOF_pos = lex-> AdvanceBuffer(0);
78}
79
80
81inline void ParsingEngine::AdvanceToNewBasePosn(int advance_amt) {
82  buffer_base_pos += advance_amt;
83  buffer_rel_pos = 0;
84}
85
86inline unsigned char * ParsingEngine::x8dataPtr(int offset) const {
87  return &((unsigned char *) buf.x8data)[buffer_rel_pos+offset];
88}
89
90
91inline int ParsingEngine::AbsPos() const {
92  return buffer_base_pos + buffer_rel_pos;
93}
94
95
96inline int ParsingEngine::BufferRelPos() const {
97  return buffer_rel_pos;
98}
99
100inline bool ParsingEngine::at_EOF () const {
101  return buffer_rel_pos >= rel_EOF_pos;
102}
103
104inline void ParsingEngine::Advance(int n) {
105  buffer_rel_pos += n;
106#ifndef OMIT_BITBUFFER_LIMIT_TEST_IN_ADVANCE
107  if (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
108    FinalizeBuffer_action();
109#ifdef BUFFER_PROFILING
110    end_BOM_interval(scanner_timer);
111#endif
112    AdvanceToNewBasePosn(buffer_rel_pos);
113    rel_EOF_pos = lex->AdvanceBuffer(AbsPos());
114  }
115#endif
116}
117
118#ifndef OPTIMIZE_SHORT_SCAN
119inline void ParsingEngine::ScanTo(int item) {
120  buffer_rel_pos = bitstream_scan(buf.item_stream[item], 
121                                      buffer_rel_pos);
122  while (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
123    FinalizeBuffer_action();
124#ifdef BUFFER_PROFILING
125    end_BOM_interval(scanner_timer);
126#endif
127    AdvanceToNewBasePosn(buffer_rel_pos);
128    rel_EOF_pos = lex->AdvanceBuffer(AbsPos());
129    buffer_rel_pos = bitstream_scan0(buf.item_stream[item]);
130  }
131}
132#endif
133
134
135#ifdef OPTIMIZE_SHORT_SCAN
136inline void ParsingEngine::ScanTo(int item) {
137  SIMD_type * stream = buf.item_stream[item];
138  unsigned long * bitstream_ptr = (unsigned long *) (((intptr_t) stream) + buffer_rel_pos/8);
139  unsigned long bitstream_slice = *bitstream_ptr >> buffer_rel_pos % 8;
140  if (bitstream_slice != 0) {
141    buffer_rel_pos += __builtin_ctzl(bitstream_slice);
142  }
143  else {
144    buffer_rel_pos = (buffer_rel_pos & -8) + 8*sizeof(unsigned long);
145    buffer_rel_pos += bitstream_scan0((SIMD_type *) &bitstream_ptr[1]);
146    while (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
147      buffer_rel_pos = BUFFER_BLOCKS * BLOCKSIZE;
148      FinalizeBuffer_action();
149#ifdef BUFFER_PROFILING
150      end_BOM_interval(scanner_timer);
151#endif
152      AdvanceToNewBasePosn(buffer_rel_pos);
153      rel_EOF_pos = lex->AdvanceBuffer(AbsPos());
154      buffer_rel_pos = bitstream_scan0(buf.item_stream[item]);
155    }
156  }
157}
158#endif
159
160
161
162inline bool ParsingEngine::AtChar(unsigned char c) const {
163  return *(x8dataPtr(0)) == c;
164}
165
166#include "multiliteral.h"
167/* Now the XML recognizers. */
168
169inline bool ParsingEngine::at_EndTag_Start() const {
170  return s2int16(x8dataPtr(0)) == c2int16('<', '/');
171}
172
173inline bool ParsingEngine::at_Comment_Start() const {
174  return s4int32(x8dataPtr(0)) == c4int32('<', '!', '-', '-');
175}
176
177inline bool ParsingEngine::at_DoubleHyphen() const {
178  return s2int16(x8dataPtr(0)) == c2int16('-', '-');
179}
180
181inline bool ParsingEngine::at_Comment_End() const {
182  return s3int32(x8dataPtr(0)) == c3int32('-', '-', '>');
183}
184
185inline bool ParsingEngine::at_CDATA_Start() const {
186  return s8int64(x8dataPtr(0)) == 
187         c8int64('<', '!', '[', 'C', 'D', 'A', 'T', 'A');
188}
189
190inline bool ParsingEngine::at_CDATA_End() const {
191  return s3int32(x8dataPtr(0)) == c3int32(']', ']', '>');
192}
193
194inline bool ParsingEngine::at_PI_Start() const {
195  return s2int16(x8dataPtr(0)) == c2int16('<', '?');
196}
197
198inline bool ParsingEngine::at_PI_End() const {
199  return s2int16(x8dataPtr(0)) == c2int16('?', '>');
200}
201
202inline bool ParsingEngine::at_EqualsDQuote() const {
203  return s2int16(x8dataPtr(0)) == c2int16('=', '"');
204}
205
206inline bool ParsingEngine::at_EqualsSQuote() const {
207  return s2int16(x8dataPtr(0)) == c2int16('=', '\'');
208}
209
210inline bool ParsingEngine::at_xmlns() const {
211  return s5int64(x8dataPtr(0)) == c5int64('x', 'm', 'l', 'n', 's'); 
212}
213
214inline bool ParsingEngine::at_EmptyElementDelim() const {
215  return s2int16(x8dataPtr(0)) == c2int16('/', '>');
216}
217
218
219/* The at_ElementTag_Start recognizer rules out '<!', '<?', '</'
220   combinations while returning true for '<' followed by any NameStrt
221   character. */
222inline bool ParsingEngine::at_ElementTag_Start() const {
223 
224  return (*(x8dataPtr(0)) == '<') &
225         ((*(x8dataPtr(1)) & 0xE1) != 0x21);
226}
227
228/* Parse a markup item beginning '<' */
229inline void ParsingEngine::Parse_Markup () {
230        int markup_start = AbsPos();
231        if (at_ElementTag_Start()) {
232                Parse_StartTag();
233        }
234        else if (at_EndTag_Start()) {
235                Parse_EndTag();
236        }
237        else if (at_Comment_Start()) {
238                Parse_Comment();
239        }
240        else if (at_CDATA_Start()) {
241                Parse_CDATA();
242        }
243        else if (at_PI_Start()) {
244                Parse_PI();
245        }
246        else {
247                Advance(1);
248                Error_action(markup_start, AbsPos());
249        }
250}
251
252/* Parse a comment beginning "<!--" */
253inline void ParsingEngine::Parse_Comment () {
254        int markup_start = AbsPos();
255        Advance(4); /* Skip "<!--". */
256        ScanTo(Hyphen);
257        while (!at_DoubleHyphen()) {
258                Advance(2); /* Skip hyphen-nonhyphen pair */
259                ScanTo(Hyphen); 
260        }
261        if (at_Comment_End()) {
262                Advance(3); /* Skip "-->". */
263                Comment_action(markup_start, AbsPos());
264        }
265        else {
266                Advance(2);  /* "--" */
267                Error_action(markup_start, AbsPos());
268        }
269}
270
271/* Parse an end tag beginning "</" */
272inline void ParsingEngine::Parse_EndTag () {
273        int markup_start = AbsPos();
274#ifndef OMIT_ADVANCE_PRIOR_TO_EXLUSIVE_SCAN
275        Advance(2); /* Skip "</". */
276#endif
277        ScanTo(RAngle);
278        Advance(1);
279        EndTag_action(markup_start, AbsPos());
280}
281
282/* Parse a CDATA section beginning "<![CDATA". */
283inline void ParsingEngine::Parse_CDATA () {
284        int markup_start = AbsPos();
285        Advance(8); /* Skip "<![CDATA". */
286        if (!AtChar('[')) {
287                Error_action(markup_start, AbsPos());
288        }
289        else {
290                ScanTo(RBracket);
291                while (!at_CDATA_End()) {
292                        Advance(1);
293                        ScanTo(RBracket);
294                }
295                Advance(3); /* Skip "]]>". */
296                CDATA_action(markup_start, AbsPos());
297        }
298}
299
300inline void ParsingEngine::Parse_Reference () {
301        int markup_start = AbsPos();
302        /* Advance(1);  // skip "&" */
303        ScanTo(NameFollow);  /* Name delimiter */
304        if (!AtChar(';')) {
305                Error_action(markup_start, AbsPos());
306        }
307        else {
308                Advance(1);
309                Reference_action(markup_start, AbsPos());
310        }
311}
312
313inline void ParsingEngine::Parse_PI () {
314        int markup_start = AbsPos();
315        Advance(2); /* Skip "<?". */
316        int target_start = AbsPos();
317        ScanTo(NameFollow);  /* Name delimiter */
318        PI_Target_action(target_start, AbsPos());
319        ScanTo(QMark);
320        while (!at_PI_End()) {
321                Advance(1);
322                ScanTo(QMark);
323        }
324        Advance(2); /* Skip "?>". */
325        PI_action(markup_start, AbsPos());
326}
327 
328/* Parse a start or empty element tag. */
329inline void ParsingEngine::Parse_StartTag () {
330        int markup_start = AbsPos();
331        int att_name_start;
332        int att_val_start;
333        int att_name_end, att_val_end;
334        lexical_item Quote_stream;
335        ScanTo(NameFollow);  /* Name delimiter: WS, "/" or ">" */
336        ElementName_action(markup_start+1, AbsPos());
337        /* The following test optimizes the most common case of a
338        start tag with no attributes.  */
339        if (AtChar('>')) {
340                Advance(1);
341                StartTag_action(markup_start, AbsPos());
342        }
343        else {
344                ScanTo(NonWS);
345                if (AtChar('>')) {
346                        Advance(1);
347                        StartTag_action(markup_start, AbsPos());
348                }
349                else if (at_EmptyElementDelim()) {
350                        Advance(2);
351                        EmptyElement_action(markup_start, AbsPos());
352                }
353                else do {
354                        /* Must be an attribute-value pair or error. */
355                        att_name_start = AbsPos();
356                        ScanTo(NameFollow);
357                        att_name_end = AbsPos();
358                        /* The following optimized tests handle the frequently occurring
359                        case that there are no blanks on either side of the equals sign.
360                        In many cases, the very first test handles 100% of actual
361                        attribute-value pairs encountered. */
362                        if (at_EqualsDQuote()) {
363                                Advance(2); 
364                                att_val_start = AbsPos();
365                                Quote_stream = DQuote;
366                        }
367                        else if (at_EqualsSQuote()) {
368                                Advance(2); 
369                                att_val_start = AbsPos();
370                                Quote_stream = SQuote;
371                        }
372                        else {
373                                ScanTo(NonWS);
374                                if (!AtChar('=')) {
375                                        Error_action(markup_start, AbsPos()); 
376                                        break;
377                                }
378                                ScanTo(NonWS);
379                                att_val_start = AbsPos()+1;
380                                if (AtChar('"')) {
381                                        Advance(1); 
382                                        Quote_stream = DQuote;
383                                }
384                                else if (AtChar('\'')) {
385                                        Advance(1); 
386                                        Quote_stream = SQuote;
387                                }
388                                else {
389                                        Error_action(markup_start, AbsPos()); 
390                                        break;
391                                }
392                        }
393                        ScanTo(Quote_stream);
394                        while (AtChar('&')) {
395                                Parse_Reference();
396                                ScanTo(Quote_stream);
397                        }
398                        if (AtChar('<')) {
399                                Error_action(markup_start, AbsPos()); 
400                                break;
401                        }
402                        att_val_end = AbsPos();
403                        Advance(1); 
404                        if (at_xmlns()) {
405                                Namespace_action(att_name_start, att_name_end,
406                                                 att_val_start, att_val_end);
407                        }
408                        else {
409                                AttributeValue_action(att_name_start, att_name_end,
410                                                      att_val_start, att_val_end);
411                        }
412                        /* Now check for end or repeat. Avoid whitespace scan if possible.*/
413                        if (AtChar('>')) {
414                                Advance(1);
415                                StartTag_action(markup_start, AbsPos());
416                                break;
417                        }
418                        else if (at_EmptyElementDelim()) {
419                                Advance(2);
420                                EmptyElement_action(markup_start, AbsPos());
421                                break;
422                        }
423                        ScanTo(NonWS);
424                        if (AtChar('>')) {
425                                Advance(1);
426                                StartTag_action(markup_start, AbsPos());
427                                break;
428                        }
429                        else if (at_EmptyElementDelim()) {
430                                Advance(2);
431                                EmptyElement_action(markup_start, AbsPos());
432                                break;
433                        }
434                        else if (AbsPos() == att_val_end + 1) { 
435                                /* No WS following att value */
436                                Error_action(markup_start, AbsPos());
437                                break;
438                        }
439                } while (1);
440        }
441}
442
443
444inline void ParsingEngine::ParseContent () {
445
446        int text_start = AbsPos();
447        do {
448                ScanTo(MarkupStart); /* '<', '&', or ']' for ']]>' test */
449/*              if (AtChar('<')) {
450                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
451                        Parse_Markup();
452                }*/
453                int markup_start = AbsPos();
454                if (at_ElementTag_Start()) {
455                        Parse_StartTag();
456                }
457                else if (at_EndTag_Start()) {
458                        Parse_EndTag();
459                }
460                else if (at_Comment_Start()) {
461                        Parse_Comment();
462                }
463                else if (AtChar('&')) {
464                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
465                        Parse_Reference();
466                }
467                else if (at_CDATA_Start()) {
468                        Parse_CDATA();
469                }
470                else if (at_PI_Start()) {
471                        Parse_PI();
472                }
473                else if (at_CDATA_End()) {
474                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
475                        Advance(3);
476                        Error_action(AbsPos()-3, AbsPos());
477                }
478                else if (at_EOF()) {
479                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
480                        break;
481                }
482                else {
483                        Advance(1);
484                        continue;
485                }
486                text_start = AbsPos();
487        } while (1);
488#ifdef BUFFER_PROFILING
489        printf("Bit stream computation.\n");
490        dump_BOM_table(bitstream_timer);
491        printf("Lexical stream transposition.\n");
492        dump_BOM_table(lextranspose_timer);
493        printf("Scanning.\n");
494        dump_BOM_table(scanner_timer);
495#endif
496}
Note: See TracBrowser for help on using the repository browser.