source: trunk/src/engine.c @ 4

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

Initial import of parabix-0.36

File size: 11.4 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 = LAngle; 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    default:
70      printf("Error: Charset family %i detected, but not supported.\n", family);
71      exit(-1);
72  }
73  rel_EOF_pos = lex-> AdvanceBuffer(0);
74}
75
76
77inline void ParsingEngine::AdvanceToNewBasePosn(int advance_amt) {
78  buffer_base_pos += advance_amt;
79  buffer_rel_pos = 0;
80}
81
82inline unsigned char * ParsingEngine::x8dataPtr(int offset) const {
83  return &((unsigned char *) buf.x8data)[buffer_rel_pos+offset];
84}
85
86
87inline int ParsingEngine::AbsPos() const {
88  return buffer_base_pos + buffer_rel_pos;
89}
90
91
92inline int ParsingEngine::BufferRelPos() const {
93  return buffer_rel_pos;
94}
95
96inline bool ParsingEngine::at_EOF () const {
97  return buffer_rel_pos >= rel_EOF_pos;
98}
99
100inline void ParsingEngine::Advance(int n) {
101  buffer_rel_pos += n;
102#ifndef OMIT_BITBUFFER_LIMIT_TEST_IN_ADVANCE
103  if (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
104    FinalizeBuffer_action();
105#ifdef BUFFER_PROFILING
106    end_BOM_interval(scanner_timer);
107#endif
108    AdvanceToNewBasePosn(buffer_rel_pos);
109    rel_EOF_pos = lex->AdvanceBuffer(AbsPos());
110  }
111#endif
112}
113
114#ifndef OPTIMIZE_SHORT_SCAN
115inline void ParsingEngine::ScanTo(int item) {
116  buffer_rel_pos = bitstream_scan(buf.item_stream[item], 
117                                      buffer_rel_pos);
118  while (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
119    FinalizeBuffer_action();
120#ifdef BUFFER_PROFILING
121    end_BOM_interval(scanner_timer);
122#endif
123    AdvanceToNewBasePosn(buffer_rel_pos);
124    rel_EOF_pos = lex->AdvanceBuffer(AbsPos());
125    buffer_rel_pos = bitstream_scan0(buf.item_stream[item]);
126  }
127}
128#endif
129
130
131#ifdef OPTIMIZE_SHORT_SCAN
132inline void ParsingEngine::ScanTo(int item) {
133  SIMD_type * stream = buf.item_stream[item];
134  unsigned long * bitstream_ptr = (unsigned long *) (((intptr_t) stream) + buffer_rel_pos/8);
135  unsigned long bitstream_slice = *bitstream_ptr >> buffer_rel_pos % 8;
136  if (bitstream_slice != 0) {
137    buffer_rel_pos += __builtin_ctzl(bitstream_slice);
138  }
139  else {
140    buffer_rel_pos = (buffer_rel_pos & -8) + 8*sizeof(unsigned long);
141    buffer_rel_pos += bitstream_scan0((SIMD_type *) &bitstream_ptr[1]);
142    while (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
143      buffer_rel_pos = BUFFER_BLOCKS * BLOCKSIZE;
144      FinalizeBuffer_action();
145#ifdef BUFFER_PROFILING
146      end_BOM_interval(scanner_timer);
147#endif
148      AdvanceToNewBasePosn(buffer_rel_pos);
149      rel_EOF_pos = lex->AdvanceBuffer(AbsPos());
150      buffer_rel_pos = bitstream_scan0(buf.item_stream[item]);
151    }
152  }
153}
154#endif
155
156
157
158inline bool ParsingEngine::AtChar(unsigned char c) const {
159  return *(x8dataPtr(0)) == c;
160}
161
162#include "multiliteral.h"
163/* Now the XML recognizers. */
164
165inline bool ParsingEngine::at_EndTag_Start() const {
166  return s2int16(x8dataPtr(0)) == c2int16('<', '/');
167}
168
169inline bool ParsingEngine::at_Comment_Start() const {
170  return s4int32(x8dataPtr(0)) == c4int32('<', '!', '-', '-');
171}
172
173inline bool ParsingEngine::at_DoubleHyphen() const {
174  return s2int16(x8dataPtr(0)) == c2int16('-', '-');
175}
176
177inline bool ParsingEngine::at_Comment_End() const {
178  return s3int32(x8dataPtr(0)) == c3int32('-', '-', '>');
179}
180
181inline bool ParsingEngine::at_CDATA_Start() const {
182  return s8int64(x8dataPtr(0)) == 
183         c8int64('<', '!', '[', 'C', 'D', 'A', 'T', 'A');
184}
185
186inline bool ParsingEngine::at_CDATA_End() const {
187  return s3int32(x8dataPtr(0)) == c3int32(']', ']', '>');
188}
189
190inline bool ParsingEngine::at_PI_Start() const {
191  return s2int16(x8dataPtr(0)) == c2int16('<', '?');
192}
193
194inline bool ParsingEngine::at_PI_End() const {
195  return s2int16(x8dataPtr(0)) == c2int16('?', '>');
196}
197
198inline bool ParsingEngine::at_EqualsDQuote() const {
199  return s2int16(x8dataPtr(0)) == c2int16('=', '"');
200}
201
202inline bool ParsingEngine::at_EqualsSQuote() const {
203  return s2int16(x8dataPtr(0)) == c2int16('=', '\'');
204}
205
206inline bool ParsingEngine::at_xmlns() const {
207  return s5int64(x8dataPtr(0)) == c5int64('x', 'm', 'l', 'n', 's'); 
208}
209
210inline bool ParsingEngine::at_EmptyElementDelim() const {
211  return s2int16(x8dataPtr(0)) == c2int16('/', '>');
212}
213
214
215/* The at_ElementTag_Start recognizer rules out '<!', '<?', '</'
216   combinations while returning true for '<' followed by any NameStrt
217   character. */
218inline bool ParsingEngine::at_ElementTag_Start() const {
219  assert(*(x8dataPtr(0)) == '<');
220  return (*(x8dataPtr(1)) & 0xE1) != 0x21;
221}
222
223
224
225
226inline void ParsingEngine::Parse_Text () {
227        int text_start;
228        int text_lgth;
229        if (!AtChar('<')) {
230                text_start = AbsPos();
231/*
232                ScanTo(NonWS);
233                non_WS_start = AbsPos(); */
234                ScanTo(LAngle);
235                /*if (text_lgth > 0) {*/
236                Text_action(text_start, AbsPos());
237        }
238}
239
240/* Parse a markup item beginning '<' */
241inline void ParsingEngine::Parse_Markup () {
242        int markup_start = AbsPos();
243        if (at_ElementTag_Start()) {
244                Parse_StartTag();
245        }
246        else if (at_EndTag_Start()) {
247                Parse_EndTag();
248        }
249        else if (at_Comment_Start()) {
250                Parse_Comment();
251        }
252        else if (at_CDATA_Start()) {
253                Parse_CDATA();
254        }
255        else if (at_PI_Start()) {
256                Parse_PI();
257        }
258        else {
259                Advance(1);
260                Error_action(markup_start, AbsPos());
261        }
262}
263
264/* Parse a comment beginning "<!--" */
265inline void ParsingEngine::Parse_Comment () {
266        int markup_start = AbsPos();
267        Advance(4); /* Skip "<!--". */
268        ScanTo(Hyphen);
269        while (!at_DoubleHyphen()) {
270                Advance(2); /* Skip hyphen-nonhyphen pair */
271                ScanTo(Hyphen); 
272        }
273        if (at_Comment_End()) {
274                Advance(3); /* Skip "-->". */
275                Comment_action(markup_start, AbsPos());
276        }
277        else {
278                Advance(2);  /* "--" */
279                Error_action(markup_start, AbsPos());
280        }
281}
282
283/* Parse an end tag beginning "</" */
284inline void ParsingEngine::Parse_EndTag () {
285        int markup_start = AbsPos();
286#ifndef OMIT_ADVANCE_PRIOR_TO_EXLUSIVE_SCAN
287        Advance(2); /* Skip "</". */
288#endif
289        ScanTo(RAngle);
290        Advance(1);
291        EndTag_action(markup_start, AbsPos());
292}
293
294/* Parse a CDATA section beginning "<![CDATA". */
295inline void ParsingEngine::Parse_CDATA () {
296        int markup_start = AbsPos();
297        Advance(8); /* Skip "<![CDATA". */
298        if (!AtChar('[')) {
299                Error_action(markup_start, AbsPos());
300        }
301        else {
302                ScanTo(RBracket);
303                while (!at_CDATA_End()) {
304                        Advance(1);
305                        ScanTo(RBracket);
306                }
307                Advance(3); /* Skip "]]>". */
308                CDATA_action(markup_start, AbsPos());
309        }
310}
311
312inline void ParsingEngine::Parse_PI () {
313        int markup_start = AbsPos();
314        Advance(2); /* Skip "<?". */
315        int target_start = AbsPos();
316        ScanTo(NameFollow);  /* Name delimiter */
317        PI_Target_action(target_start, AbsPos());
318        ScanTo(QMark);
319        while (!at_PI_End()) {
320                Advance(1);
321                ScanTo(QMark);
322        }
323        Advance(2); /* Skip "?>". */
324        PI_action(markup_start, AbsPos());
325}
326 
327/* Parse a start or empty element tag. */
328inline void ParsingEngine::Parse_StartTag () {
329        int markup_start = AbsPos();
330        int att_name_start;
331        int att_val_start;
332        int att_name_end, att_val_end;
333        ScanTo(NameFollow);  /* Name delimiter: WS, "/" or ">" */
334        ElementName_action(markup_start+1, AbsPos());
335        /* The following test optimizes the most common case of a
336        start tag with no attributes.  */
337        if (AtChar('>')) {
338                Advance(1);
339                StartTag_action(markup_start, AbsPos());
340        }
341        else {
342                ScanTo(NonWS);
343                if (AtChar('>')) {
344                        Advance(1);
345                        StartTag_action(markup_start, AbsPos());
346                }
347                else if (at_EmptyElementDelim()) {
348                        Advance(2);
349                        EmptyElement_action(markup_start, AbsPos());
350                }
351                else do {
352                        /* Must be an attribute-value pair or error. */
353                        att_name_start = AbsPos();
354                        ScanTo(NameFollow);
355                        att_name_end = AbsPos();
356                        /* The following optimized tests handle the frequently occurring
357                        case that there are no blanks on either side of the equals sign.
358                        In many cases, the very first test handles 100% of actual
359                        attribute-value pairs encountered. */
360                        if (at_EqualsDQuote()) {
361                                Advance(2); 
362                                att_val_start = AbsPos();
363                                ScanTo(DQuote);
364                        }
365                        else if (at_EqualsSQuote()) {
366                                Advance(2); 
367                                att_val_start = AbsPos();
368                                ScanTo(SQuote);
369                        }
370                        else {
371                                ScanTo(NonWS);
372                                if (!AtChar('=')) {
373                                        Error_action(markup_start, AbsPos()); 
374                                        break;
375                                }
376                                ScanTo(NonWS);
377                                att_val_start = AbsPos()+1;
378                                if (AtChar('"')) {
379                                        Advance(1); 
380                                        ScanTo(DQuote);
381                                }
382                                else if (AtChar('\'')) {
383                                        Advance(1); 
384                                        ScanTo(SQuote);
385                                }
386                                else {
387                                        Error_action(markup_start, AbsPos()); 
388                                        break;
389                                }
390                        }
391                        /* ScanTo(DQuote) or ScanTo(SQuote) complete. */
392                        att_val_end = AbsPos();
393                        Advance(1); 
394                        if (at_xmlns()) {
395                                Namespace_action(att_name_start, att_name_end,
396                                                 att_val_start, att_val_end);
397                        }
398                        else {
399                                AttributeValue_action(att_name_start, att_name_end,
400                                                      att_val_start, att_val_end);
401                        }
402                        /* Now check for end or repeat. Avoid whitespace scan if possible.*/
403                        if (AtChar('>')) {
404                                Advance(1);
405                                StartTag_action(markup_start, AbsPos());
406                                break;
407                        }
408                        else if (at_EmptyElementDelim()) {
409                                Advance(2);
410                                EmptyElement_action(markup_start, AbsPos());
411                                break;
412                        }
413                        ScanTo(NonWS);
414                        if (AtChar('>')) {
415                                Advance(1);
416                                StartTag_action(markup_start, AbsPos());
417                                break;
418                        }
419                        else if (at_EmptyElementDelim()) {
420                                Advance(2);
421                                EmptyElement_action(markup_start, AbsPos());
422                                break;
423                        }
424                        else if (AbsPos() == att_val_end + 1) { 
425                                /* No WS following att value */
426                                Error_action(markup_start, AbsPos());
427                                break;
428                        }
429                } while (1);
430        }
431}
432
433
434inline void ParsingEngine::ParseContent () {
435
436       
437        while (!at_EOF()) {
438                Parse_Text();
439                if (!at_EOF()) {
440                        Parse_Markup();
441                }
442        }
443        if (BufferRelPos() > rel_EOF_pos) {
444                printf("Incomplete markup item at end of file.\n");
445        }
446#ifdef BUFFER_PROFILING
447        printf("Bit stream computation.\n");
448        dump_BOM_table(bitstream_timer);
449        printf("Lexical stream transposition.\n");
450        dump_BOM_table(lextranspose_timer);
451        printf("Scanning.\n");
452        dump_BOM_table(scanner_timer);
453#endif
454}
Note: See TracBrowser for help on using the repository browser.