Commit ef676368 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'trac4271' (vendor options support in classification)

# Conflicts:
#	src/lib/eval/lexer.cc
#	src/lib/eval/lexer.ll
#	src/lib/eval/location.hh
#	src/lib/eval/parser.cc
#	src/lib/eval/parser.h
#	src/lib/eval/parser.yy
#	src/lib/eval/position.hh
#	src/lib/eval/stack.hh
#	src/lib/eval/tests/context_unittest.cc
#	src/lib/eval/tests/token_unittest.cc
#	src/lib/eval/token.cc
#	src/lib/eval/token.h
parents 2edbac43 4d93fc32
......@@ -202,7 +202,7 @@
-->
<row>
<entry>Option existence</entry>
<entry>option[123].exist</entry>
<entry>option[123].exists</entry>
<entry>'true'</entry>
<entry>If the option with given code is present in the
packet "true" else "false"</entry>
......@@ -315,6 +315,88 @@
<entry>The value of the transaction id in the DHCPv6
packet.</entry>
</row>
<row>
<entry>Vendor option existence (any vendor)</entry>
<entry>vendor[*].exists</entry>
<entry>true</entry>
<entry>Returns whether a vendor option from any vendor
is present ('true') or absent ('false').</entry>
</row>
<row>
<entry>Vendor option existence (specific vendor)</entry>
<entry>vendor[4491].exists</entry>
<entry>true</entry>
<entry>Returns whether a vendor option from specified
vendor (determined by its enterprise-id)
is present ('true') or absent ('false').</entry>
</row>
<row>
<entry>Enterprise-id from vendor option</entry>
<entry>vendor.enterprise</entry>
<entry>0x0000118b</entry>
<entry>If the vendor option is present, it returns the
value of the enterprise-id field padded to 4
bytes. Returns '' otherwise.</entry>
</row>
<row>
<entry>Vendor sub-option existence</entry>
<entry>vendor[4491].option[1].exists</entry>
<entry>true</entry>
<entry>Returns 'true' if there is vendor option with
specified enterprise-id and given sub-option is present.
Returns 'false' otherwise.</entry>
</row>
<row>
<entry>Vendor sub-option content</entry>
<entry>vendor[4491].option[1].hex</entry>
<entry>docsis3.0</entry>
<entry>Returns content of the specified sub-option of
a vendor option with specified enterprise id. Returns
'' if no such option or sub-option is present.
</entry>
</row>
<row>
<entry>Vendor class option existence (any vendor)</entry>
<entry>vendor-class[*].exists</entry>
<entry>true</entry>
<entry>Returns whether a vendor class option from any vendor
is present ('true') or absent ('false').</entry>
</row>
<row>
<entry>Vendor class option existence (specific vendor)</entry>
<entry>vendor-class[4491].exists</entry>
<entry>true</entry>
<entry>Returns whether a vendor class option from specified
vendor (determined by its enterprise-id)
is present ('true') or absent ('false').</entry>
</row>
<row>
<entry>Enterprise-id from vendor class option</entry>
<entry>vendor-class.enterprise</entry>
<entry>0x0000118b</entry>
<entry>If the vendor option is present, it returns the
value of the enterprise-id field padded to 4
bytes. Returns '' otherwise.</entry>
</row>
<row>
<entry>First data chunk from vendor class option</entry>
<entry>vendor-class[4491].data</entry>
<entry>docsis3.0</entry>
<entry>Returns content of the first data chunk from
the vendor class option with specified enterprise-id.
Returns '' if missing.</entry>
</row>
<row>
<entry>Specific data chunk from vendor class option</entry>
<entry>vendor-class[4491].data[3]</entry>
<entry>docsis3.0</entry>
<entry>Returns content of the specified data chunk of
a vendor class option with specified enterprise id. Returns
'' if no such option or data chunk is present.
</entry>
</row>
</tbody>
</tgroup>
</table>
......@@ -341,7 +423,7 @@
</para>
<para>
"option[code].exist" checks if an option with the code "code" is present
"option[code].exists" checks if an option with the code "code" is present
in the incoming packet. It can be used with empty options.
</para>
......@@ -387,6 +469,33 @@
"0x00000001" or simply 1 as in "pkt6.msgtype == 1".
</para>
<para>
Vendor option means Vendor-Identifying Vendor-specific Information
option (code 125, see Section 4 of RFC3925) in DHCPv4 and
Vendor-specific Information Option (code 17, defined in Section 22.17 of
RFC3315) in DHCPv6. Vendor class option means Vendor-Identifying Vendor
Class Option (code 124, see Section 3 of RFC3925) in DHCPv4 and Vendor
Class Option (code 16, see Section 22.16 of RFC3315). Vendor options may
have sub-options that are referenced by their codes. Vendor class
options do not have sub-options, but rather data chunks, which are
referenced by index value. Index 0 means the first data chunk, Index 1
is for the second data chunk (if present), etc.
</para>
<para>In the vendor and vendor-class constructs Asterisk (*) or 0 can be
used to specify a wildcard enterprise-id value, i.e. it will match any
enterprise-id value.</para>
<para>Vendor Class Identifier (option 60 in DHCPv4) can be
accessed using option[60] expression.</para>
<para>RFC3925 and RFC3315 allow for multiple instances of vendor options
to appear in a single message. The client classification code currently
examines the first instance if more than one appear. For vendor.enterprise
and vendor-class.enterprise expressions, the value from the first instance
is returned. Please submit a feature request on Kea website if you need
support for multiple instances.</para>
<para>
<table frame="all" id="classification-expressions-list">
<title>List of Classification Expressions</title>
......@@ -407,7 +516,8 @@
<row><entry>And</entry> <entry>('foo' == 'bar') and ('bar' == 'foo')</entry><entry>Logical and</entry></row>
<row><entry>Or</entry> <entry>('foo' == 'bar') or ('bar' == 'foo')</entry><entry>Logical or</entry></row>
<row><entry>Substring</entry><entry>substring('foobar',0,3)</entry><entry>Return the requested substring</entry></row>
<row><entry>Concat</entry><entry>concat('foo','bar')</entry><entry>Return the concatenation of the strings</entry></row>
<row><entry>Concat</entry><entry>concat('foo','bar')</entry><entry>Return the
concatenation of the strings</entry></row>
</tbody>
</tgroup>
</table>
......
......@@ -3583,9 +3583,6 @@ src/lib/dhcpsrv/cfg_host_operations.cc -->
<listitem>
<simpara>Host reservation (static addresses) is not supported yet.</simpara>
</listitem>
<listitem>
<simpara>Full featured client classification is not supported yet.</simpara>
</listitem>
<listitem>
<simpara>
BOOTP (<ulink url="http://tools.ietf.org/html/rfc951">RFC 951</ulink>)
......@@ -3609,9 +3606,6 @@ src/lib/dhcpsrv/cfg_host_operations.cc -->
allocating server should verify that address is not used by
sending ICMP echo request.</simpara>
</listitem>
<listitem>
<simpara>Address duplication report (DECLINE) is not supported yet.</simpara>
</listitem>
</itemizedlist>
</section>
......
......@@ -3828,8 +3828,7 @@ should include options from the isc option space:
<listitem>
<simpara>
Duplication report (DECLINE) and client reconfiguration (RECONFIGURE) are
not yet supported.
Client reconfiguration (RECONFIGURE) is not yet supported.
</simpara>
</listitem>
</itemizedlist>
......
......@@ -85,6 +85,11 @@ parser: lexer.cc location.hh position.hh stack.hh parser.cc parser.h
@echo "Flex/bison files regenerated"
# --- Flex/Bison stuff below --------------------------------------------------
# When debugging grammar issues, it's useful to add -v to bison parameters.
# bison will generate parser.output file that explains the whole grammar.
# It can be used to manually follow what's going on in the parser.
# This is especially useful if yydebug_ is set to 1 as that variable
# will cause parser to print out its internal state.
location.hh position.hh stack.hh parser.cc parser.h: parser.yy
$(YACC) --defines=parser.h -o parser.cc parser.yy
......
......@@ -13,6 +13,7 @@
#include <exceptions/exceptions.h>
#include <boost/lexical_cast.hpp>
#include <fstream>
#include <limits>
EvalContext::EvalContext(const Option::Universe& option_universe)
: trace_scanning_(false), trace_parsing_(false),
......@@ -97,14 +98,9 @@ uint8_t
EvalContext::convertNestLevelNumber(const std::string& nest_level,
const isc::eval::location& loc)
{
int n = 0;
try {
n = boost::lexical_cast<int>(nest_level);
} catch (const boost::bad_lexical_cast &) {
error(loc, "Nest level has invalid value in " + nest_level);
}
uint8_t n = convertUint8(nest_level, loc);
if (option_universe_ == Option::V6) {
if (n < 0 || n >= HOP_COUNT_LIMIT) {
if (n >= HOP_COUNT_LIMIT) {
error(loc, "Nest level has invalid value in "
+ nest_level + ". Allowed range: 0..31");
}
......@@ -112,9 +108,44 @@ EvalContext::convertNestLevelNumber(const std::string& nest_level,
error(loc, "Nest level invalid for DHCPv4 packets");
}
return (n);
}
uint8_t
EvalContext::convertUint8(const std::string& number,
const isc::eval::location& loc)
{
int n = 0;
try {
n = boost::lexical_cast<int>(number);
} catch (const boost::bad_lexical_cast &) {
error(loc, "Invalid integer value in " + number);
}
if (n < 0 || n >= std::numeric_limits<uint8_t>::max()) {
error(loc, "Invalid value in "
+ number + ". Allowed range: 0..255");
}
return (static_cast<uint8_t>(n));
}
uint32_t
EvalContext::convertUint32(const std::string& number,
const isc::eval::location& loc)
{
uint64_t n = 0;
try {
n = boost::lexical_cast<uint64_t>(number);
} catch (const boost::bad_lexical_cast &) {
error(loc, "Invalid value in " + number);
}
if (n >= std::numeric_limits<uint32_t>::max()) {
error(loc, "Invalid value in "
+ number + ". Allowed range: 0..4294967295");
}
return (static_cast<uint32_t>(n));
}
void
EvalContext::fatal (const std::string& what)
......
......@@ -96,16 +96,34 @@ public:
///
/// @param option_name the option name
/// @param loc the location of the token
/// @result the option code
/// @return the option code
/// @throw calls the syntax error function if the name cannot be resolved
uint16_t convertOptionName(const std::string& option_name,
const isc::eval::location& loc);
/// @brief Attempts to convert string to unsigned 32bit integer
///
/// @param number string to be converted
/// @param loc the location of the token
/// @return the integer value
/// @throw EvalParseError if conversion fails or the value is out of range.
uint32_t convertUint32(const std::string& number,
const isc::eval::location& loc);
/// @brief Attempts to convert string to unsigned 8bit integer
///
/// @param number string to be converted
/// @param loc the location of the token
/// @return the integer value
/// @throw EvalParseError if conversion fails or the value is out of range.
uint8_t convertUint8(const std::string& number,
const isc::eval::location& loc);
/// @brief Nest level conversion
///
/// @param nest_level a string representing the integer nesting level
/// @param loc the location of the token
/// @result the nesting level
/// @return the nesting level
/// @throw calls the syntax error function if the value is not in
/// the range 0..31
uint8_t convertNestLevelNumber(const std::string& nest_level,
......
......@@ -113,6 +113,51 @@ string and an empty result will be pushed onto the stack. The start,
length and string are still popped from the stack and the result is
still pushed. The strings are displayed in hex.
% EVAL_DEBUG_VENDOR_CLASS_DATA Data %1 (out of %2 received) in vendor class found, pushing result '%3'
This debug message indicates that vendor class option was found and passed
enterprise-id checks and has sufficient number of data chunks. The total number
of chunks and value pushed are reported as debugging aid.
% EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index %1, but option with enterprise-id %2 has only %3 data tuple(s), pushing result '%4'
This debug message indicates that vendor class option was found and passed
enterprise-id checks, but does not have sufficient number of data chunks.
Note that the index starts at 0, so there has to be at least (index + 1)
data chunks.
% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id %1 as result 0x%2
This debug message indicates that the expression has been evaluated and vendor
class option was found and its enterprise-id is being reported.
% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for %1, option had %2, pushing result '%3'
This debug message indicates that the expression has been evaluated
and vendor class option was found, but has different enterprise-id than specified
in the expression.
% EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id %1 found, pushing result '%2'
This debug message indicates that the expression has been evaluated and vendor
class option was found.
% EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code %1 missing, pushing result '%2'
This debug message indicates that the expression has been evaluated
and vendor class option was not found.
% EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id %1 as result 0x%2
This debug message indicates that the expression has been evaluated and vendor
option was found and its enterprise-id is being reported.
% EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for %1, option had %2, pushing result '%3'
This debug message indicates that the expression has been evaluated
and vendor option was found, but has different enterprise-id than specified
in the expression.
% EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id %1 found, pushing result '%2'
This debug message indicates that the expression has been evaluated and vendor
option was found.
% EVAL_DEBUG_VENDOR_NO_OPTION Option with code %1 missing, pushing result '%2'
This debug message indicates that the expression has been evaluated
and vendor option was not found.
% EVAL_RESULT Expression %1 evaluated to %2
This debug message indicates that the expression has been evaluated
to said value. This message is mostly useful during debugging of the
......
This diff is collapsed.
......@@ -140,44 +140,48 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]*
return isc::eval::EvalParser::make_IP_ADDRESS(yytext, loc);
}
"==" return isc::eval::EvalParser::make_EQUAL(loc);
"option" return isc::eval::EvalParser::make_OPTION(loc);
"relay4" return isc::eval::EvalParser::make_RELAY4(loc);
"relay6" return isc::eval::EvalParser::make_RELAY6(loc);
"peeraddr" return isc::eval::EvalParser::make_PEERADDR(loc);
"linkaddr" return isc::eval::EvalParser::make_LINKADDR(loc);
"text" return isc::eval::EvalParser::make_TEXT(loc);
"hex" return isc::eval::EvalParser::make_HEX(loc);
"exists" return isc::eval::EvalParser::make_EXISTS(loc);
"pkt" return isc::eval::EvalParser::make_PKT(loc);
"iface" return isc::eval::EvalParser::make_IFACE(loc);
"src" return isc::eval::EvalParser::make_SRC(loc);
"dst" return isc::eval::EvalParser::make_DST(loc);
"len" return isc::eval::EvalParser::make_LEN(loc);
"pkt4" return isc::eval::EvalParser::make_PKT4(loc);
"mac" return isc::eval::EvalParser::make_CHADDR(loc);
"hlen" return isc::eval::EvalParser::make_HLEN(loc);
"htype" return isc::eval::EvalParser::make_HTYPE(loc);
"ciaddr" return isc::eval::EvalParser::make_CIADDR(loc);
"giaddr" return isc::eval::EvalParser::make_GIADDR(loc);
"yiaddr" return isc::eval::EvalParser::make_YIADDR(loc);
"siaddr" return isc::eval::EvalParser::make_SIADDR(loc);
"pkt6" return isc::eval::EvalParser::make_PKT6(loc);
"msgtype" return isc::eval::EvalParser::make_MSGTYPE(loc);
"transid" return isc::eval::EvalParser::make_TRANSID(loc);
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
"all" return isc::eval::EvalParser::make_ALL(loc);
"concat" return isc::eval::EvalParser::make_CONCAT(loc);
"not" return isc::eval::EvalParser::make_NOT(loc);
"and" return isc::eval::EvalParser::make_AND(loc);
"or" return isc::eval::EvalParser::make_OR(loc);
"." return isc::eval::EvalParser::make_DOT(loc);
"(" return isc::eval::EvalParser::make_LPAREN(loc);
")" return isc::eval::EvalParser::make_RPAREN(loc);
"[" return isc::eval::EvalParser::make_LBRACKET(loc);
"]" return isc::eval::EvalParser::make_RBRACKET(loc);
"," return isc::eval::EvalParser::make_COMA(loc);
"==" return isc::eval::EvalParser::make_EQUAL(loc);
"option" return isc::eval::EvalParser::make_OPTION(loc);
"relay4" return isc::eval::EvalParser::make_RELAY4(loc);
"relay6" return isc::eval::EvalParser::make_RELAY6(loc);
"peeraddr" return isc::eval::EvalParser::make_PEERADDR(loc);
"linkaddr" return isc::eval::EvalParser::make_LINKADDR(loc);
"text" return isc::eval::EvalParser::make_TEXT(loc);
"hex" return isc::eval::EvalParser::make_HEX(loc);
"exists" return isc::eval::EvalParser::make_EXISTS(loc);
"pkt" return isc::eval::EvalParser::make_PKT(loc);
"iface" return isc::eval::EvalParser::make_IFACE(loc);
"src" return isc::eval::EvalParser::make_SRC(loc);
"dst" return isc::eval::EvalParser::make_DST(loc);
"len" return isc::eval::EvalParser::make_LEN(loc);
"pkt4" return isc::eval::EvalParser::make_PKT4(loc);
"mac" return isc::eval::EvalParser::make_CHADDR(loc);
"hlen" return isc::eval::EvalParser::make_HLEN(loc);
"htype" return isc::eval::EvalParser::make_HTYPE(loc);
"ciaddr" return isc::eval::EvalParser::make_CIADDR(loc);
"giaddr" return isc::eval::EvalParser::make_GIADDR(loc);
"yiaddr" return isc::eval::EvalParser::make_YIADDR(loc);
"siaddr" return isc::eval::EvalParser::make_SIADDR(loc);
"pkt6" return isc::eval::EvalParser::make_PKT6(loc);
"msgtype" return isc::eval::EvalParser::make_MSGTYPE(loc);
"transid" return isc::eval::EvalParser::make_TRANSID(loc);
"vendor" return isc::eval::EvalParser::make_VENDOR(loc);
"vendor-class" return isc::eval::EvalParser::make_VENDOR_CLASS(loc);
"data" return isc::eval::EvalParser::make_DATA(loc);
"enterprise" return isc::eval::EvalParser::make_ENTERPRISE(loc);
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
"all" return isc::eval::EvalParser::make_ALL(loc);
"concat" return isc::eval::EvalParser::make_CONCAT(loc);
"not" return isc::eval::EvalParser::make_NOT(loc);
"and" return isc::eval::EvalParser::make_AND(loc);
"or" return isc::eval::EvalParser::make_OR(loc);
"." return isc::eval::EvalParser::make_DOT(loc);
"(" return isc::eval::EvalParser::make_LPAREN(loc);
")" return isc::eval::EvalParser::make_RPAREN(loc);
"[" return isc::eval::EvalParser::make_LBRACKET(loc);
"]" return isc::eval::EvalParser::make_RBRACKET(loc);
"," return isc::eval::EvalParser::make_COMA(loc);
"*" return isc::eval::EvalParser::make_ANY(loc);
. driver.error (loc, "Invalid character: " + std::string(yytext));
<<EOF>> return isc::eval::EvalParser::make_END(loc);
%%
......
// Generated 201608161508
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++
......
This diff is collapsed.
......@@ -320,8 +320,11 @@ namespace isc { namespace eval {
// option_code
char dummy7[sizeof(uint16_t)];
// enterprise_id
char dummy8[sizeof(uint32_t)];
// nest_level
char dummy8[sizeof(uint8_t)];
char dummy9[sizeof(uint8_t)];
};
/// Symbol semantic values.
......@@ -375,18 +378,23 @@ namespace isc { namespace eval {
TOKEN_GIADDR = 285,
TOKEN_YIADDR = 286,
TOKEN_SIADDR = 287,
TOKEN_PKT6 = 288,
TOKEN_MSGTYPE = 289,
TOKEN_TRANSID = 290,
TOKEN_SUBSTRING = 291,
TOKEN_ALL = 292,
TOKEN_COMA = 293,
TOKEN_CONCAT = 294,
TOKEN_STRING = 295,
TOKEN_INTEGER = 296,
TOKEN_HEXSTRING = 297,
TOKEN_OPTION_NAME = 298,
TOKEN_IP_ADDRESS = 299
TOKEN_SUBSTRING = 288,
TOKEN_ALL = 289,
TOKEN_COMA = 290,
TOKEN_CONCAT = 291,
TOKEN_PKT6 = 292,
TOKEN_MSGTYPE = 293,
TOKEN_TRANSID = 294,
TOKEN_VENDOR_CLASS = 295,
TOKEN_VENDOR = 296,
TOKEN_ANY = 297,
TOKEN_DATA = 298,
TOKEN_ENTERPRISE = 299,
TOKEN_STRING = 300,
TOKEN_INTEGER = 301,
TOKEN_HEXSTRING = 302,
TOKEN_OPTION_NAME = 303,
TOKEN_IP_ADDRESS = 304
};
};
......@@ -438,6 +446,8 @@ namespace isc { namespace eval {
basic_symbol (typename Base::kind_type t, const uint16_t v, const location_type& l);
basic_symbol (typename Base::kind_type t, const uint32_t v, const location_type& l);
basic_symbol (typename Base::kind_type t, const uint8_t v, const location_type& l);
......@@ -631,6 +641,22 @@ namespace isc { namespace eval {
symbol_type
make_SIADDR (const location_type& l);
static inline
symbol_type
make_SUBSTRING (const location_type& l);
static inline
symbol_type
make_ALL (const location_type& l);
static inline
symbol_type
make_COMA (const location_type& l);
static inline
symbol_type
make_CONCAT (const location_type& l);
static inline
symbol_type
make_PKT6 (const location_type& l);
......@@ -645,19 +671,23 @@ namespace isc { namespace eval {
static inline
symbol_type
make_SUBSTRING (const location_type& l);
make_VENDOR_CLASS (const location_type& l);
static inline
symbol_type
make_ALL (const location_type& l);
make_VENDOR (const location_type& l);
static inline
symbol_type
make_COMA (const location_type& l);
make_ANY (const location_type& l);
static inline
symbol_type
make_CONCAT (const location_type& l);
make_DATA (const location_type& l);
static inline
symbol_type
make_ENTERPRISE (const location_type& l);
static inline
symbol_type
......@@ -746,7 +776,7 @@ namespace isc { namespace eval {
// Tables.
// YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
// STATE-NUM.
static const signed char yypact_[];
static const short int yypact_[];
// YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
// Performed when YYTABLE does not specify something else to do. Zero
......@@ -757,14 +787,14 @@ namespace isc { namespace eval {
static const signed char yypgoto_[];
// YYDEFGOTO[NTERM-NUM].
static const signed char yydefgoto_[];
static const short int yydefgoto_[];
// YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
// positive, shift that token. If negative, reduce the rule whose
// number is the opposite. If YYTABLE_NINF, syntax error.
static const unsigned char yytable_[];
static const signed char yycheck_[];
static const short int yycheck_[];
// YYSTOS[STATE-NUM] -- The (internal number of the) accessing
// symbol of state STATE-NUM.
......@@ -884,12 +914,12 @@ namespace isc { namespace eval {
enum
{
yyeof_ = 0,
yylast_ = 121, ///< Last index in yytable_.
yynnts_ = 13, ///< Number of nonterminal symbols.
yyfinal_ = 27, ///< Termination state number.
yylast_ = 171, ///< Last index in yytable_.
yynnts_ = 14, ///< Number of nonterminal symbols.
yyfinal_ = 33, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
yyntokens_ = 45 ///< Number of tokens.
yyntokens_ = 50 ///< Number of tokens.
};
......@@ -935,9 +965,10 @@ namespace isc { namespace eval {
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44
35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49
};
const unsigned int user_token_number_max_ = 299;
const unsigned int user_token_number_max_ = 304;
const token_number_type undef_token_ = 2;
if (static_cast<int>(t) <= yyeof_)
......@@ -9