source: trunk/src/engine.c @ 37

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

Charset Architecture: Parser Factory

File size: 12.6 KB
Line 
1/*  engine.c - Parabix XML parsing engine.
2    Copyright (c) 2007, 2008, 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 "bytelex.h"
12#include "bitlex.h"
13
14#include <assert.h>
15#include <stdlib.h>
16#include <errno.h>
17#include <string.h>
18
19
20Parser_Interface * Parser_Interface::ParserFactory(char * filename) {
21        XML_Buffer_Interface * b = XML_Buffer_Interface::BufferFactory(filename);
22        b->DoByteplex();
23        b->PreparePseudoASCII_Stream();
24#ifdef DEBUG
25        printf("PseudoASCII stream complete.\n");
26#endif
27        b->ReadXMLInfo();
28#ifdef DEBUG
29        printf("XML Info read; content start position = %i.\n", b->ContentStartUnit());
30#endif
31        if (b->code_unit_base == ASCII) {
32                return new ParsingEngine<ASCII>(b);
33        }
34        else /* if (b->code_unit_base == EBCDIC) */ {
35                return new ParsingEngine<EBCDIC>(b);
36        }
37}
38
39bool Parser_Interface::has_ByteOrderMark() {
40        return xml_buf->BOM_units > 0;
41}
42
43XML_version Parser_Interface::get_version() {
44        return xml_buf->version;
45}
46
47XML_standalone Parser_Interface::standalone_status() {
48        return xml_buf->standalone;
49}
50
51bool Parser_Interface::has_EncodingDecl() {
52        return xml_buf->has_encoding_decl;
53}
54
55int Parser_Interface::get_Encoding_pos() {
56        return xml_buf->encoding_start_pos;
57}
58
59int Parser_Interface::get_Encoding_lgth() {
60        return xml_buf->encoding_lgth;
61}
62
63
64
65
66template <CodeUnit_Base C>
67ParsingEngine<C>::ParsingEngine(XML_Buffer_Interface * b) : Parser_Interface () {
68#ifdef BUFFER_PROFILING
69        bitstream_timer = init_BOM_timer(BUFFER_BLOCKS * BLOCKSIZE);
70        lextranspose_timer = init_BOM_timer(BUFFER_BLOCKS * BLOCKSIZE);
71        scanner_timer = init_BOM_timer(BUFFER_BLOCKS * BLOCKSIZE);
72#endif
73/*      buf = new LexicalStreamSet;*/
74        posix_memalign((void **) &buf, sizeof(BitBlock), sizeof(LexicalStreamSet));
75#ifdef DEBUG
76        printf("parser->buf addr = %x\n", (int) buf);
77#endif
78
79  /* Install sentinels for every lexical item stream*/
80#ifndef OPTIMIZE_SHORT_SCAN
81        BitBlock sentinel_value = simd_const_1(1);
82#endif
83#ifdef OPTIMIZE_SHORT_SCAN
84        BitBlock sentinel_value = sisd_sfli(simd_const_1(1), 8*sizeof(unsigned long));
85#endif
86        for (int j = MarkupStart; j < LexicalItemCount; j++) {
87                buf->item_stream[j][BUFFER_BLOCKS] = sentinel_value;
88        }
89#ifdef DEBUG
90        printf("Bitspace sentinels established.\n");
91#endif
92        xml_buf = b;
93        buffer_base_pos = 0;
94        buffer_rel_pos = b->ContentStartUnit();
95        lexer = Lexer<C>::LexerFactory(b, buf);
96#ifdef DEBUG
97        printf("Lexer created.\n");
98#endif
99        lexer->AdvanceBuffer(buffer_base_pos, buffer_rel_pos, buffer_limit_pos);
100        x8data = &xml_buf->x8data[buffer_base_pos/PACKSIZE];
101#ifdef DEBUG
102        printf("Initial lexical buffer formed.\n");
103#endif
104}
105
106
107
108template <CodeUnit_Base C>
109inline unsigned char * ParsingEngine<C>::cur() const {
110  return &((unsigned char *) x8data)[buffer_rel_pos];
111}
112
113template <CodeUnit_Base C>
114inline int ParsingEngine<C>::AbsPos() const {
115  return buffer_base_pos + buffer_rel_pos;
116}
117
118
119template <CodeUnit_Base C>
120inline int ParsingEngine<C>::BufferRelPos() const {
121  return buffer_rel_pos;
122}
123
124
125template <CodeUnit_Base C>
126inline bool ParsingEngine<C>::at_EOF() const {
127  return (buffer_rel_pos >= buffer_limit_pos) && 
128         (buffer_limit_pos < BUFFER_BLOCKS * BLOCKSIZE + LOOKAHEAD_POSITIONS);
129}
130
131template <CodeUnit_Base C>
132inline void ParsingEngine<C>::Advance(int n) {
133  buffer_rel_pos += n;
134#ifndef OMIT_BITBUFFER_LIMIT_TEST_IN_ADVANCE
135  if (buffer_rel_pos >= buffer_limit_pos) {
136    FinalizeBuffer_action();
137#ifdef BUFFER_PROFILING
138    end_BOM_interval(scanner_timer);
139#endif
140    lexer->AdvanceBuffer(buffer_base_pos, buffer_rel_pos, buffer_limit_pos);
141    x8data = &xml_buf->x8data[buffer_base_pos/PACKSIZE];
142  }
143#endif
144}
145
146
147#ifndef OPTIMIZE_SHORT_SCAN
148template <CodeUnit_Base C>
149inline void ParsingEngine<C>::ScanTo(int item) {
150  buffer_rel_pos = bitstream_scan(buf->item_stream[item], 
151                                      buffer_rel_pos);
152  while (buffer_rel_pos >= BUFFER_SIZE) {
153    FinalizeBuffer_action();
154#ifdef BUFFER_PROFILING
155    end_BOM_interval(scanner_timer);
156#endif
157    lexer->AdvanceBuffer(buffer_base_pos, buffer_rel_pos, buffer_limit_pos);
158#ifdef DEBUG
159printf("lexer->AdvanceBuffer complete; base_pos = %i, rel_pos = %i, limit_pos = %i\n",
160       buffer_base_pos, buffer_rel_pos, buffer_limit_pos);
161#endif
162    x8data = &xml_buf->x8data[buffer_base_pos/PACKSIZE];
163    buffer_rel_pos = bitstream_scan(buf->item_stream[item], buffer_rel_pos);
164  }
165}
166#endif
167
168#ifdef OPTIMIZE_SHORT_SCAN
169template <CodeUnit_Base C>
170inline void ParsingEngine<C>::ScanTo(int item) {
171  SIMD_type * stream = buf->item_stream[item];
172  unsigned long * bitstream_ptr = (unsigned long *) (((intptr_t) stream) + buffer_rel_pos/8);
173  unsigned long bitstream_slice = *bitstream_ptr >> buffer_rel_pos % 8;
174  if (bitstream_slice != 0) {
175    buffer_rel_pos += __builtin_ctzl(bitstream_slice);
176  }
177  else {
178    buffer_rel_pos = (buffer_rel_pos & -8) + 8*sizeof(unsigned long);
179    buffer_rel_pos += bitstream_scan0((SIMD_type *) &bitstream_ptr[1]);
180    while (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
181      buffer_rel_pos = BUFFER_BLOCKS * BLOCKSIZE;
182      FinalizeBuffer_action();
183#ifdef BUFFER_PROFILING
184      end_BOM_interval(scanner_timer);
185#endif
186      lexer->AdvanceBuffer(buffer_base_pos, buffer_rel_pos, buffer_limit_pos);
187        x8data = &xml_buf->x8data[buffer_base_pos/PACKSIZE];
188      buffer_rel_pos = bitstream_scan(buf->item_stream[item], buffer_rel_pos);
189    }
190  }
191}
192#endif
193
194
195/* Parse a markup item beginning '<' */
196template <CodeUnit_Base C>
197inline void ParsingEngine<C>::Parse_Markup() {
198        int markup_start = AbsPos();
199        if (at_ElementTag_Start<C>(cur())) {
200                Parse_StartTag();
201        }
202        else if (at_EndTag_Start<C>(cur())) {
203                Parse_EndTag();
204        }
205        else if (at_Comment_Start<C>(cur())) {
206                Parse_Comment();
207        }
208        else if (at_CDATA_Start<C>(cur())) {
209                Parse_CDATA();
210        }
211        else if (at_PI_Start<C>(cur())) {
212                Parse_PI();
213        }
214        else {
215                Advance(1);
216                Error_action(markup_start, AbsPos());
217        }
218}
219
220/* Parse a comment beginning "<!--" */
221template <CodeUnit_Base C>
222inline void ParsingEngine<C>::Parse_Comment() {
223        int markup_start = AbsPos();
224        Advance(4); /* Skip "<!--". */
225        ScanTo(Hyphen);
226        while (!at_DoubleHyphen<C>(cur())) {
227                Advance(2); /* Skip hyphen-nonhyphen pair */
228                ScanTo(Hyphen); 
229        }
230        if (at_Comment_End<C>(cur())) {
231                Advance(3); /* Skip "-->". */
232                Comment_action(markup_start, AbsPos());
233        }
234        else {
235                Advance(2);  /* "--" */
236                Error_action(markup_start, AbsPos());
237        }
238}
239
240/* Parse an end tag beginning "</" */
241template <CodeUnit_Base C>
242inline void ParsingEngine<C>::Parse_EndTag() {
243        int markup_start = AbsPos();
244#ifndef OMIT_ADVANCE_PRIOR_TO_EXCLUSIVE_SCAN
245        Advance(2); /* Skip "</". */
246#endif
247        ScanTo(NameFollow);
248        if (AtChar<C,'>'>(cur())) {
249                Advance(1);
250                EndTag_action(markup_start, AbsPos());
251        }
252        else {
253                ScanTo(NonWS);
254                if (AtChar<C,'>'>(cur())) {
255                        Advance(1);
256                        EndTag_action(markup_start, AbsPos());
257                }
258                else Error_action(markup_start, AbsPos());
259        }
260}
261
262/* Parse a CDATA section beginning "<![CDATA". */
263template <CodeUnit_Base C>
264inline void ParsingEngine<C>::Parse_CDATA() {
265        int markup_start = AbsPos();
266        Advance(8); /* Skip "<![CDATA". */
267        if (!AtChar<C,'['>(cur())) {
268                Error_action(markup_start, AbsPos());
269        }
270        else {
271                ScanTo(CD_End_check);
272                while (!at_CDATA_End<C>(cur())) {
273                        Advance(1);
274                        ScanTo(CD_End_check);
275                }
276                Advance(3); /* Skip "]]>". */
277                CDATA_action(markup_start, AbsPos());
278        }
279}
280
281template <CodeUnit_Base C>
282inline void ParsingEngine<C>::Parse_Reference() {
283        int markup_start = AbsPos();
284        /* Advance(1);  // skip "&" */
285        ScanTo(NameFollow);  /* Name delimiter */
286        if (!AtChar<C,';'>(cur())) {
287                Error_action(markup_start, AbsPos());
288        }
289        else {
290                Advance(1);
291                Reference_action(markup_start, AbsPos());
292        }
293}
294
295template <CodeUnit_Base C>
296inline void ParsingEngine<C>::Parse_PI (){
297        int markup_start = AbsPos();
298        Advance(2); /* Skip "<?". */
299        int target_start = AbsPos();
300        // Check for illegal [Xx][Mm][Ll] target.
301        if (at_XxMmLll_WS<C>(cur())) {
302                Advance(4);
303                Error_action(markup_start, AbsPos());
304                return;
305        } 
306        ScanTo(NameFollow);  /* Name delimiter */
307        PI_Target_action(target_start, AbsPos());
308        ScanTo(QMark);
309        while (!at_PI_End<C>(cur())) {
310                Advance(1);
311                ScanTo(QMark);
312        }
313        Advance(2); /* Skip "?>". */
314        PI_action(markup_start, AbsPos());
315}
316 
317/* Parse a start or empty element tag. */
318template <CodeUnit_Base C>
319inline void ParsingEngine<C>::Parse_StartTag (){
320        int markup_start = AbsPos();
321        int att_name_start;
322        int att_val_start;
323        int att_name_end, att_val_end;
324        unsigned char quoteCh;
325        ScanTo(NameFollow);  /* Name delimiter: WS, "/" or ">" */
326        ElementName_action(markup_start+1, AbsPos());
327        /* The following test optimizes the most common case of a
328        start tag with no attributes.  */
329        if (AtChar<C,'>'>(cur())) {
330                Advance(1);
331                StartTag_action(markup_start, AbsPos());
332        }
333        else {
334                ScanTo(NonWS);
335                if (AtChar<C,'>'>(cur())) {
336                        Advance(1);
337                        StartTag_action(markup_start, AbsPos());
338                }
339                else if (at_EmptyElementDelim<C>(cur())) {
340                        Advance(2);
341                        EmptyElement_action(markup_start, AbsPos());
342                }
343                else do {
344                        /* Must be an attribute-value pair or error. */
345                        att_name_start = AbsPos();
346                        ScanTo(NameFollow);
347                        att_name_end = AbsPos();
348                        /* The following optimized tests handle the frequently occurring
349                        case that there are no blanks on either side of the equals sign.
350                        In many cases, the very first test handles 100% of actual
351                        attribute-value pairs encountered. */
352                        if (at_EqualsQuote<C>(cur())) {
353                                quoteCh = cur()[1];
354                                Advance(2); 
355                        }
356                        else {
357                                ScanTo(NonWS);
358                                if (!AtChar<C,'='>(cur())) {
359                                        Error_action(markup_start, AbsPos()); 
360                                        break;
361                                }
362                                ScanTo(NonWS);
363                                quoteCh = cur()[0];
364                                if (!AtQuote<C>(cur())) {
365                                        Error_action(markup_start, AbsPos()); 
366                                        break;
367                                }
368                                Advance(1);
369                        }
370                        att_val_start = AbsPos();
371                        ScanTo(Quote);
372                        while (cur()[0] != quoteCh) {
373                                if (AtChar<C,'&'>(cur())) {
374                                        Parse_Reference();
375                                        ScanTo(Quote);
376                                }
377                                else if (AtQuote<C>(cur())) {
378                                        Advance(1);
379                                }
380                                else /* if (AtChar<C,'<'>(cur())) */{
381                                        Error_action(markup_start, AbsPos()); 
382                                        break;
383                                }
384                        }
385                        att_val_end = AbsPos();
386                        Advance(1); 
387                        if (at_xmlns<C>(cur()+att_name_start-AbsPos())) {
388                                Namespace_action(att_name_start, att_name_end,
389                                                 att_val_start, att_val_end);
390                        }
391                        else {
392                                AttributeValue_action(att_name_start, att_name_end,
393                                                      att_val_start, att_val_end);
394                        }
395                        /* Now check for end or repeat. Avoid whitespace scan if possible.*/
396                        if (AtChar<C,'>'>(cur())) {
397                                Advance(1);
398                                StartTag_action(markup_start, AbsPos());
399                                break;
400                        }
401                        else if (at_EmptyElementDelim<C>(cur())) {
402                                Advance(2);
403                                EmptyElement_action(markup_start, AbsPos());
404                                break;
405                        }
406                        ScanTo(NonWS);
407                        if (AtChar<C,'>'>(cur())) {
408                                Advance(1);
409                                StartTag_action(markup_start, AbsPos());
410                                break;
411                        }
412                        else if (at_EmptyElementDelim<C>(cur())) {
413                                Advance(2);
414                                EmptyElement_action(markup_start, AbsPos());
415                                break;
416                        }
417                        else if (AbsPos() == att_val_end + 1) { 
418                                /* No WS following att value */
419                                Error_action(markup_start, AbsPos());
420                                break;
421                        }
422                } while (1);
423        }
424}
425
426
427template <CodeUnit_Base C>
428inline void ParsingEngine<C>::ParseContent() {
429
430        int text_start = AbsPos();
431        do {
432                ScanTo(MarkupStart); /* '<', '&', or ']' for ']]>' test */
433/*              if (AtChar<C,'<'>(cur())) {
434                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
435                        Parse_Markup<C>();
436                }*/
437                int markup_start = AbsPos();
438                if (at_ElementTag_Start<C>(cur())) {
439                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
440                        Parse_StartTag();
441                }
442                else if (at_EndTag_Start<C>(cur())) {
443                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
444                        Parse_EndTag();
445                }
446                else if (at_Comment_Start<C>(cur())) {
447                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
448                        Parse_Comment();
449                }
450                else if (AtChar<C,'&'>(cur())) {
451                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
452                        Parse_Reference();
453                }
454                else if (at_CDATA_Start<C>(cur())) {
455                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
456                        Parse_CDATA();
457                }
458                else if (at_PI_Start<C>(cur())) {
459                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
460                        Parse_PI();
461                }
462                else if (at_CDATA_End<C>(cur())) {
463                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
464                        Advance(3);
465                        Error_action(AbsPos()-3, AbsPos());
466                }
467                else if (at_EOF()) {
468                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
469                        break;
470                }
471                else {
472                        Advance(1);
473                        continue;
474                }
475                text_start = AbsPos();
476        } while (1);
477#ifdef BUFFER_PROFILING
478        printf("Bit stream computation.\n");
479        dump_BOM_table(bitstream_timer);
480        printf("Lexical stream transposition.\n");
481        dump_BOM_table(lextranspose_timer);
482        printf("Scanning.\n");
483        dump_BOM_table(scanner_timer);
484#endif
485}
486
Note: See TracBrowser for help on using the repository browser.