Skip to content

Commit

Permalink
xml_parsert: construct with message handler
Browse files Browse the repository at this point in the history
This both avoids an object of static lifetime as well as it fixes the
(transitive) use of the deprecated messaget() constructor. Avoid global
objects in the lexer (as side-effect making it reentrant) as
initialisation is required. The parser continues to have global state,
so guard against reentrant use.
  • Loading branch information
tautschnig committed Mar 15, 2024
1 parent 7232457 commit 9f01d3e
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 27 deletions.
12 changes: 8 additions & 4 deletions src/xmllang/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

#include "xml_parser.h"

int yyxmllex();
extern char *yyxmltext;
int yyxmllex(void *);
char *yyxmlget_text(void *);

int yyxmlerror(const std::string &error)
int yyxmlerror(xml_parsert &xml_parser, void *scanner, const std::string &error)

Check warning on line 9 in src/xmllang/parser.y

View check run for this annotation

Codecov / codecov/patch

src/xmllang/parser.y#L9

Added line #L9 was not covered by tests
{
xml_parser.parse_error(error, yyxmltext);
xml_parser.parse_error(error, yyxmlget_text(scanner));

Check warning on line 11 in src/xmllang/parser.y

View check run for this annotation

Codecov / codecov/patch

src/xmllang/parser.y#L11

Added line #L11 was not covered by tests
return 0;
}

Expand All @@ -26,6 +26,10 @@ int yyxmlerror(const std::string &error)
#endif
%}

%parse-param {xml_parsert &xml_parser}
%parse-param {void *scanner}
%lex-param {void *scanner}

%union {char *s;}

%token STARTXMLDECL
Expand Down
11 changes: 5 additions & 6 deletions src/xmllang/scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
%option noinput
%option nounistd
%option never-interactive
%option noyywrap
%option reentrant
%option extra-type="xml_parsert *"

%{

Expand All @@ -19,7 +22,7 @@
#include "xml_parser.h"
#include "xml_y.tab.h"

#define PARSER xml_parser
#define PARSER (*yyextra)

//static int keep; /* To store start condition */

Expand Down Expand Up @@ -87,9 +90,5 @@ string \"([^"&]|{esc})*\"|\'([^'&]|{esc})*\'
<DTD>. {/* skip */}
<DTD>\]{close} {BEGIN(INITIAL); /* skip */}

. { yyxmlerror("unexpected character"); }
. { yyxmlerror(*yyextra, yyscanner, "unexpected character"); }

Check warning on line 93 in src/xmllang/scanner.l

View check run for this annotation

Codecov / codecov/patch

src/xmllang/scanner.l#L93

Added line #L93 was not covered by tests
{nl} {/* skip, must be an extra one at EOF */;}

%%

int yywrap() { return 1; }
24 changes: 17 additions & 7 deletions src/xmllang/xml_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,20 @@ Author: Daniel Kroening, [email protected]

#include <fstream>

xml_parsert xml_parser;
int xml_parsert::instance_count = 0;

int yyxmllex_init_extra(xml_parsert *, void **);
int yyxmllex_destroy(void *);
int yyxmlparse(xml_parsert &, void *);

bool xml_parsert::parse()
{
void *scanner;
yyxmllex_init_extra(this, &scanner);
bool parse_fail = yyxmlparse(*this, scanner) != 0;
yyxmllex_destroy(scanner);
return parse_fail;
}

// 'do it all' function
bool parse_xml(
Expand All @@ -19,19 +32,16 @@ bool parse_xml(
message_handlert &message_handler,
xmlt &dest)
{
xml_parser.clear();
xml_parsert xml_parser{message_handler};

xml_parser.set_file(filename);
xml_parser.in=&in;
xml_parser.log.set_message_handler(message_handler);

bool result=yyxmlparse()!=0;
bool result = xml_parser.parse();

// save result
xml_parser.parse_tree.element.swap(dest);

// save some memory
xml_parser.clear();

return result;
}

Expand Down
35 changes: 25 additions & 10 deletions src/xmllang/xml_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,25 @@ Author: Daniel Kroening, [email protected]

#include "xml_parse_tree.h"

int yyxmlparse();

class xml_parsert:public parsert
{
public:
explicit xml_parsert(message_handlert &message_handler)
: parsert(message_handler)
{
// Simplistic check that we don't attempt to do reentrant parsing as the
// Bison-generated parser has global state.
PRECONDITION(++instance_count == 1);
stack.push_back(&parse_tree.element);
}

xml_parsert(const xml_parsert &) = delete;

~xml_parsert() override
{
--instance_count;
}

xml_parse_treet parse_tree;

std::list<xmlt *> stack;
Expand All @@ -28,29 +42,30 @@ class xml_parsert:public parsert
return *stack.back();
}

virtual bool parse()
{
return yyxmlparse()!=0;
}
bool parse() override;

void new_level()
{
current().elements.push_back(xmlt());
stack.push_back(&current().elements.back());
}

virtual void clear()
/// Clears the parser state. May be removed in future as there should not be a
/// need to re-use an existing parser object.
void clear() override

Check warning on line 55 in src/xmllang/xml_parser.h

View check run for this annotation

Codecov / codecov/patch

src/xmllang/xml_parser.h#L55

Added line #L55 was not covered by tests
{
parse_tree.clear();
// set up stack
stack.clear();
stack.push_back(&parse_tree.element);
parsert::clear();

Check warning on line 61 in src/xmllang/xml_parser.h

View check run for this annotation

Codecov / codecov/patch

src/xmllang/xml_parser.h#L61

Added line #L61 was not covered by tests
}
};

extern xml_parsert xml_parser;
protected:
static int instance_count;
};

int yyxmlerror(const std::string &error);
int yyxmlerror(xml_parsert &, void *, const std::string &);

// 'do it all' functions
bool parse_xml(
Expand Down

0 comments on commit 9f01d3e

Please sign in to comment.