source: trunk/src/engine.c @ 73

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

Refactored Parsing Engine

File size: 12.7 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 "engine.h"
9#include "byteplex.h"
10#include "xmldecl.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       
22        int chars_read;
23        unsigned char signature[4];
24        FILE * infile;
25        infile = fopen(filename, "rb");
26        if (!infile) {
27                fprintf(stderr, "Error: cannot open %s for input.\n", filename);
28                exit(-1);
29        }
30        fread(signature,1,4,infile);
31        Model_Info * m = new Model_Info;
32        m->AnalyzeSignature(signature);
33        Byteplex * b = Byteplex::ByteplexFactory(m, infile);
34        b->InitializeBuffer(signature,4);
35
36        if (m->code_unit_base == ASCII) {
37                return new ParsingEngine<ASCII>(m, b);
38        }
39        else /* if (m->code_unit_base == EBCDIC) */ {
40                return new ParsingEngine<EBCDIC>(m, b);
41        }       
42}
43
44Parser_Interface::~Parser_Interface() {
45}
46
47
48bool Parser_Interface::has_ByteOrderMark() {
49        return model_info->BOM_units > 0;
50}
51
52XML_version Parser_Interface::get_version() {
53        return model_info->version;
54}
55
56XML_standalone Parser_Interface::standalone_status() {
57        return model_info->standalone;
58}
59
60bool Parser_Interface::has_EncodingDecl() {
61        return model_info->has_encoding_decl;
62}
63
64unsigned char * Parser_Interface::get_Encoding() {
65        return model_info->encoding;
66}
67
68unsigned char * Parser_Interface::GetCodeUnitPtr(int pos) {
69        int rel_pos = pos - buffer_base_pos;
70        return &((unsigned char *) (byteplex->src_buffer))[rel_pos * (int) model_info->code_unit_size];
71}
72
73
74
75
76template <CodeUnit_Base C>
77ParsingEngine<C>::ParsingEngine(Model_Info * m, Byteplex * b) : Parser_Interface () {
78
79        model_info = m;
80        byteplex = b;
81
82        byteplex->DoByteplex();
83        byteplex->PreparePseudoASCII_Stream();
84        decl_parser = new XML_Decl_Parser<C>(byteplex);
85        int content_start = decl_parser->ReadXMLInfo(model_info);
86
87        bitplex = new Bitplex;
88        buf = (LexicalStreamSet *) simd_new(sizeof(LexicalStreamSet)/PACKSIZE);
89
90  /* Install sentinels for every lexical item stream*/
91#ifndef OPTIMIZE_SHORT_SCAN
92        BitBlock sentinel_value = simd_const_1(1);
93#endif
94#ifdef OPTIMIZE_SHORT_SCAN
95        BitBlock sentinel_value = sisd_sfli(simd_const_1(1), 8*sizeof(unsigned long));
96#endif
97        for (int j = minLexicalItem; j < LexicalItemCount; j++) {
98                buf->item_stream[j][BUFFER_BLOCKS] = sentinel_value;
99        }
100
101        buffer_base_pos = 0;
102        buffer_rel_pos = content_start;
103        buffer_limit_pos = min(BUFFER_SIZE, byteplex->units_in_buffer);
104        int blocks_in_buffer = (buffer_limit_pos + BLOCKSIZE - 1)/BLOCKSIZE;
105        x8data = byteplex->x8data;
106        lexer = Lexer<C>::LexerFactory(m, buf);
107        bitplex->TransposeToBitStreams(byteplex->x8data, blocks_in_buffer);
108        lexer->AnalyzeBuffer(bitplex->x8basis, buffer_limit_pos);
109}
110
111template <CodeUnit_Base C>
112ParsingEngine<C>::~ParsingEngine() {
113  model_info->~Model_Info();
114  byteplex->~Byteplex();
115  decl_parser->~XML_Decl_Parser<C>();
116  bitplex->~Bitplex();
117  simd_delete((SIMD_type *) buf);
118  lexer->~Lexer_Interface();
119}
120
121template <CodeUnit_Base C>
122inline void ParsingEngine<C>::AdvanceBuffers(int preserve_pos){
123        int advance_amt = min(preserve_pos, text_or_markup_start) - buffer_base_pos;
124        advance_amt &= -PACKSIZE; // maintain alignment
125        byteplex->AdvanceInputBuffer(advance_amt);
126        buffer_base_pos += advance_amt;
127        buffer_rel_pos -= advance_amt;
128        buffer_limit_pos = min(BUFFER_SIZE, byteplex->units_in_buffer);
129        int blocks_in_buffer = (buffer_limit_pos + BLOCKSIZE - 1)/BLOCKSIZE;
130        byteplex->DoByteplex();
131        byteplex->PreparePseudoASCII_Stream();
132        bitplex->TransposeToBitStreams(byteplex->x8data, blocks_in_buffer);
133        lexer->AnalyzeBuffer(bitplex->x8basis, buffer_limit_pos);
134}
135
136template <CodeUnit_Base C>
137inline unsigned char * ParsingEngine<C>::cur() const {
138  return &((unsigned char *) x8data)[buffer_rel_pos];
139}
140
141template <CodeUnit_Base C>
142inline int ParsingEngine<C>::AbsPos() const {
143  return buffer_base_pos + buffer_rel_pos;
144}
145
146
147template <CodeUnit_Base C>
148inline int ParsingEngine<C>::BufferRelPos() const {
149  return buffer_rel_pos;
150}
151
152
153template <CodeUnit_Base C>
154inline bool ParsingEngine<C>::at_EOF() const {
155  return (buffer_rel_pos >= buffer_limit_pos) && 
156         (buffer_limit_pos < BUFFER_SIZE);
157}
158
159template <CodeUnit_Base C>
160inline void ParsingEngine<C>::Advance(int n) {
161        int preserve_pos;
162        buffer_rel_pos += n;
163#ifndef OMIT_BITBUFFER_LIMIT_TEST_IN_ADVANCE
164  if (buffer_rel_pos >= BUFFER_SIZE) {
165        FinalizeBuffer_action(preserve_pos);
166        AdvanceBuffers(preserve_pos);
167  }
168#endif
169}
170
171
172#ifndef OPTIMIZE_SHORT_SCAN
173template <CodeUnit_Base C>
174inline void ParsingEngine<C>::ScanTo(int item) {
175        int preserve_pos;
176  buffer_rel_pos = bitstream_scan(buf->item_stream[item], 
177                                      buffer_rel_pos);
178  while (buffer_rel_pos >= BUFFER_SIZE) {
179        FinalizeBuffer_action(preserve_pos);
180        AdvanceBuffers(preserve_pos);
181        buffer_rel_pos = bitstream_scan(buf->item_stream[item], buffer_rel_pos);
182  }
183}
184#endif
185
186#ifdef OPTIMIZE_SHORT_SCAN
187template <CodeUnit_Base C>
188inline void ParsingEngine<C>::ScanTo(int item) {
189  SIMD_type * stream = buf->item_stream[item];
190  unsigned long * bitstream_ptr = (unsigned long *) (((intptr_t) stream) + buffer_rel_pos/8);
191  unsigned long bitstream_slice = *bitstream_ptr >> buffer_rel_pos % 8;
192  if (bitstream_slice != 0) {
193    buffer_rel_pos += __builtin_ctzl(bitstream_slice);
194  }
195  else {
196    buffer_rel_pos = (buffer_rel_pos & -8) + 8*sizeof(unsigned long);
197    buffer_rel_pos += bitstream_scan0((SIMD_type *) &bitstream_ptr[1]);
198    while (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
199      buffer_rel_pos = BUFFER_BLOCKS * BLOCKSIZE;
200      FinalizeBuffer_action(preserve_pos);
201          AdvanceBuffers(preserve_pos);
202      buffer_rel_pos = bitstream_scan(buf->item_stream[item], buffer_rel_pos);
203    }
204  }
205}
206#endif
207
208
209/* Parse a markup item beginning '<' */
210template <CodeUnit_Base C>
211inline void ParsingEngine<C>::Parse_Markup() {
212        text_or_markup_start = AbsPos();
213        if (at_ElementTag_Start<C>(cur())) {
214                Parse_StartTag();
215        }
216        else if (at_EndTag_Start<C>(cur())) {
217                Parse_EndTag();
218        }
219        else if (at_Comment_Start<C>(cur())) {
220                Parse_Comment();
221        }
222        else if (at_CDATA_Start<C>(cur())) {
223                Parse_CDATA();
224        }
225        else if (at_PI_Start<C>(cur())) {
226                Parse_PI();
227        }
228        else {
229                Advance(1);
230                Error_action(text_or_markup_start, AbsPos());
231        }
232}
233
234/* Parse a comment beginning "<!--" */
235template <CodeUnit_Base C>
236inline void ParsingEngine<C>::Parse_Comment() {
237
238        Advance(4); /* Skip "<!--". */
239        ScanTo(Hyphen);
240        while (!at_DoubleHyphen<C>(cur())) {
241                Advance(2); /* Skip hyphen-nonhyphen pair */
242                ScanTo(Hyphen); 
243        }
244        if (at_Comment_End<C>(cur())) {
245                Advance(3); /* Skip "-->". */
246                Comment_action(text_or_markup_start, AbsPos());
247        }
248        else {
249                Advance(2);  /* "--" */
250                Error_action(text_or_markup_start, AbsPos());
251        }
252}
253
254/* Parse an end tag beginning "</" */
255template <CodeUnit_Base C>
256inline void ParsingEngine<C>::Parse_EndTag() {
257        Advance(2); /* Skip "</". */
258        ScanTo(NameFollow);
259        if (AtChar<C,'>'>(cur())) {
260                Advance(1);
261                EndTag_action(text_or_markup_start, AbsPos());
262        }
263        else {
264                ScanTo(NonWS);
265                if (AtChar<C,'>'>(cur())) {
266                        Advance(1);
267                        EndTag_action(text_or_markup_start, AbsPos());
268                }
269                else Error_action(text_or_markup_start, AbsPos());
270        }
271}
272
273/* Parse a CDATA section beginning "<![CDATA". */
274template <CodeUnit_Base C>
275inline void ParsingEngine<C>::Parse_CDATA() {
276        Advance(8); /* Skip "<![CDATA". */
277        if (!AtChar<C,'['>(cur())) {
278                Error_action(text_or_markup_start, AbsPos());
279        }
280        else {
281                ScanTo(CD_End_check);
282                while (!at_CDATA_End<C>(cur())) {
283                        Advance(1);
284                        ScanTo(CD_End_check);
285                }
286                Advance(3); /* Skip "]]>". */
287                CDATA_action(text_or_markup_start, AbsPos());
288        }
289}
290
291template <CodeUnit_Base C>
292inline void ParsingEngine<C>::Parse_Reference() {
293        Advance(1);  // skip "&"
294        ScanTo(NameFollow);  /* Name delimiter */
295        if (!AtChar<C,';'>(cur())) {
296                Error_action(text_or_markup_start, AbsPos());
297        }
298        else {
299                Advance(1);
300                Reference_action(text_or_markup_start, AbsPos());
301        }
302}
303
304template <CodeUnit_Base C>
305inline void ParsingEngine<C>::Parse_PI (){
306        Advance(2); /* Skip "<?". */
307        int target_start = AbsPos();
308        // Check for illegal [Xx][Mm][Ll] target.
309        if (at_XxMmLll_WS<C>(cur())) {
310                Advance(4);
311                Error_action(text_or_markup_start, AbsPos());
312                return;
313        } 
314        ScanTo(NameFollow);  /* Name delimiter */
315        PI_Target_action(target_start, AbsPos());
316        ScanTo(QMark);
317        while (!at_PI_End<C>(cur())) {
318                Advance(1);
319                ScanTo(QMark);
320        }
321        Advance(2); /* Skip "?>". */
322        PI_action(text_or_markup_start, AbsPos());
323}
324 
325/* Parse a start or empty element tag. */
326template <CodeUnit_Base C>
327inline void ParsingEngine<C>::Parse_StartTag (){
328        int att_name_start;
329        int att_val_start;
330        int att_name_end, att_val_end;
331        unsigned char quoteCh;
332        Advance(1);
333        ScanTo(NameFollow);  /* Name delimiter: WS, "/" or ">" */
334        ElementName_action(text_or_markup_start+1, AbsPos());
335        /* The following test optimizes the most common case of a
336        start tag with no attributes.  */
337        if (AtChar<C,'>'>(cur())) {
338                Advance(1);
339                StartTag_action(text_or_markup_start, AbsPos());
340        }
341        else {
342                ScanTo(NonWS);
343                if (AtChar<C,'>'>(cur())) {
344                        Advance(1);
345                        StartTag_action(text_or_markup_start, AbsPos());
346                }
347                else if (at_EmptyElementDelim<C>(cur())) {
348                        Advance(2);
349                        EmptyElement_action(text_or_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_EqualsQuote<C>(cur())) {
361                                quoteCh = cur()[1];
362                                Advance(2); 
363                        }
364                        else {
365                                ScanTo(NonWS);
366                                if (!AtChar<C,'='>(cur())) {
367                                        Error_action(text_or_markup_start, AbsPos()); 
368                                        break;
369                                }
370                                ScanTo(NonWS);
371                                quoteCh = cur()[0];
372                                if (!AtQuote<C>(cur())) {
373                                        Error_action(text_or_markup_start, AbsPos()); 
374                                        break;
375                                }
376                                Advance(1);
377                        }
378                        att_val_start = AbsPos();
379                        ScanTo(Quote);
380                        while (cur()[0] != quoteCh) {
381                                if (AtChar<C,'&'>(cur())) {
382                                        Parse_Reference();
383                                        ScanTo(Quote);
384                                }
385                                else if (AtQuote<C>(cur())) {
386                                        Advance(1);
387                                }
388                                else /* if (AtChar<C,'<'>(cur())) */{
389                                        Error_action(text_or_markup_start, AbsPos()); 
390                                        break;
391                                }
392                        }
393                        att_val_end = AbsPos();
394                        Advance(1); 
395                        if (at_xmlns<C>(cur()+att_name_start-AbsPos())) {
396                                Namespace_action(att_name_start, att_name_end,
397                                                 att_val_start, att_val_end);
398                        }
399                        else {
400                                AttributeValue_action(att_name_start, att_name_end,
401                                                      att_val_start, att_val_end);
402                        }
403                        /* Now check for end or repeat. Avoid whitespace scan if possible.*/
404                        if (AtChar<C,'>'>(cur())) {
405                                Advance(1);
406                                StartTag_action(text_or_markup_start, AbsPos());
407                                break;
408                        }
409                        else if (at_EmptyElementDelim<C>(cur())) {
410                                Advance(2);
411                                EmptyElement_action(text_or_markup_start, AbsPos());
412                                break;
413                        }
414                        ScanTo(NonWS);
415                        if (AtChar<C,'>'>(cur())) {
416                                Advance(1);
417                                StartTag_action(text_or_markup_start, AbsPos());
418                                break;
419                        }
420                        else if (at_EmptyElementDelim<C>(cur())) {
421                                Advance(2);
422                                EmptyElement_action(text_or_markup_start, AbsPos());
423                                break;
424                        }
425                        else if (AbsPos() == att_val_end + 1) { 
426                                /* No WS following att value */
427                                Error_action(text_or_markup_start, AbsPos());
428                                break;
429                        }
430                } while (1);
431        }
432}
433
434template <CodeUnit_Base C>
435inline void ParsingEngine<C>::text_if_nonnull_action(){
436        if (AbsPos() > text_or_markup_start) {
437                Text_action(text_or_markup_start, AbsPos());
438                text_or_markup_start = AbsPos();
439        }
440}
441
442template <CodeUnit_Base C>
443inline void ParsingEngine<C>::ParseContent() {
444        DocumentStart_action(); 
445        do {
446                text_or_markup_start = AbsPos();
447                ScanTo(MarkupStart); /* '<', '&', or ']' for ']]>' test */
448/*              if (AtChar<C,'<'>(cur())) {
449                        text_if_nonnull_action();
450                        Parse_Markup<C>();
451                }*/
452                if (at_ElementTag_Start<C>(cur())) {
453                        text_if_nonnull_action();
454                        Parse_StartTag();
455                }
456                else if (at_EndTag_Start<C>(cur())) {
457                        text_if_nonnull_action();
458                        Parse_EndTag();
459                }
460                else if (at_Comment_Start<C>(cur())) {
461                        text_if_nonnull_action();
462                        Parse_Comment();
463                }
464                else if (AtChar<C,'&'>(cur())) {
465                        text_if_nonnull_action();
466                        Parse_Reference();
467                }
468                else if (at_CDATA_Start<C>(cur())) {
469                        text_if_nonnull_action();
470                        Parse_CDATA();
471                }
472                else if (at_PI_Start<C>(cur())) {
473                        text_if_nonnull_action();
474                        Parse_PI();
475                }
476                else if (at_CDATA_End<C>(cur())) {
477                        text_if_nonnull_action();
478                        Advance(3);
479                        Error_action(AbsPos()-3, AbsPos());
480                }
481                else if (at_EOF()) {
482                        text_if_nonnull_action();
483                        break;
484                }
485                else {
486                        Advance(1);
487                        continue;
488                }
489        } while (1);
490        DocumentEnd_action();   
491}
492
Note: See TracBrowser for help on using the repository browser.