mirror of
https://github.com/cwbaker/lalr.git
synced 2026-09-26 16:33:18 +03:00
1411 lines
40 KiB
C++
1411 lines
40 KiB
C++
//
|
|
// RegexParser.cpp
|
|
// Copyright (c) 2007 - 2011 Charles Baker. All rights reserved.
|
|
//
|
|
|
|
#include "stdafx.hpp"
|
|
#include "RegexParser.hpp"
|
|
#include "RegexNode.hpp"
|
|
#include "RegexNodeLess.hpp"
|
|
#include "RegexCharacter.hpp"
|
|
#include "LexerGenerator.hpp"
|
|
#include "Error.hpp"
|
|
#include <boost/spirit/include/classic.hpp>
|
|
#include <boost/spirit/include/classic_file_iterator.hpp>
|
|
#include <boost/spirit/include/classic_position_iterator.hpp>
|
|
#include <boost/bind.hpp>
|
|
|
|
using std::set;
|
|
using std::pair;
|
|
using std::string;
|
|
using std::vector;
|
|
using namespace sweet;
|
|
using namespace sweet::lexer;
|
|
|
|
namespace sweet
|
|
{
|
|
|
|
namespace lexer
|
|
{
|
|
|
|
/**
|
|
// ParserGrammar for regular expressions.
|
|
*/
|
|
template <class Iterator>
|
|
class RegexGrammar : public boost::spirit::grammar<RegexGrammar<Iterator> >
|
|
{
|
|
public:
|
|
typedef Iterator iterator;
|
|
|
|
template <typename Scanner>
|
|
class definition
|
|
{
|
|
boost::spirit::rule<Scanner> regex;
|
|
boost::spirit::rule<Scanner> or_expression;
|
|
boost::spirit::rule<Scanner> cat_expression;
|
|
boost::spirit::rule<Scanner> postfix_expression;
|
|
boost::spirit::rule<Scanner> base_expression;
|
|
boost::spirit::rule<Scanner> negative_bracket_expression;
|
|
boost::spirit::rule<Scanner> bracket_expression;
|
|
boost::spirit::rule<Scanner> action_expression;
|
|
boost::spirit::rule<Scanner> postfix;
|
|
boost::spirit::rule<Scanner> character_;
|
|
boost::spirit::rule<Scanner> item;
|
|
boost::spirit::rule<Scanner> negative_item;
|
|
boost::spirit::rule<Scanner> ch;
|
|
|
|
public:
|
|
definition( const RegexGrammar& self );
|
|
boost::spirit::rule<Scanner> const& start() const;
|
|
};
|
|
|
|
private:
|
|
RegexParser* parser_; ///< The RegexParser to report matches to.
|
|
|
|
public:
|
|
RegexGrammar( RegexParser* parser );
|
|
RegexParser* get_parser() const;
|
|
void action_expression( iterator start, iterator finish ) const;
|
|
void character( iterator start, iterator finish ) const;
|
|
void item_range( iterator start, iterator finish ) const;
|
|
void item_character( iterator start, iterator finish ) const;
|
|
void negative_item_range( iterator start, iterator finish ) const;
|
|
void negative_item_character( iterator start, iterator finish ) const;
|
|
int escape( iterator start, iterator finish ) const;
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
// The RegexGrammar definition.
|
|
//
|
|
// @param self
|
|
// The RegexGrammar.
|
|
*/
|
|
template <class Iterator>
|
|
template <class Scanner>
|
|
RegexGrammar<Iterator>::definition<Scanner>::definition( const RegexGrammar& self )
|
|
{
|
|
using namespace boost::spirit;
|
|
|
|
RegexParser* parser = self.get_parser();
|
|
|
|
regex = or_expression
|
|
>> end_p
|
|
;
|
|
|
|
or_expression = cat_expression
|
|
>> !(ch_p('|') >> or_expression) [boost::bind(&RegexParser::or_expression, parser)]
|
|
;
|
|
|
|
cat_expression = postfix_expression
|
|
>> !cat_expression [boost::bind(&RegexParser::cat_expression, parser)]
|
|
;
|
|
|
|
postfix_expression = base_expression
|
|
>> !postfix
|
|
;
|
|
|
|
base_expression = negative_bracket_expression
|
|
| bracket_expression
|
|
| action_expression
|
|
| ch_p('(') >> or_expression >> ch_p(')')
|
|
| character_
|
|
;
|
|
|
|
negative_bracket_expression = str_p("[^") [boost::bind(&RegexParser::begin_negative_bracket_expression, parser)]
|
|
>> !ch_p( '-' ) [boost::bind(&RegexParser::negative_item_character, parser, '-')]
|
|
>> *negative_item
|
|
>> !ch_p( '-' ) [boost::bind(&RegexParser::negative_item_character, parser, '-')]
|
|
>> ch_p(']') [boost::bind(&RegexParser::end_bracket_expression, parser)]
|
|
;
|
|
|
|
bracket_expression = ch_p('[') [boost::bind(&RegexParser::begin_bracket_expression, parser)]
|
|
>> !ch_p( '-' ) [boost::bind(&RegexParser::item_character, parser, '-')]
|
|
>> *item
|
|
>> !ch_p( '-' ) [boost::bind(&RegexParser::item_character, parser, '-')]
|
|
>> ch_p(']') [boost::bind(&RegexParser::end_bracket_expression, parser)]
|
|
;
|
|
|
|
action_expression = lexeme_d[
|
|
ch_p(':')
|
|
>> ((alpha_p | ch_p("_")) >> *(alnum_p | ch_p("_"))) [boost::bind(&RegexGrammar::action_expression, &self, _1, _2)]
|
|
>> ch_p(':')
|
|
];
|
|
|
|
postfix = ch_p( '*' ) [boost::bind(&RegexParser::star_expression, parser)]
|
|
| ch_p( '+' ) [boost::bind(&RegexParser::plus_expression, parser)]
|
|
| ch_p( '?' ) [boost::bind(&RegexParser::optional_expression, parser)]
|
|
;
|
|
|
|
character_ = ch_p( '.' ) [boost::bind(&RegexParser::dot, parser)]
|
|
| ch [boost::bind(&RegexGrammar::character, &self, _1, _2)]
|
|
;
|
|
|
|
item = str_p("[:alnum:]" ) [boost::bind(&RegexParser::item_alnum, parser)]
|
|
| str_p("[:word:]" ) [boost::bind(&RegexParser::item_word, parser)]
|
|
| str_p("[:alpha:]" ) [boost::bind(&RegexParser::item_alpha, parser)]
|
|
| str_p("[:blank:]" ) [boost::bind(&RegexParser::item_blank, parser)]
|
|
| str_p("[:cntrl:]" ) [boost::bind(&RegexParser::item_cntrl, parser)]
|
|
| str_p("[:digit:]" ) [boost::bind(&RegexParser::item_digit, parser)]
|
|
| str_p("[:graph:]" ) [boost::bind(&RegexParser::item_graph, parser)]
|
|
| str_p("[:lower:]" ) [boost::bind(&RegexParser::item_lower, parser)]
|
|
| str_p("[:print:]" ) [boost::bind(&RegexParser::item_print, parser)]
|
|
| str_p("[:punct:]" ) [boost::bind(&RegexParser::item_punct, parser)]
|
|
| str_p("[:space:]" ) [boost::bind(&RegexParser::item_space, parser)]
|
|
| str_p("[:upper:]" ) [boost::bind(&RegexParser::item_upper, parser)]
|
|
| str_p("[:xdigit:]" ) [boost::bind(&RegexParser::item_xdigit, parser)]
|
|
| (ch >> ch_p('-') >> ch) [boost::bind(&RegexGrammar::item_range, &self, _1, _2)]
|
|
| ch [boost::bind(&RegexGrammar::item_character, &self, _1, _2)]
|
|
;
|
|
|
|
negative_item = str_p("[:alnum:]" ) [boost::bind(&RegexParser::negative_item_alnum, parser)]
|
|
| str_p("[:word:]" ) [boost::bind(&RegexParser::negative_item_word, parser)]
|
|
| str_p("[:alpha:]" ) [boost::bind(&RegexParser::negative_item_alpha, parser)]
|
|
| str_p("[:blank:]" ) [boost::bind(&RegexParser::negative_item_blank, parser)]
|
|
| str_p("[:cntrl:]" ) [boost::bind(&RegexParser::negative_item_cntrl, parser)]
|
|
| str_p("[:digit:]" ) [boost::bind(&RegexParser::negative_item_digit, parser)]
|
|
| str_p("[:graph:]" ) [boost::bind(&RegexParser::negative_item_graph, parser)]
|
|
| str_p("[:lower:]" ) [boost::bind(&RegexParser::negative_item_lower, parser)]
|
|
| str_p("[:print:]" ) [boost::bind(&RegexParser::negative_item_print, parser)]
|
|
| str_p("[:punct:]" ) [boost::bind(&RegexParser::negative_item_punct, parser)]
|
|
| str_p("[:space:]" ) [boost::bind(&RegexParser::negative_item_space, parser)]
|
|
| str_p("[:upper:]" ) [boost::bind(&RegexParser::negative_item_upper, parser)]
|
|
| str_p("[:xdigit:]" ) [boost::bind(&RegexParser::negative_item_xdigit, parser)]
|
|
| (ch >> ch_p('-') >> ch) [boost::bind(&RegexGrammar::negative_item_range, &self, _1, _2)]
|
|
| ch [boost::bind(&RegexGrammar::negative_item_character, &self, _1, _2)]
|
|
;
|
|
|
|
ch = lexeme_d[
|
|
ch_p( '\\' ) >> oct_p
|
|
| str_p( "\\x" ) >> hex_p
|
|
| ch_p( '\\' ) >> anychar_p
|
|
| anychar_p - chset_p( "|*+?[]()-" )
|
|
];
|
|
|
|
BOOST_SPIRIT_DEBUG_RULE( regex );
|
|
BOOST_SPIRIT_DEBUG_RULE( or_expression );
|
|
BOOST_SPIRIT_DEBUG_RULE( cat_expression );
|
|
BOOST_SPIRIT_DEBUG_RULE( postfix_expression );
|
|
BOOST_SPIRIT_DEBUG_RULE( base_expression );
|
|
BOOST_SPIRIT_DEBUG_RULE( negative_bracket_expression );
|
|
BOOST_SPIRIT_DEBUG_RULE( bracket_expression );
|
|
BOOST_SPIRIT_DEBUG_RULE( action_expression );
|
|
BOOST_SPIRIT_DEBUG_RULE( postfix );
|
|
BOOST_SPIRIT_DEBUG_RULE( character_ );
|
|
BOOST_SPIRIT_DEBUG_RULE( item );
|
|
BOOST_SPIRIT_DEBUG_RULE( negative_item );
|
|
BOOST_SPIRIT_DEBUG_RULE( ch );
|
|
}
|
|
|
|
/**
|
|
// Get the starting symbol for the grammar grammar.
|
|
//
|
|
// @return
|
|
// The starting symbol.
|
|
*/
|
|
template <class Iterator>
|
|
template <class Scanner>
|
|
boost::spirit::rule<Scanner> const&
|
|
RegexGrammar<Iterator>::definition<Scanner>::start() const
|
|
{
|
|
return regex;
|
|
}
|
|
|
|
/**
|
|
// Constructor.
|
|
//
|
|
// @param parser
|
|
// The RegexParser to report grammar matches to.
|
|
*/
|
|
template <class Iterator>
|
|
RegexGrammar<Iterator>::RegexGrammar( RegexParser* parser )
|
|
: parser_( parser )
|
|
{
|
|
SWEET_ASSERT( parser_ );
|
|
}
|
|
|
|
/**
|
|
// Get the RegexParser that this RegexGrammar reports matches to.
|
|
//
|
|
// @return
|
|
// The RegexParser.
|
|
*/
|
|
template <class Iterator>
|
|
RegexParser*
|
|
RegexGrammar<Iterator>::get_parser() const
|
|
{
|
|
return parser_;
|
|
}
|
|
|
|
/**
|
|
// Match an action call.
|
|
//
|
|
// @param start
|
|
// The iterator at the start of the action to matched.
|
|
//
|
|
// @param finish
|
|
// The iterator one past the end of the action to match.
|
|
*/
|
|
template <class Iterator>
|
|
void
|
|
RegexGrammar<Iterator>::action_expression( iterator start, iterator finish ) const
|
|
{
|
|
SWEET_ASSERT( parser_ );
|
|
parser_->action_expression( std::string(start, finish) );
|
|
}
|
|
|
|
/**
|
|
// Match a character.
|
|
//
|
|
// @param start
|
|
// The iterator at the start of the character to match.
|
|
//
|
|
// @param finish
|
|
// The iterator one past the end of the character to match.
|
|
*/
|
|
template <class Iterator>
|
|
void
|
|
RegexGrammar<Iterator>::character( iterator start, iterator finish ) const
|
|
{
|
|
SWEET_ASSERT( parser_ );
|
|
parser_->character( escape(start, finish) );
|
|
}
|
|
|
|
/**
|
|
// Match a range in a bracketed expression.
|
|
//
|
|
// @param start
|
|
// The iterator at the start of the range to match.
|
|
//
|
|
// @param finish
|
|
// The iterator one past the end of the range to match.
|
|
*/
|
|
template <class Iterator>
|
|
void
|
|
RegexGrammar<Iterator>::item_range( iterator start, iterator finish ) const
|
|
{
|
|
iterator delimiter = std::find( start, finish, '-' );
|
|
SWEET_ASSERT( delimiter != finish );
|
|
SWEET_ASSERT( *delimiter == '-' );
|
|
int begin = escape( start, delimiter );
|
|
++delimiter;
|
|
int end = escape( delimiter, finish ) + 1;
|
|
|
|
SWEET_ASSERT( parser_ );
|
|
parser_->item_range( begin, end );
|
|
}
|
|
|
|
/**
|
|
// Match a character in a bracketed expression.
|
|
//
|
|
// @param start
|
|
// The iterator at the start of the character to match.
|
|
//
|
|
// @param finish
|
|
// The iterator one past the end of the character to match.
|
|
*/
|
|
template <class Iterator>
|
|
void
|
|
RegexGrammar<Iterator>::item_character( iterator start, iterator finish ) const
|
|
{
|
|
SWEET_ASSERT( parser_ );
|
|
parser_->item_character( escape(start, finish) );
|
|
}
|
|
|
|
/**
|
|
// Match a range in a negative bracketed expression.
|
|
//
|
|
// @param start
|
|
// The iterator at the start of the range to match.
|
|
//
|
|
// @param finish
|
|
// The iterator one past the end of the range to match.
|
|
*/
|
|
template <class Iterator>
|
|
void
|
|
RegexGrammar<Iterator>::negative_item_range( iterator start, iterator finish ) const
|
|
{
|
|
iterator delimiter = std::find( start, finish, '-' );
|
|
SWEET_ASSERT( delimiter != finish );
|
|
SWEET_ASSERT( *delimiter == '-' );
|
|
int begin = escape( start, delimiter );
|
|
++delimiter;
|
|
int end = escape( delimiter, finish ) + 1;
|
|
|
|
SWEET_ASSERT( parser_ );
|
|
parser_->negative_item_range( begin, end );
|
|
}
|
|
|
|
/**
|
|
// Match a character in a negative bracketed expression.
|
|
//
|
|
// @param start
|
|
// The iterator at the start of the character to match.
|
|
//
|
|
// @param finish
|
|
// The iterator one past the end of the character to match.
|
|
*/
|
|
template <class Iterator>
|
|
void
|
|
RegexGrammar<Iterator>::negative_item_character( iterator start, iterator finish ) const
|
|
{
|
|
SWEET_ASSERT( parser_ );
|
|
parser_->negative_item_character( escape(start, finish) );
|
|
}
|
|
|
|
/**
|
|
// Convert [\e start, \e finish) into a character converting escape
|
|
// sequences \b, \f, \n, \r, \t, \xHH, \000, or \ followed by any
|
|
// character.
|
|
//
|
|
// @param start
|
|
// The first character in the sequence to convert.
|
|
//
|
|
// @param finish
|
|
// One past the last character in the sequence to convert.
|
|
//
|
|
// @return
|
|
// The sequence [\e start, \e finish) converted into a character.
|
|
*/
|
|
template <class Iterator>
|
|
int
|
|
RegexGrammar<Iterator>::escape( iterator start, iterator finish ) const
|
|
{
|
|
int character = *start;
|
|
if ( character == '\\' )
|
|
{
|
|
++start;
|
|
if ( start != finish )
|
|
{
|
|
switch ( *start )
|
|
{
|
|
case 'b':
|
|
character = '\b';
|
|
break;
|
|
|
|
case 'f':
|
|
character = '\f';
|
|
break;
|
|
|
|
case 'n':
|
|
character = '\n';
|
|
break;
|
|
|
|
case 'r':
|
|
character = '\r';
|
|
break;
|
|
|
|
case 't':
|
|
character = '\t';
|
|
break;
|
|
|
|
case 'x':
|
|
case 'X':
|
|
++start;
|
|
character = 0;
|
|
while ( isxdigit(*start ) )
|
|
{
|
|
character <<= 4;
|
|
if ( *start >= '0' && *start <= '9' )
|
|
{
|
|
character += *start - '0';
|
|
}
|
|
else if ( *start >= 'a' && *start <= 'f' )
|
|
{
|
|
character += *start - 'a' + 10;
|
|
}
|
|
else if ( *start >= 'A' && *start <= 'F' )
|
|
{
|
|
character += *start - 'A' + 10;
|
|
}
|
|
|
|
++start;
|
|
}
|
|
break;
|
|
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
{
|
|
character = 0;
|
|
int count = 0;
|
|
while ( *start >= '0' && *start <= '7' && count < 3 )
|
|
{
|
|
character <<= 3;
|
|
character += *start - '0';
|
|
++start;
|
|
++count;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
character = *start;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return character;
|
|
}
|
|
|
|
/**
|
|
// Constructor.
|
|
//
|
|
// @param regular_expression
|
|
// The single regular expression to parse.
|
|
//
|
|
// @param symbol
|
|
// The symbol to return when the regular expression matches.
|
|
*/
|
|
RegexParser::RegexParser( const LexerToken& token, LexerGenerator* lexer_generator )
|
|
: lexer_generator_( lexer_generator ),
|
|
bracket_expression_characters_(),
|
|
index_( 0 ),
|
|
nodes_(),
|
|
errors_( 0 )
|
|
{
|
|
SWEET_ASSERT( lexer_generator_ );
|
|
parse_regular_expression( token );
|
|
calculate_nullable_first_last_and_follow();
|
|
}
|
|
|
|
/**
|
|
// Constructor.
|
|
*/
|
|
RegexParser::RegexParser( const std::vector<LexerToken>& tokens, LexerGenerator* lexer_generator )
|
|
: lexer_generator_( lexer_generator ),
|
|
bracket_expression_characters_(),
|
|
index_( 0 ),
|
|
nodes_(),
|
|
errors_( 0 )
|
|
{
|
|
SWEET_ASSERT( lexer_generator_ );
|
|
calculate_combined_parse_tree( tokens );
|
|
calculate_nullable_first_last_and_follow();
|
|
}
|
|
|
|
bool RegexParser::empty() const
|
|
{
|
|
return nodes_.empty();
|
|
}
|
|
|
|
/**
|
|
// Get the number of errors that occured while parsing.
|
|
//
|
|
// @return
|
|
// The number of errors.
|
|
*/
|
|
int RegexParser::errors() const
|
|
{
|
|
return errors_;
|
|
}
|
|
|
|
/**
|
|
// Get the RegexNode that resulted from the parse.
|
|
//
|
|
// @return
|
|
// The RegexNode.
|
|
*/
|
|
const ptr<RegexNode>& RegexParser::node() const
|
|
{
|
|
SWEET_ASSERT( !nodes_.empty() );
|
|
SWEET_ASSERT( nodes_.front() );
|
|
return nodes_.front();
|
|
}
|
|
|
|
/**
|
|
// Print the regular expression parse tree.
|
|
*/
|
|
void RegexParser::print() const
|
|
{
|
|
print_nodes( nodes_, 0 );
|
|
printf( "\n\n" );
|
|
}
|
|
|
|
/**
|
|
// Reduce the two most recently parsed expressions into a cat expression.
|
|
*/
|
|
void RegexParser::cat_expression()
|
|
{
|
|
ptr<RegexNode> right_node( nodes_.back() );
|
|
nodes_.pop_back();
|
|
|
|
ptr<RegexNode> left_node( nodes_.back() );
|
|
nodes_.pop_back();
|
|
|
|
ptr<RegexNode> node = regex_node( LEXER_NODE_CAT );
|
|
node->add_node( left_node );
|
|
node->add_node( right_node );
|
|
nodes_.push_back( node );
|
|
}
|
|
|
|
/**
|
|
// Reduce the two most recently parsed expressions into an or expression.
|
|
*/
|
|
void RegexParser::or_expression()
|
|
{
|
|
ptr<RegexNode> right_node( nodes_.back() );
|
|
nodes_.pop_back();
|
|
|
|
ptr<RegexNode> left_node( nodes_.back() );
|
|
nodes_.pop_back();
|
|
|
|
ptr<RegexNode> node = regex_node( LEXER_NODE_OR );
|
|
node->add_node( left_node );
|
|
node->add_node( right_node );
|
|
nodes_.push_back( node );
|
|
}
|
|
|
|
/**
|
|
// Reduce the most recently parsed expression into a star expression.
|
|
*/
|
|
void RegexParser::star_expression()
|
|
{
|
|
ptr<RegexNode> star_node( nodes_.back() );
|
|
nodes_.pop_back();
|
|
|
|
ptr<RegexNode> node = regex_node( LEXER_NODE_STAR );
|
|
node->add_node( star_node );
|
|
nodes_.push_back( node );
|
|
}
|
|
|
|
/**
|
|
// Reduce the most recently parsed expression into a plus expression.
|
|
*/
|
|
void RegexParser::plus_expression()
|
|
{
|
|
ptr<RegexNode> plus_node( nodes_.back() );
|
|
nodes_.pop_back();
|
|
|
|
ptr<RegexNode> node = regex_node( LEXER_NODE_PLUS );
|
|
node->add_node( plus_node );
|
|
nodes_.push_back( node );
|
|
}
|
|
|
|
/**
|
|
// Reduce the most recently parsed expression into an optional expression.
|
|
*/
|
|
void RegexParser::optional_expression()
|
|
{
|
|
ptr<RegexNode> optional_node( nodes_.back() );
|
|
nodes_.pop_back();
|
|
|
|
ptr<RegexNode> node = regex_node( LEXER_NODE_OPTIONAL );
|
|
node->add_node( optional_node );
|
|
nodes_.push_back( node );
|
|
}
|
|
|
|
/**
|
|
// Begin a bracket expression '[ ...'.
|
|
*/
|
|
void RegexParser::begin_bracket_expression()
|
|
{
|
|
bracket_expression_characters_.clear();
|
|
}
|
|
|
|
/**
|
|
// Begin a negative bracket expression '[^ ...'.
|
|
*/
|
|
void RegexParser::begin_negative_bracket_expression()
|
|
{
|
|
bracket_expression_characters_.clear();
|
|
insert_characters( BEGIN_CHARACTER, END_CHARACTER );
|
|
}
|
|
|
|
/**
|
|
// End a bracket or negative bracket expression.
|
|
*/
|
|
void RegexParser::end_bracket_expression()
|
|
{
|
|
set<RegexCharacter>::const_iterator character = bracket_expression_characters_.begin();
|
|
ptr<RegexNode> node = regex_node( character->get_begin_character(), character->get_end_character() );
|
|
nodes_.push_back( node );
|
|
++character;
|
|
|
|
while ( character != bracket_expression_characters_.end() )
|
|
{
|
|
node = regex_node( character->get_begin_character(), character->get_end_character() );
|
|
nodes_.push_back( node );
|
|
or_expression();
|
|
++character;
|
|
}
|
|
}
|
|
|
|
/**
|
|
// Handle an action expression ': [A-Za-z_][A-Za-z0-9_]* :'.
|
|
*/
|
|
void RegexParser::action_expression( const std::string& identifier )
|
|
{
|
|
SWEET_ASSERT( !identifier.empty() );
|
|
SWEET_ASSERT( lexer_generator_ );
|
|
ptr<RegexNode> node = regex_node( lexer_generator_->add_lexer_action(identifier) );
|
|
nodes_.push_back( node );
|
|
}
|
|
|
|
/**
|
|
// Handle a character.
|
|
*/
|
|
void RegexParser::character( int character )
|
|
{
|
|
ptr<RegexNode> node = regex_node( character, character + 1 );
|
|
nodes_.push_back( node );
|
|
}
|
|
|
|
/**
|
|
// Handle a dot.
|
|
*/
|
|
void RegexParser::dot()
|
|
{
|
|
ptr<RegexNode> node = regex_node( BEGIN_CHARACTER, END_CHARACTER );
|
|
nodes_.push_back( node );
|
|
|
|
}
|
|
|
|
/**
|
|
// Handle a range specified within a character class.
|
|
*/
|
|
void RegexParser::item_range( int begin, int end )
|
|
{
|
|
SWEET_ASSERT( begin >= BEGIN_CHARACTER && begin < END_CHARACTER );
|
|
SWEET_ASSERT( end >= BEGIN_CHARACTER && end < END_CHARACTER );
|
|
SWEET_ASSERT( begin <= end );
|
|
insert_characters( begin, end );
|
|
}
|
|
|
|
/**
|
|
// Handle a character specified within a character class.
|
|
*/
|
|
void RegexParser::item_character( int character )
|
|
{
|
|
SWEET_ASSERT( character >= BEGIN_CHARACTER && character < END_CHARACTER );
|
|
insert_characters( character, character + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':alnum:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_alnum()
|
|
{
|
|
item_alpha();
|
|
item_digit();
|
|
}
|
|
|
|
/**
|
|
// Handle ':word:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_word()
|
|
{
|
|
item_alpha();
|
|
item_digit();
|
|
insert_characters( '_', '_' + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':alpha:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_alpha()
|
|
{
|
|
item_lower();
|
|
item_upper();
|
|
}
|
|
|
|
/**
|
|
// Handle ':blank:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_blank()
|
|
{
|
|
insert_characters( " \t" );
|
|
}
|
|
|
|
/**
|
|
// Handle ':cntrl:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_cntrl()
|
|
{
|
|
insert_characters( 0x00, 0x1f + 1 );
|
|
insert_characters( 0x7f, 0x7f + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':digit:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_digit()
|
|
{
|
|
insert_characters( '0', '9' + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':graph:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_graph()
|
|
{
|
|
insert_characters( 0x21, 0x7e + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':lower:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_lower()
|
|
{
|
|
insert_characters( 'a', 'z' + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':print:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_print()
|
|
{
|
|
insert_characters( 0x20, 0x7e + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':punct:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_punct()
|
|
{
|
|
insert_characters( "-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~" );
|
|
}
|
|
|
|
/**
|
|
// Handle ':space:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_space()
|
|
{
|
|
insert_characters( " \t\r\n" );
|
|
}
|
|
|
|
/**
|
|
// Handle ':upper:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_upper()
|
|
{
|
|
insert_characters( 'A', 'Z' + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':xdigit:' specified in a character class.
|
|
*/
|
|
void RegexParser::item_xdigit()
|
|
{
|
|
insert_characters( "0123456789abcdefABCDEF" );
|
|
}
|
|
|
|
/**
|
|
// Handle a range specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_range( int begin, int end )
|
|
{
|
|
SWEET_ASSERT( begin >= BEGIN_CHARACTER && begin < END_CHARACTER );
|
|
SWEET_ASSERT( end >= BEGIN_CHARACTER && end < END_CHARACTER );
|
|
SWEET_ASSERT( begin <= end );
|
|
erase_characters( begin, end );
|
|
}
|
|
|
|
/**
|
|
// Handle a character specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_character( int character )
|
|
{
|
|
SWEET_ASSERT( character >= BEGIN_CHARACTER && character < END_CHARACTER );
|
|
erase_characters( character, character + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':alnum:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_alnum()
|
|
{
|
|
negative_item_alpha();
|
|
negative_item_digit();
|
|
}
|
|
|
|
/**
|
|
// Handle ':word:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_word()
|
|
{
|
|
negative_item_alpha();
|
|
negative_item_digit();
|
|
insert_characters( '_', '_' + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':alpha:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_alpha()
|
|
{
|
|
negative_item_lower();
|
|
negative_item_upper();
|
|
}
|
|
|
|
/**
|
|
// Handle ':blank:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_blank()
|
|
{
|
|
insert_characters( " \t" );
|
|
}
|
|
|
|
/**
|
|
// Handle ':cntrl:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_cntrl()
|
|
{
|
|
insert_characters( 0x00, 0x1f + 1 );
|
|
insert_characters( 0x7f, 0x7f + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':digit:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_digit()
|
|
{
|
|
insert_characters( '0', '9' + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':graph:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_graph()
|
|
{
|
|
insert_characters( 0x21, 0x7e + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':lower:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_lower()
|
|
{
|
|
insert_characters( 'a', 'z' + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':print:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_print()
|
|
{
|
|
insert_characters( 0x20, 0x7e + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':punct:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_punct()
|
|
{
|
|
insert_characters( "-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~" );
|
|
}
|
|
|
|
/**
|
|
// Handle ':space:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_space()
|
|
{
|
|
insert_characters( " \t\r\n" );
|
|
}
|
|
|
|
/**
|
|
// Handle ':upper:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_upper()
|
|
{
|
|
insert_characters( 'A', 'Z' + 1 );
|
|
}
|
|
|
|
/**
|
|
// Handle ':xdigit:' specified in a negative character class.
|
|
*/
|
|
void RegexParser::negative_item_xdigit()
|
|
{
|
|
insert_characters( "0123456789abcdefABCDEF" );
|
|
}
|
|
|
|
/**
|
|
// Create a specific type of RegexNode.
|
|
//
|
|
// @param type
|
|
// The type of RegexNode to create.
|
|
//
|
|
// @return
|
|
// The RegeNode.
|
|
*/
|
|
ptr<RegexNode> RegexParser::regex_node( RegexNodeType type )
|
|
{
|
|
ptr<RegexNode> node( new RegexNode(index_, type) );
|
|
++index_;
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
// Create a RegexNode to represent characters in the interval
|
|
// [\e begin, \e end).
|
|
//
|
|
// @param begin
|
|
// The first character in the interval to match.
|
|
//
|
|
// @param end
|
|
// One past the last character in the interval to match.
|
|
//
|
|
// @return
|
|
// The RegexNode.
|
|
*/
|
|
ptr<RegexNode> RegexParser::regex_node( int begin, int end )
|
|
{
|
|
ptr<RegexNode> node( new RegexNode(index_, begin, end) );
|
|
++index_;
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
// Create a RegexNode to represent characters in the interval
|
|
// [\e begin, \e end).
|
|
//
|
|
// @param begin
|
|
// The first character in the interval to match.
|
|
//
|
|
// @param end
|
|
// One past the last character in the interval to match.
|
|
//
|
|
// @param token
|
|
// The token to associate with the RegexNode.
|
|
//
|
|
// @return
|
|
// The RegexNode.
|
|
*/
|
|
ptr<RegexNode> RegexParser::regex_node( int begin, int end, const LexerToken* token )
|
|
{
|
|
ptr<RegexNode> node( new RegexNode(index_, begin, end, token) );
|
|
++index_;
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
// Create a RegexNode to represent a lexical analyzer action.
|
|
//
|
|
// @param action
|
|
// The LexerAction that this RegexNode represents.
|
|
// @return
|
|
// The RegexNode.
|
|
*/
|
|
ptr<RegexNode> RegexParser::regex_node( const LexerAction* action )
|
|
{
|
|
ptr<RegexNode> node( new RegexNode(index_, action) );
|
|
++index_;
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
// Print the positions represented by the RegexNodes in \e positions.
|
|
//
|
|
// @param positions
|
|
// The RegexNodes that are the positions to print.
|
|
*/
|
|
void RegexParser::print_positions( const std::set<RegexNode*, RegexNodeLess>& positions ) const
|
|
{
|
|
set<RegexNode*, RegexNodeLess>::const_iterator i = positions.begin();
|
|
if ( i != positions.end() )
|
|
{
|
|
const RegexNode* node = *i;
|
|
SWEET_ASSERT( node );
|
|
printf( "%d", node->get_index() );
|
|
++i;
|
|
}
|
|
|
|
while ( i != positions.end() )
|
|
{
|
|
const RegexNode* node = *i;
|
|
SWEET_ASSERT( node );
|
|
printf( ", %d", node->get_index() );
|
|
++i;
|
|
}
|
|
}
|
|
|
|
/**
|
|
// Print the RegexNodes \e nodes.
|
|
//
|
|
// @param nodes
|
|
// The RegexNodes to print.
|
|
//
|
|
// @param level
|
|
// The recursion level to use when identing lines.
|
|
*/
|
|
void RegexParser::print_nodes( const vector<ptr<RegexNode> >& nodes, int level ) const
|
|
{
|
|
for ( vector<ptr<RegexNode> >::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
|
|
{
|
|
static const char* LEXER_NODE_TYPES [LEXER_NODE_COUNT] =
|
|
{
|
|
"LEXER_NODE_NULL",
|
|
"LEXER_NODE_CAT",
|
|
"LEXER_NODE_OR",
|
|
"LEXER_NODE_STAR",
|
|
"LEXER_NODE_PLUS",
|
|
"LEXER_NODE_OPTIONAL",
|
|
"LEXER_NODE_SYMBOL",
|
|
"LEXER_NODE_ACTION"
|
|
};
|
|
|
|
RegexNode* node = i->get();
|
|
SWEET_ASSERT( node != NULL );
|
|
|
|
for ( int i = 0; i < level; ++i )
|
|
{
|
|
printf( " " );
|
|
}
|
|
|
|
printf( "%d, %s, %s, [%d, %d), nullable=%s", node->get_index(), LEXER_NODE_TYPES[node->get_type()], node->get_lexeme(), node->get_begin_character(), node->get_end_character(), node->is_nullable() ? "true" : "false" );
|
|
printf( ", first={" );
|
|
print_positions( node->get_first_positions() );
|
|
printf( "}, last={" );
|
|
print_positions( node->get_last_positions() );
|
|
printf( "}, follow={" );
|
|
print_positions( node->get_follow_positions() );
|
|
printf( "}\n" );
|
|
|
|
if ( !node->get_nodes().empty() )
|
|
{
|
|
print_nodes( node->get_nodes(), level + 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
// Calculate the combined parse tree for all of the literal and regular
|
|
// expression Symbols in \e symbols.
|
|
//
|
|
// @param symbols
|
|
// The Symbols to calculate the combined parse tree for.
|
|
*/
|
|
void RegexParser::calculate_combined_parse_tree( const std::vector<LexerToken>& tokens )
|
|
{
|
|
for ( vector<LexerToken>::const_iterator token = tokens.begin(); token != tokens.end(); ++token )
|
|
{
|
|
switch ( token->type() )
|
|
{
|
|
case TOKEN_REGULAR_EXPRESSION:
|
|
parse_regular_expression( *token );
|
|
break;
|
|
|
|
case TOKEN_LITERAL:
|
|
parse_literal( *token );
|
|
break;
|
|
|
|
case TOKEN_NULL:
|
|
default:
|
|
SWEET_ASSERT( false );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
// Calculate nullable, first positions, last positions, and follow positions
|
|
// for the regular expressions that have been parsed.
|
|
*/
|
|
void RegexParser::calculate_nullable_first_last_and_follow()
|
|
{
|
|
if ( !nodes_.empty() )
|
|
{
|
|
SWEET_ASSERT( nodes_.size() == 1 );
|
|
SWEET_ASSERT( nodes_.back() );
|
|
|
|
ptr<RegexNode> node( nodes_.back() );
|
|
node->calculate_nullable();
|
|
node->calculate_first_positions();
|
|
node->calculate_last_positions();
|
|
node->calculate_follow_positions();
|
|
}
|
|
}
|
|
|
|
/**
|
|
// Parse the regular expression [\e start, \e finish) for \e symbol.
|
|
//
|
|
// Parses the regular expression [\e start, \e finish) and combines it with
|
|
// all of the previously parsed regular expressions and literals using an or
|
|
// operator.
|
|
//
|
|
// @param token
|
|
// The LexerToken that defines the regular expression to parse.
|
|
*/
|
|
void RegexParser::parse_regular_expression( const LexerToken& token )
|
|
{
|
|
SWEET_ASSERT( token.type() == TOKEN_REGULAR_EXPRESSION );
|
|
SWEET_ASSERT( !token.lexeme().empty() );
|
|
|
|
//
|
|
// Create position iterators for the beginning and end of the sequence that
|
|
// will be parsed.
|
|
//
|
|
const std::string& regular_expression = token.lexeme();
|
|
typedef boost::spirit::position_iterator<const char*> iterator;
|
|
iterator first( regular_expression.c_str(), regular_expression.c_str() + regular_expression.length() );
|
|
iterator last;
|
|
|
|
//
|
|
// Parse the regular expression.
|
|
//
|
|
using namespace boost;
|
|
RegexGrammar<iterator> grammar( this );
|
|
spirit::parse_info<iterator> info = spirit::parse( first, last, grammar );
|
|
if ( !info.hit || !info.full )
|
|
{
|
|
++errors_;
|
|
SWEET_ASSERT( lexer_generator_ );
|
|
lexer_generator_->fire_error( token.line(), SyntaxError("Syntax error in regular expression '%s'", token.lexeme().c_str()) );
|
|
nodes_.clear();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Add the end character to the regular expression that has just been parsed
|
|
// and then combine that regular expression with any literals or regular
|
|
// expressions that have been previously parsed using an or expression.
|
|
//
|
|
SWEET_ASSERT( nodes_.size() == 1 || nodes_.size() == 2 );
|
|
SWEET_ASSERT( nodes_.back() );
|
|
ptr<RegexNode> node = regex_node( INVALID_BEGIN_CHARACTER, INVALID_END_CHARACTER, &token );
|
|
nodes_.push_back( node );
|
|
cat_expression();
|
|
while ( nodes_.size() > 1 )
|
|
{
|
|
or_expression();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
// Parse the literal [\e start, \e finish) for \e symbol.
|
|
//
|
|
// Parses the literal [\e start, \e finish) and combines it with all of the
|
|
// previously parsed regular expressions and literals using an or operator.
|
|
//
|
|
// @param start
|
|
// The first character in the literal to parse.
|
|
//
|
|
// @param finish
|
|
// One past the last character in the literal to parse.
|
|
//
|
|
// @param matched_symbol
|
|
// The symbol that represents the token that the literal matches.
|
|
*/
|
|
void RegexParser::parse_literal( const LexerToken& token )
|
|
{
|
|
SWEET_ASSERT( token.type() == TOKEN_LITERAL );
|
|
SWEET_ASSERT( !token.lexeme().empty() );
|
|
SWEET_ASSERT( token.symbol() );
|
|
|
|
//
|
|
// Combine all characters in \e literal using cat expressions.
|
|
//
|
|
const std::string& literal = token.lexeme();
|
|
std::string::const_iterator i = literal.begin();
|
|
int character = escape( i, literal.end(), &i );
|
|
ptr<RegexNode> node = regex_node( character, character + 1 );
|
|
nodes_.push_back( node );
|
|
++i;
|
|
|
|
while ( i != literal.end() )
|
|
{
|
|
int character = escape( i, literal.end(), &i );
|
|
node = regex_node( character, character + 1 );
|
|
nodes_.push_back( node );
|
|
cat_expression();
|
|
++i;
|
|
}
|
|
|
|
//
|
|
// Add the end character to the literal that has just been parsed and then
|
|
// combine that literal with any literals or regular expressions that have
|
|
// been previously parsed using an or expression.
|
|
//
|
|
SWEET_ASSERT( nodes_.size() == 1 || nodes_.size() == 2 );
|
|
SWEET_ASSERT( nodes_.back().get() != NULL );
|
|
node = regex_node( INVALID_BEGIN_CHARACTER, INVALID_END_CHARACTER, &token );
|
|
nodes_.push_back( node );
|
|
cat_expression();
|
|
while ( nodes_.size() > 1 )
|
|
{
|
|
or_expression();
|
|
}
|
|
}
|
|
|
|
/**
|
|
// The first character in [\e start, \e end) to its potentially escaped
|
|
// character equivalent.
|
|
//
|
|
// @param start
|
|
// The iterator to the first character to convert from.
|
|
//
|
|
// @param end
|
|
// One past the last character to convert from.
|
|
//
|
|
// @param next
|
|
// An iterator to update to the position after the potentially escaped
|
|
// character.
|
|
//
|
|
// @return
|
|
// The character value.
|
|
*/
|
|
int RegexParser::escape( std::string::const_iterator start, std::string::const_iterator end, std::string::const_iterator* next ) const
|
|
{
|
|
int character = *start;
|
|
if ( character == '\\' )
|
|
{
|
|
++start;
|
|
if ( start != end )
|
|
{
|
|
switch ( *start )
|
|
{
|
|
case 'b':
|
|
character = '\b';
|
|
break;
|
|
|
|
case 'f':
|
|
character = '\f';
|
|
break;
|
|
|
|
case 'n':
|
|
character = '\n';
|
|
break;
|
|
|
|
case 'r':
|
|
character = '\r';
|
|
break;
|
|
|
|
case 't':
|
|
character = '\t';
|
|
break;
|
|
|
|
case 'x':
|
|
case 'X':
|
|
SWEET_ASSERT( false );
|
|
break;
|
|
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
SWEET_ASSERT( false );
|
|
break;
|
|
|
|
default:
|
|
character = *start;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SWEET_ASSERT( next );
|
|
*next = start;
|
|
|
|
return character;
|
|
}
|
|
|
|
/**
|
|
// Insert characters in the interval [\e begin, \e end) into the current
|
|
// set of bracket expression characters.
|
|
//
|
|
// @param begin
|
|
// The first character in the interval of characters to insert.
|
|
//
|
|
// @param end
|
|
// One past the last character in the interval of characters to insert.
|
|
*/
|
|
void RegexParser::insert_characters( int begin, int end )
|
|
{
|
|
std::pair<set<RegexCharacter>::iterator, bool> result = bracket_expression_characters_.insert( RegexCharacter(begin, end) );
|
|
while ( !result.second )
|
|
{
|
|
SWEET_ASSERT( result.first->get_end_character() >= begin || end >= result.first->get_begin_character() );
|
|
begin = std::min( begin, result.first->get_begin_character() );
|
|
end = std::max( end, result.first->get_end_character() );
|
|
bracket_expression_characters_.erase( result.first );
|
|
result = bracket_expression_characters_.insert( RegexCharacter(begin, end) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
// Remove characters in the interval [\e begin, \e end) from the current
|
|
// set of bracket expression characters.
|
|
//
|
|
// @param begin
|
|
// The first character in the interval of characters to remove.
|
|
//
|
|
// @param end
|
|
// One past the last character in the interval of characters to remove.
|
|
*/
|
|
void RegexParser::erase_characters( int begin, int end )
|
|
{
|
|
set<RegexCharacter>::iterator i = bracket_expression_characters_.find( RegexCharacter(begin, end) );
|
|
if ( i != bracket_expression_characters_.end() )
|
|
{
|
|
int pre_begin = i->get_begin_character();
|
|
int pre_end = begin;
|
|
|
|
int post_begin = end;
|
|
int post_end = i->get_end_character();
|
|
|
|
bracket_expression_characters_.erase( i );
|
|
|
|
if ( pre_begin < pre_end )
|
|
{
|
|
bool inserted = bracket_expression_characters_.insert( RegexCharacter(pre_begin, pre_end) ).second;
|
|
SWEET_ASSERT( inserted );
|
|
}
|
|
|
|
if ( post_begin < post_end )
|
|
{
|
|
bool inserted = bracket_expression_characters_.insert( RegexCharacter(post_begin, post_end) ).second;
|
|
SWEET_ASSERT( inserted );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
// Insert the characters in \e characters into the current set of bracket
|
|
// expression characters.
|
|
//
|
|
// @param characters
|
|
// A nul terminated string that contains the characters to insert.
|
|
*/
|
|
void RegexParser::insert_characters( const char* characters )
|
|
{
|
|
SWEET_ASSERT( characters );
|
|
const char* character = characters;
|
|
while ( *character != '\0' )
|
|
{
|
|
insert_characters( *character, *character + 1 );
|
|
++character;
|
|
}
|
|
}
|
|
|
|
/**
|
|
// Remove the characters in \e characters from the current set of bracket
|
|
// expression characters.
|
|
//
|
|
// @param characters
|
|
// A nul terminated string that contains the characters to remove.
|
|
*/
|
|
void RegexParser::erase_characters( const char* characters )
|
|
{
|
|
const char* character = characters;
|
|
while ( *character != '\0' )
|
|
{
|
|
erase_characters( *character, *character + 1 );
|
|
++character;
|
|
}
|
|
}
|