### Declare and Use Start Conditions Source: https://www.genivia.com/doc/reflex/html/index.html Example of declaring inclusive and exclusive start conditions and applying them to rules. ```text %s A %x X %% pattern1 action1 // rule for states A and X pattern2 action2 // rule for state A pattern3 action3 // rule for state X <*>pattern4 action4 // rule for states INITIAL, A and X pattern5 action5 // rule for states INITIAL and A <> action6 // rule for states INITIAL, A and X %% ``` -------------------------------- ### Nest Start Condition Scopes Source: https://www.genivia.com/doc/reflex/html/index.html Example of nesting start condition scopes to combine active states. ```text %s A %x X %% pattern action // rule for states INITIAL and A { pattern action // rule for state A { pattern action // rule for states A and X } } { pattern action // rule for state X { pattern action // rule for states A and X } } %% ``` -------------------------------- ### Flex-compatible BEGIN macro Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Sets a start condition. ```cpp #define BEGIN YY_SCANNER_DOT_ start_ = ``` -------------------------------- ### Define YYSTATE macro Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Get the current start condition. ```cpp #define YYSTATE YY_SCANNER_DOT_ start() ``` -------------------------------- ### Switch Start Condition States Source: https://www.genivia.com/doc/reflex/html/index.html Using start() to transition between states, such as entering a comment block. ```text %x COMMENT %% "/*" start(COMMENT); // with −−flex use: BEGIN COMMENT; .|\n echo(); // with −−flex use: ECHO; [^*]* // eat anything that is not a '*' "*"+[^*/]* // eat '*'s not followed by a '/' "*"+"/" start(INITIAL); <> std::cerr << "EOF in comment\n"; return 1; %% ``` -------------------------------- ### Initializing the Bison Parser Source: https://www.genivia.com/doc/reflex/html/index.html Example of how to instantiate the lexer and parser in a C++ main program. ```cpp FILE *f = fopen(filename, "r"); if (f != NULL) { yy::Lexer lexer(f); // read file, decode UTF-8/16/32 format lexer.filename = filename; // the filename to display with error locations yy::parser parser(lexer); if (parser.parse() != 0) ... // error ``` -------------------------------- ### Use Start Condition Scopes Source: https://www.genivia.com/doc/reflex/html/index.html Grouping multiple rules under a single start condition scope. ```text { [^*]* // eat anything that is not a '*' "*"+[^*/]* // eat '*'s not followed by a '/' "*"+"/" start(INITIAL); <> std::cerr << "EOF in comment\n"; return 1; } ``` -------------------------------- ### Configure Bison Parser for Combined Bridge and Locations Source: https://www.genivia.com/doc/reflex/html/index.html Example of a Bison grammar file setup combining both --bison-bridge and --bison-locations options. ```c /* yacc grammar (.y file) for C or C++ */ %{ #include "lex.yy.h" void yyerror(YYLTYPE*, yyscan_t, const char*); #define YYPARSE_PARAM scanner #define YYLEX_PARAM scanner %} %locations %pure-parser %lex-param { void *scanner } %parse-param { void *scanner } %union { // YYSTYPE yylval is a union: int num; // yylval.num char* str; // yylval.str } %token CONST_NUMBER %token CONST_STRING %% ... // grammar rules %% void yyerror(YYLTYPE *yylloc, yyscan_t scanner, const char *msg) { fprintf(stderr, "%s at %d,%d to line %d,%d\n", msg, yylloc->first_line, yylloc->first_column, yylloc->last_line, yylloc->last_column); } ``` -------------------------------- ### Define Start Condition Rules Source: https://www.genivia.com/doc/reflex/html/index.html Basic syntax for prefixing patterns with start condition states. ```text pattern1 action1 pattern2 action2 pattern3 action3 ``` -------------------------------- ### Manage Start Condition Stack Source: https://www.genivia.com/doc/reflex/html/index.html Using push_state and pop_state to handle nested or temporary state transitions. ```text %x COMMENT %% "/*" push_state(COMMENT); .|\n echo(); [^*]* // eat anything that is not a '*' "*"+[^*/]* // eat '*'s not followed by a '/' "*"+"/" pop_state(); <> std::cerr << "EOF in comment\n"; return 1; %% ``` -------------------------------- ### Switching Input Sources Source: https://www.genivia.com/doc/reflex/html/index.html Examples of switching input sources using files, streams, strings, and memory segments. ```cpp // read from a file, this also decodes UTF-8/16/32 encodings automatically FILE *fd = fopen("cow.txt", "r"); if (fd == NULL) ... // error, bail out lexer.in(fd); lexer.lex(); // read from a stream (ASCII or UTF-8) std::istream i = std::ifstream("file", std::ios::in); lexer.in(i); lexer.lex(); // read from a string (0-terminated, ASCII or UTF-8) lexer.in("How now brown cow."); lexer.lex(); // read from a memory segment (raw bytes, ASCII, or UTF-8) const char *ptr = ...; // points to segment size_t len = ...; // length of the memory segment lexer.in(ptr, len); lexer.lex(); // read from a wide string, 0-terminated, encoding it to UTF-8 for matching lexer.in(L"How now brown cow."); lexer.lex(); ``` -------------------------------- ### Flex-compatible state stack macros Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Manages the start condition state stack. ```cpp #define YY_NULL (0) ``` ```cpp #define yy_pop_state | ( | | ) | YY_SCANNER_DOT_ pop_state() ``` ```cpp #define yy_push_state | ( | | n| ) | YY_SCANNER_DOT_ push_state(n) ``` -------------------------------- ### Configure Bison Pure Parser for Bison-bridge Source: https://www.genivia.com/doc/reflex/html/index.html Example of a Bison grammar file setup for use with the --bison-bridge option. ```c /* yacc grammar (.y file) for C or C++ */ %{ #include "lex.yy.h" #define YYPARSE_PARAM scanner #define YYLEX_PARAM scanner %} %pure-parser %% ... // grammar rules %% ``` -------------------------------- ### Configure Bison Parser for Bison-locations Source: https://www.genivia.com/doc/reflex/html/index.html Example of a Bison grammar file setup for use with the --bison-locations option, including error reporting with line and column numbers. ```c /* yacc grammar (.y file) for C or C++ */ %{ #include "lex.yy.h" void yyerror(const char*); %} %locations %union { // YYSTYPE yylval is a union: int num; // type of yylval.num is int char* str; // type of yylval.str is char* } %{ /* reflex option −−bison-locations makes yylex() take yylval and yylloc */ extern int yylex(YYSTYPE*, YYLTYPE*); #define YYLEX_PARAM &yylval, &yylloc %} /* add &yylval and &yyloc parameters to yylex() with a trick: use YYLEX_PARAM */ %lex-param { void *YYLEX_PARAM } %token CONST_NUMBER %token CONST_STRING %% ... // grammar rules %% void yyerror(const char *msg) { fprintf(stderr, "%s at %d,%d to line %d,%d\n", msg, yylloc.first_line, yylloc.first_column, yylloc.last_line, yylloc.last_column); } ``` -------------------------------- ### Defining Start Condition Scopes Source: https://www.genivia.com/doc/reflex/html/index.html Demonstrates the use of start condition scopes and the ^ operator to remove states within nested and global contexts. ```reflex %s A B C %% { pattern action // rule for states B and C { pattern action // rule for states A and C } } <*,^A,^C>pattern action // rule for states INITIAL and B (all states except A and C) %% ``` -------------------------------- ### Debugging Example with Reflex Macros Source: https://www.genivia.com/doc/reflex/html/debug_8h.html Demonstrates the use of DBGLOG, DBGLOGA, DBGCHK, and DBGSTR macros within a C++ program. ```cpp #include int main(int argc, char *argv[]) { FILE *fd; DBGLOG("Program start"); if ((fd = fopen("foo.bar", "r")) == NULL) { DBGLOG("Error %d: %s ", errno, DBGSTR(strerror(errno))); for (int i = 1; i < argc; ++i) DBGLOGA(" %s", argv[1]); } else { DBGCHK(fd != NULL); // OK, so go ahead to read foo.bar ... // ... fclose(fd); } DBGLOG("Program end"); } ``` -------------------------------- ### Switching Input Sources for Standard Scanners Source: https://www.genivia.com/doc/reflex/html/index.html Examples of configuring input sources for standard lexers using files, streams, strings, and memory buffers. ```cpp // read from a file, this also decodes UTF-8/16/32 encodings automatically FILE *fd = fopen("cow.txt", "r"); if (fd == NULL) ... // error, bail out yyin = fd; yylex(); // read from a stream (ASCII or UTF-8) std::istream i = std::ifstream("file", std::ios::in); yyin = &i; yylex(); // read from a string (0-terminated, ASCII or UTF-8) yy_delete_buffer(YY_CURRENT_BUFFER); yy_scan_string("How now brown cow."); // new buffer to scan a string // yyin = "How now brown cow."; // alternative, does not create a new buffer yylex(); // read from a memory segment (raw bytes, ASCII, or UTF-8) const char *ptr = ...; // points to memory segment size_t len = ...; // length of the memory segment yy_delete_buffer(YY_CURRENT_BUFFER); yy_scan_bytes(ptr, len); // new buffer to scan memory yylex(); // read from a wide string, 0-terminated, encoding it to UTF-8 for matching yy_delete_buffer(YY_CURRENT_BUFFER); yy_scan_wstring(L"How now brown cow."); // new buffer to scan a wide string // yyin = L"How now brown cow."; // alternative, does not create a new buffer yylex(); ``` ```cpp // read a 0-terminated buffer in place, buffer content is changed!! char *base = ...; // points to 0-terminated buffer size_t size = ...; // length of the buffer including two final \0 bytes yy_delete_buffer(YY_CURRENT_BUFFER); yy_scan_buffer(base, size); yylex(); ``` -------------------------------- ### State and Matcher Control Macros Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Macros for managing start condition states and manipulating matched text. ```cpp #define yy_push_state(n) YY_SCANNER_DOT_ push_state(n) ``` ```cpp #define yy_pop_state() YY_SCANNER_DOT_ pop_state() ``` ```cpp #define yy_top_state() YY_SCANNER_DOT_ top_state() ``` ```cpp #define yymore() YY_SCANNER_DOT_ matcher().more() ``` ```cpp #define yyless(n) YY_SCANNER_DOT_ matcher().less(n) ``` ```cpp #define yy_flex_debug YY_SCANNER_DOT_ debug_; ``` -------------------------------- ### reflex::timer_start Source: https://www.genivia.com/doc/reflex/html/timer_8h.html Starts the timer by initializing the provided timer_type object. ```APIDOC ## void reflex::timer_start(timer_type &t) ### Description Starts the timer. ### Parameters - **t** (timer_type &) - The timer object to start. ``` -------------------------------- ### Declare start condition states Source: https://www.genivia.com/doc/reflex/html/index.html Define inclusive and exclusive start condition states using %state and %xstate. ```reflex %s INCLUSIVE %x EXCLUSIVE ``` -------------------------------- ### Batch Input Scanner Configuration Source: https://www.genivia.com/doc/reflex/html/index.html Example of specifying a buffer size for the batch scanner option. ```text --batch=1024 ``` -------------------------------- ### Define yylook macro Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Get the next action index. ```cpp #define yylook | ( | | ) | YY_SCANNER_DOT_ matcher().scan() ``` -------------------------------- ### State Management Source: https://www.genivia.com/doc/reflex/html/classreflex_1_1_flex_lexer.html Methods for managing lexer start condition states. ```APIDOC ## AbstractLexer & start(int state) ### Description Transition to the given start condition state. ## int start() const ### Description Returns the current start condition state. ## void push_state(int state) ### Description Push the current start condition state on the stack and transition to the given start condition state. ## void pop_state() ### Description Pop the stack start condition state and transition to that state. ``` -------------------------------- ### Match Property Output Source: https://www.genivia.com/doc/reflex/html/index.html The console output generated by the match property example. ```text accept: 1 text: How size: 3 line: 1 column: 0 first: 0 last: 3 accept: 1 text: now size: 3 line: 1 column: 4 first: 4 last: 7 accept: 1 text: brown size: 5 line: 1 column: 8 first: 8 last: 13 accept: 1 text: cow size: 3 line: 1 column: 14 first: 14 last: 17 ``` -------------------------------- ### POSIX Matcher Example Source: https://www.genivia.com/doc/reflex/html/index.html Demonstrates the default POSIX matcher behavior where the longest match is selected. ```bash reflex -m reflex −−main lexer.l c++ -o lexer lex.yy.cpp -lreflex echo "integer" | ./lexer => identifier ``` -------------------------------- ### Basic Indent/Nodent/Dedent Rules Source: https://www.genivia.com/doc/reflex/html/index.html Demonstrates basic indentation tracking using \i and \j anchors with line start anchors. ```RE/flex ^\h+ out() << "| "; // nodent: text is aligned to current indent ^\h+\i out() << "> "; // indent: matched and added with \i ^\h*\j out() << "< "; // dedent: matched with \j \j out() << "< "; // dedent: for each extra level dedented .|\n echo(); ``` -------------------------------- ### Lexer State Management Source: https://www.genivia.com/doc/reflex/html/classreflex_1_1_abstract_lexer.html Methods for managing the lexer's start condition states and stack. ```APIDOC ## AbstractLexer State Methods ### start(int state) Transition to the given start condition state. ### start() const Returns the current start condition state. ### push_state(int state) Push the current start condition state on the stack and transition to the given start condition state. ### pop_state() Pop the stack start condition state and transition to that state. ### top_state() const Returns the stack top start condition state or 0 (INITIAL) if the stack is empty. ### states_empty() const Returns true if the condition state stack is empty. ``` -------------------------------- ### Define lexer rules for line input Source: https://www.genivia.com/doc/reflex/html/index.html Example rules for matching lines when using interactive input. ```text %% .+ echo(); // ECHO the entire line \n echo(); // ECHO end of the line %% ``` -------------------------------- ### RE/flex Performance Report Output Source: https://www.genivia.com/doc/reflex/html/index.html Example output generated by the -p option showing rule match counts, byte counts, and execution times. ```text reflex x.y.z json.l performance report: INITIAL rules matched: rule at line 51 accepted 58 times matching 255 bytes total in 0.009 ms rule at line 52 accepted 58 times matching 58 bytes total in 0.824 ms rule at line 53 accepted 0 times matching 0 bytes total in 0 ms rule at line 54 accepted 0 times matching 0 bytes total in 0 ms rule at line 55 accepted 0 times matching 0 bytes total in 0 ms rule at line 56 accepted 5 times matching 23 bytes total in 0.007 ms rule at line 57 accepted 38 times matching 38 bytes total in 0.006 ms rule at line 72 accepted 0 times matching 0 bytes total in 0 ms default rule accepted 0 times STRING rules matched: rule at line 60 accepted 38 times matching 38 bytes total in 0.021 ms rule at line 61 accepted 0 times matching 0 bytes total in 0 ms rule at line 62 accepted 0 times matching 0 bytes total in 0 ms rule at line 63 accepted 0 times matching 0 bytes total in 0 ms rule at line 64 accepted 0 times matching 0 bytes total in 0 ms rule at line 65 accepted 0 times matching 0 bytes total in 0 ms rule at line 66 accepted 0 times matching 0 bytes total in 0 ms rule at line 67 accepted 0 times matching 0 bytes total in 0 ms rule at line 68 accepted 314 times matching 314 bytes total in 0.04 ms rule at line 69 accepted 8 times matching 25 bytes total in 0.006 ms rule at line 72 accepted 0 times matching 0 bytes total in 0 ms default rule accepted 0 times WARNING: execution times are relative: 1) includes caller's execution time between matches when yylex() returns 2) perf-report instrumentation adds overhead and increases execution times ``` -------------------------------- ### Define Lexer Patterns and Actions Source: https://www.genivia.com/doc/reflex/html/index.html Example of a lexer specification defining patterns for keywords, operators, identifiers, and constants. ```lex %% /* PATTERN */ /* ACTION */ "if" return KEYWORD_IF; "*" return OP_MUL; "=" return OP_ASSIGN; [a-zA-Z_][a-zA-Z0-9_]* return ASCII_IDENTIFIER; [0-9]+ return CONST_NUMBER; \"([^\\\"]|\\\")*\" return CONST_STRING; [ \t\r\n] /* no action: ignore all white space */ %% ``` -------------------------------- ### Printing Match Properties Source: https://www.genivia.com/doc/reflex/html/index.html Example usage of BoostMatcher to iterate through matches and print metadata including accept index, text, size, line number, column, and byte offsets. ```cpp #include // reflex::BoostMatcher, reflex::Input, boost::regex reflex::BoostMatcher matcher("\\w+", "How now brown cow."); while (matcher.find() != 0) std::cout << "accept: " << matcher.accept() << "text: " << matcher.text() << "size: " << matcher.size() << "line: " << matcher.lineno() << "column: " << matcher.columno() << "first: " << matcher.first() << "last: " << matcher.last() << std::endl; ``` -------------------------------- ### C++ Class Inheritance Example Source: https://www.genivia.com/doc/reflex/html/graph_legend.html A collection of class definitions demonstrating public, protected, and private inheritance, as well as template usage and containment for graph generation. ```cpp 1 /*! Invisible class because of truncation */ 2 class Invisible { }; 3 4 /*! Truncated class, inheritance relation is hidden */ 5 class Truncated : public Invisible { }; 6 7 /* Class not documented with doxygen comments */ 8 class Undocumented { }; 9 10 /*! Class that is inherited using public inheritance */ 11 class PublicBase : public Truncated { }; 12 13 /*! A template class */ 14 template class Templ { }; 15 16 /*! Class that is inherited using protected inheritance */ 17 class ProtectedBase { }; 18 19 /*! Class that is inherited using private inheritance */ 20 class PrivateBase { }; 21 22 /*! Class that is used by the Inherited class */ 23 class Used { }; 24 25 /*! Super class that inherits a number of other classes */ 26 class Inherited : public PublicBase, 27 protected ProtectedBase, 28 private PrivateBase, 29 public Undocumented, 30 public Templ 31 { 32 private: 33 Used *m_usedClass; 34 }; ``` -------------------------------- ### Initialize and use a reflex::Matcher Source: https://www.genivia.com/doc/reflex/html/index.html Demonstrates initializing a matcher with a string or file input and iterating through matches. ```cpp #include // reflex::PCRE2Matcher, reflex::Input // set the input source to a string (or a stream or a FILE*) reflex::Input source = "How now brown cow."; reflex::PCRE2Matcher matcher("\\w+", source); while (matcher.find() != 0) std::cout << "Found " << matcher.text() << std::endl; // use the same matcher with a new source (an Input object): std::ifstream ifs("cows.txt", std::ios::in | std::ios::binary); source = ifs; // Input source is reassignable matcher.input(source); // can use ifs as parameter also while (matcher.find() != 0) std::cout << "Found " << matcher.text() << std::endl; ifs.close(); ``` -------------------------------- ### Configure Lexer Matcher with Initial Code Source: https://www.genivia.com/doc/reflex/html/index.html Use %class and %init blocks to manage lexer state and configure the matcher behavior. ```reflex %class{ bool init_matcher; } %init{ init_matcher = true; } %% %{ if (init_matcher) // init the new matcher? { init_matcher = false; // init only once if (BUFFER_ALL) // buffer all input at once? matcher().buffer(); // same as %option batch else if (INTERACTIVE) // console-based (TTY) "interactive" input? matcher().interactive(); // same as %option interactive matcher().tabs(4); // same as %option tabs=4 } %} ``` -------------------------------- ### Switching Input Sources with Matchers Source: https://www.genivia.com/doc/reflex/html/index.html Demonstrates switching to a new input source and restoring the original one using RE/flex matcher methods. ```cpp ... // scanning etc. Matcher *oldmatcher = matcher(); reflex::Input input(...); Matcher *newmatcher = new_matcher(input); matcher(newmatcher); ... // scan the new input del_matcher(newmatcher); matcher(oldmatcher); ... // continue scanning the old input ``` -------------------------------- ### Switch input sources Source: https://www.genivia.com/doc/reflex/html/classreflex_1_1_input.html Demonstrates switching the input source of a reflex::Input object during runtime. ```cpp reflex::Input input = "Hello"; std::string message; char c; while (input.get(&c, 1)) message.append(c); input = L" world! To ∞ and beyond."; // switch input to a wide string while (input.get(&c, 1)) message.append(c); ``` -------------------------------- ### Compile an application with RE/flex and Boost Source: https://www.genivia.com/doc/reflex/html/index.html Link the application against the libreflex and boost_regex libraries during compilation. ```bash c++ myapp.cpp -lreflex -lboost_regex ``` -------------------------------- ### Define yytext macro Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Get the matched text. ```cpp #define yytext const_cast(YY_SCANNER_DOT_ YYText()) ``` -------------------------------- ### Initialize a BoostMatcher engine Source: https://www.genivia.com/doc/reflex/html/index.html Create a BoostMatcher instance for Perl-style matching using a regex object or string and an input source. ```cpp #include reflex::BoostMatcher matcher( boost::regex or string, reflex::Input [, "options"] ) ``` -------------------------------- ### Define yylineno macro Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Get the current line number. ```cpp #define yylineno static_cast(YY_SCANNER_DOT_ matcher().lineno()) ``` -------------------------------- ### Define yyleng macro Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Get the length of the matched text. ```cpp #define yyleng static_cast(YY_SCANNER_DOT_ YYLeng()) ``` -------------------------------- ### Configure Lexer with file input and custom output stream Source: https://www.genivia.com/doc/reflex/html/index.html Demonstrates instantiating the Lexer class to read from a file descriptor and write to a specific output file. This approach supports automatic character encoding decoding. ```cpp int main(int argc, char **argv) { FILE *fd = stdin; if (argc > 1 && (fd = fopen(argv[1], "r")) == NULL) exit(EXIT_FAILURE); std::ofstream of("output.txt", std::ofstream::out); if (!of) exit(EXIT_FAILURE); Lexer(fd, of).lex(); of.close(); if (fd != stdin) fclose(fd); return 0; } ``` -------------------------------- ### Capture group output Source: https://www.genivia.com/doc/reflex/html/index.html The expected output from the PCRE2Matcher capture example. ```text name: cow, number: 123 ``` -------------------------------- ### Initialize a RE/flex Matcher Source: https://www.genivia.com/doc/reflex/html/index.html Basic initialization of a matcher with a pattern and input source. ```cpp reflex::Matcher matcher(pattern, input); ``` -------------------------------- ### Switching Input Sources with --flex Option Source: https://www.genivia.com/doc/reflex/html/index.html Shows the equivalent input switching logic when using the --flex compatibility option. ```cpp ... // scanning etc. YY_BUFFER_STATE oldbuf = YY_CURRENT_BUFFER; reflex::Input input(...); YY_BUFFER_STATE newbuf = yy_create_buffer(input, YY_BUF_SIZE); yy_switch_to_buffer(newbuf); ... // scan the new input yy_delete_buffer(newbuf); ... // the specified input is no longer needed here yy_switch_to_buffer(oldbuf); ... // continue scanning the old input ``` -------------------------------- ### Constructing reflex::Pattern and reflex::Matcher Source: https://www.genivia.com/doc/reflex/html/index.html Basic syntax for initializing a pattern and associating it with a matcher. ```cpp #include [static] [const] reflex:Pattern pattern(string [, "options"] ) reflex::Matcher matcher(pattern, reflex::Input [, "options"] ) ``` -------------------------------- ### Flex-compatible YY_AT_BOL macro Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Performs an at-begin-of-line check; use only when the scanner has started. ```cpp #define YY_AT_BOL | ( | | ) | YY_SCANNER_DOT_ matcher().at_bol() ``` -------------------------------- ### Flex-compatible scanner state macros Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Accesses the current matcher buffer and start condition. ```cpp #define YY_CURRENT_BUFFER YY_SCANNER_DOT_ ptr_matcher() ``` ```cpp #define yy_current_state YY_SCANNER_DOT_ start() ``` -------------------------------- ### Flex-compatible yy_act macro Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Returns the matched action index; use only when the scanner has started. ```cpp #define yy_act YY_SCANNER_DOT_ matcher().accept() ``` -------------------------------- ### Implement nested include directives with RE/flex Source: https://www.genivia.com/doc/reflex/html/index.html Uses a stack of matchers to handle nested #include directives up to a depth of 99 files. ```C %top{ #include } %class{ int depth; void include_file() { depth++; if (depth > 99) exit(EXIT_FAILURE); // max include depth exceeded char *q = strchr(text(), '"'); // get ..."filename" char *file = strdup(q + 1); // get filename" file[strlen(file) - 1] = '\0'; // get filename FILE *fd = fopen(file, "r"); free(file); if (!fd) exit(EXIT_FAILURE); // cannot open file push_matcher(new_matcher(fd)); // push current matcher, use new matcher } bool end_of_file() { if (depth == 0) return true; // return true: no more input to read fclose(in()); // close current input in() (a FILE*) pop_matcher(); // delete current matcher, pop matcher depth--; return false; // return false: continue reading } } %init{ depth = 0; } %% ^\h*#include\h*\".*?\" include_file(); .|\n echo(); <> if (end_of_file()) return 0; %% ``` -------------------------------- ### Initialize Lexer with Custom Input Source: https://www.genivia.com/doc/reflex/html/index.html Instantiate a Lexer class with a specific input source and output stream. ```cpp Lexer lexer(input, std::cout); ``` ```cpp yyFlexLexer lexer(input, std::cout); ``` -------------------------------- ### Compile RE/flex from source Source: https://www.genivia.com/doc/reflex/html/index.html Manual compilation commands for cross-compilation or applying specific SIMD optimizations. ```bash c++ -I. -Iinclude lex.yy.cpp lib/debug.cpp lib/error.cpp \ lib/input.cpp lib/matcher.cpp lib/pattern.cpp lib/utf8.cpp lib/simd.cpp ``` ```bash c++ -DHAVE_NEON -mfpu=neon -I. -Iinclude lex.yy.cpp lib/debug.cpp lib/error.cpp \ lib/input.cpp lib/matcher.cpp lib/pattern.cpp lib/utf8.cpp lib/simd.cpp ``` ```bash c++ -DHAVE_SSE2 -msse2 -I. -Iinclude lex.yy.cpp lib/debug.cpp lib/error.cpp \ lib/input.cpp lib/matcher.cpp lib/pattern.cpp lib/utf8.cpp lib/simd.cpp ``` ```bash c++ -DHAVE_AVX2 -mavx2 -I. -Iinclude lex.yy.cpp lib/debug.cpp lib/error.cpp \ lib/input.cpp lib/matcher.cpp lib/pattern.cpp lib/utf8.cpp lib/simd.cpp \ lib/matcher_avx2.cpp lib/simd_avx2.cpp ``` ```bash c++ -DHAVE_AVX512BW -mavx512bw -I. -Iinclude lex.yy.cpp lib/debug.cpp lib/error.cpp \ lib/input.cpp lib/matcher.cpp lib/pattern.cpp lib/utf8.cpp lib/simd.cpp \ lib/matcher_avx2.cpp lib/matcher_avx512bw.cpp lib/simd_avx2.cpp lib/simd_avx512bw.cpp ``` -------------------------------- ### Using External Buffers Source: https://www.genivia.com/doc/reflex/html/index.html Demonstrates using an external buffer for zero-copy input assignment. ```cpp // read a 0-terminated buffer in place, buffer content is changed!! char *base = ...; // points to the base address of the data size_t size = ...; // length of the data including one extra byte for a final \0 lexer.buffer(base, size); lexer.lex(); ``` -------------------------------- ### Initialize Pattern with Options Source: https://www.genivia.com/doc/reflex/html/index.html Configures a regex pattern with specific flags for case-insensitivity, dot-all mode, and exception handling. ```cpp reflex::Pattern pattern(pattern, "isr") ``` -------------------------------- ### Generated FSM Opcode Table Source: https://www.genivia.com/doc/reflex/html/index.html Example of an FSM opcode table generated by the f=machine.cpp option. ```cpp REFLEX_CODE_DECL reflex_code_FSM[11] = { 0x617A0005, // 0: GOTO 5 ON a-z 0x5F5F0005, // 1: GOTO 5 ON _ 0x415A0005, // 2: GOTO 5 ON A-Z 0x30390005, // 3: GOTO 5 ON 0-9 0x00FFFFFF, // 4: HALT 0xFF000001, // 5: TAKE 1 0x617A0005, // 6: GOTO 5 ON a-z 0x5F5F0005, // 7: GOTO 5 ON _ 0x415A0005, // 8: GOTO 5 ON A-Z 0x30390005, // 9: GOTO 5 ON 0-9 0x00FFFFFF, // 10: HALT }; ``` -------------------------------- ### Search and Split Text with Matcher and BoostMatcher Source: https://www.genivia.com/doc/reflex/html/index.html Demonstrates using reflex::Matcher and reflex::BoostMatcher for finding patterns, counting words, and splitting text using iterators and range-based loops. ```cpp #include #include using namespace reflex; // some random text (with extra spacing) std::string example("Monty\n Python's Flying Circus"); // construct a fixed pattern that is case insensitive static const Pattern pattern("monty|python", "i"); // construct a matcher to search the example text Matcher matcher(pattern, example); while (matcher.find() != 0) std::cout << matcher.text() << " at " << matcher.lineno() << "," << matcher.columno() << " spans " << matcher.first() << ".." << matcher.last() << std::endl; // construct a Boost.Regex matcher to count the words (all non-spaces "\S+") BoostMatcher boostmatcher("\\\S+", example); boostmatcher.buffer(); // because Boost.Regex partial_match is broken! std::cout << std::distance(boostmatcher.find.begin(), boostmatcher.find.end()) << " words" << std::endl; // reuse the BoostMatcher with a C++11 range-based loop to split the example text on space "\s+": for (auto& split : boostmatcher.pattern("\\\s+").input(example).split) std::cout << split.text() << " "; std::cout << std::endl; // reuse the BoostMatcher to split on whitespace using an iterator, sort into a set, and print boostmatcher.input(example).buffer(); std::set words(boostmatcher.split.begin(), boostmatcher.split.end()); std::copy(words.begin(), words.end(), std::ostream_iterator(std::cout, " ")); std::cout << std::endl; ``` -------------------------------- ### Scan nested structures Source: https://www.genivia.com/doc/reflex/html/index.html Uses a start condition state to scan nested parentheses as a single token. ```text { .*?[()] yymore(); if (yytext[yyleng-1] == '(') ++param; else if (param-- <= 1) { do_something(yytext); yy_pop_state(); } } ``` -------------------------------- ### void compile() Source: https://www.genivia.com/doc/reflex/html/classreflex_1_1_p_c_r_e2_u_t_f_matcher.html Compiles the pattern for JIT partial matching and allocates necessary match data. ```APIDOC ## void compile() ### Description Compiles the pattern for JIT partial matching and allocates match data. ``` -------------------------------- ### matcher().tabs() Source: https://www.genivia.com/doc/reflex/html/index.html Gets or sets the current tab expansion value (1, 2, 4, or 8). ```APIDOC ## matcher().tabs() ### Description Returns or sets the current tab expansion value used by the matcher. ### Parameters - **n** (int) - Optional - The tab expansion value to set (1, 2, 4, or 8). ### Response - **value** (int) - The current tab expansion value. ``` -------------------------------- ### Compiling with libreflex Source: https://www.genivia.com/doc/reflex/html/index.html Link the application against the libreflex library during compilation. ```bash c++ myapp.cpp -lreflex ``` -------------------------------- ### Matcher Configuration Methods Source: https://www.genivia.com/doc/reflex/html/index.html Methods used to initialize a matcher, assign input sources, and configure patterns or buffering. ```APIDOC ## Matcher Configuration ### Methods - `input(i)`: Set input to `reflex::Input i` (string, stream, or `FILE*`). - `pattern(p)`: Set pattern `reflex::Pattern`, `boost::regex`, or a string `p`. - `has_pattern()`: Returns true if the matcher has a pattern assigned. - `own_pattern()`: Returns true if the matcher has a pattern to manage and delete. - `pattern()`: Returns a reference to the pattern object. - `buffer()`: Buffer all input at once. - `buffer(n)`: Set the buffer window size to `n` bytes. - `buffer(b, n)`: Use buffer of `n` bytes at address `b` (zero copy). - `interactive()`: Set buffer size to 1 for TTY input. - `flush()`: Flush remaining input from internal buffer. - `reset()`: Resets the matcher. - `reset(o)`: Resets the matcher with options string `o`. ``` -------------------------------- ### matcher().first() and matcher().last() Source: https://www.genivia.com/doc/reflex/html/index.html Returns the position in the input stream of the match, counting in bytes from the start of the input. ```APIDOC ## matcher().first() / matcher().last() ### Description Returns the position in the input stream of the match, counting in bytes from the start of the input at position 0. ``` -------------------------------- ### Compile application with libreflex Source: https://www.genivia.com/doc/reflex/html/index.html Link the application against libreflex and ensure C++11 standard is enabled. ```bash c++ -std=c++11 myapp.cpp -lreflex ``` -------------------------------- ### reflex::AbstractLexer::top_state Source: https://www.genivia.com/doc/reflex/html/classreflex_1_1_abstract_lexer.html Returns the stack top start condition state or 0 (INITIAL) if the stack is empty. ```APIDOC ## int reflex::AbstractLexer< M >::top_state() const ### Description Returns the stack top start condition state or 0 (INITIAL) if the stack is empty. ### Returns - **int** - start condition (integer) ``` -------------------------------- ### Bison/Yacc Grammar Definition Source: https://www.genivia.com/doc/reflex/html/index.html Example of a Yacc grammar file defining the union type and tokens used by the scanner. ```yacc /* yacc grammar (.y file) */ %{ extern int yylex(void); %} %union { // YYSTYPE yylval is a union: int num; // yylval.num char* str; // yylval.str } %token CONST_NUMBER %token CONST_STRING %% ... // grammar rules %% ``` -------------------------------- ### Define yyrestart macro Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Restart with a new input source. ```cpp #define yyrestart | ( | | i| ) | YY_SCANNER_DOT_ in(i) ``` -------------------------------- ### Flex-compatible buffer creation macros Source: https://www.genivia.com/doc/reflex/html/flexlexer_8h.html Creates and returns a new buffer. ```cpp #define yy_create_buffer | ( | | i, ---|---|---|--- | | | _ | ) | | YY_SCANNER_DOT_ new_matcher(i) ``` ```cpp #define YY_NEW_BUFFER | ( | | i, ---|---|---|--- | | | _ | ) | | YY_SCANNER_DOT_ new_matcher(i) ``` -------------------------------- ### Validate a date string using PCRE2 Source: https://www.genivia.com/doc/reflex/html/index.html Uses the PCRE2Matcher class to perform the same date validation as the Boost example. ```cpp #include // reflex::PCRE2Matcher, reflex::Input // use a PCRE2Matcher to check if the birthdate string is a valid date if (reflex::PCRE2Matcher("\\d{4}-\\d{2}-\\d{2}", birthdate).matches()) std::cout << "Valid date!" << std::endl; ``` -------------------------------- ### Implementing wrap() for Input Continuation Source: https://www.genivia.com/doc/reflex/html/index.html Example of overriding the wrap() method to continue reading from std::cin after reaching EOF. ```cpp %class{ virtual int wrap() // note: yywrap() with option −−flex { in(std::cin); return in().good() ? 0 : 1; } } ``` -------------------------------- ### Initialize a BoostPosixMatcher engine Source: https://www.genivia.com/doc/reflex/html/index.html Create a BoostPosixMatcher instance for POSIX-style matching, which does not support lazy quantifiers and uses the leftmost longest rule. ```cpp #include reflex::BoostPosixMatcher matcher( boost::regex or string, reflex::Input [, "options"] ) ``` -------------------------------- ### Lexer Specification with Defined Names Source: https://www.genivia.com/doc/reflex/html/index.html Example of using defined names within a lexer specification to build character classes. ```reflex lower [a-z] upper [A-Z] letter [||{lower}||{upper}] alnum [0-9||{letter}] name {letter}{alnum}* %% {name} std::cout << "name: " << text() << std::endl; .| // skip everything else %% ``` -------------------------------- ### Generated Native C++ FSM Code Source: https://www.genivia.com/doc/reflex/html/index.html Example of optimized native C++ code generated for an FSM using the o option. ```cpp void reflex_code_FSM(reflex::Matcher& m) { int c = 0; m.FSM_INIT(c); S0: c = m.FSM_CHAR(); if (97 <= c && c <= 122) goto S5; if (c == 95) goto S5; if (65 <= c && c <= 90) goto S5; if (48 <= c && c <= 57) goto S5; return m.FSM_HALT(c); S5: m.FSM_TAKE(1); c = m.FSM_CHAR(); if (97 <= c && c <= 122) goto S5; if (c == 95) goto S5; if (65 <= c && c <= 90) goto S5; if (48 <= c && c <= 57) goto S5; return m.FSM_HALT(c); } ``` -------------------------------- ### Initialize Input with Encoding Source: https://www.genivia.com/doc/reflex/html/index.html Sets the input stream encoding to ISO-8859-1 for the matcher. ```cpp reflex::Input input(stdin, reflex::Input::file_encoding::latin); reflex::Matcher matcher(pattern, input); ``` -------------------------------- ### Compile an application with RE/flex Source: https://www.genivia.com/doc/reflex/html/index.html Standard compilation command for linking an application against the libreflex library. ```bash c++ myapp.cpp -lreflex ``` ```bash c++ myapp.cpp -lreflex -lpcre2-8 ``` ```bash c++ myapp.cpp -lreflex -lboost_regex ``` -------------------------------- ### State-based Indent Stop Management Source: https://www.genivia.com/doc/reflex/html/index.html Uses start conditions and stop management to handle nested comments while preserving indentation state. ```RE/flex %{ int level; // a variable to track the /*-comment nesting level std::vector stops; // a variable to save the stop positions after indent %} %o tabs=8 %x COMMENT %% ^\h+ out() << "| "; // nodent, text is aligned to current margin column ^\h+\i out() << "> "; // indent stops = matcher().stops(); // save the stop positions ^"/*"\j level = 1; // do not count dedent(s) to the first line that has a /*-comment start(COMMENT); // skip comment ^\h*\j out() << "< "; // dedent \j out() << "< "; // dedent, triggered for each extra level dedented (?^^\h*\n) // a negative pattern to eat empty lines without affecting indent stops (?^^\h+/"/*") // a negative pattern to eat white space before /*-comments without affecting indent stops "/*" level = 1; start(COMMENT); // continue w/o indent matching (?^\\\\\n\h*) // lines ending in \ continue on the next line .|\n echo(); // ECHO character { "/*" ++level; // allow nested /*-comments "*/" if (--level == 0) { matcher().stops() = stops; // restore the indent margin/tab stops start(INITIAL); // back to initial state } .|\n // ignore all content in comments <> out() << "/* not closed"; } %% ``` -------------------------------- ### Handling Regex Syntax Errors Source: https://www.genivia.com/doc/reflex/html/index.html Example of using a try-catch block to handle regex syntax errors when the 'r' option is enabled. ```cpp try { reflex::Pattern pattern(argv[1], "r"); // "r" option throws syntax error exceptions ... // code that uses the pattern object ... } catch (reflex::regex_error& e) { switch (e.code()) { case reflex::regex_error::mismatched_parens: std::cerr << "mismatched ( )"; break; case reflex::regex_error::mismatched_braces: std::cerr << "mismatched { }"; break; case reflex::regex_error::mismatched_brackets: std::cerr << "mismatched [ ]"; break; case reflex::regex_error::mismatched_quotation: std::cerr << "mismatched \\Q...\\E quotation"; break; case reflex::regex_error::empty_expression: std::cerr << "regex (sub)expression should not be empty"; break; case reflex::regex_error::empty_class: std::cerr << "character class [...] is empty, e.g. [a&&[b]]"; break; case reflex::regex_error::invalid_class: std::cerr << "invalid character class name"; break; case reflex::regex_error::invalid_class_range: std::cerr << "invalid character class range, e.g. [Z-A]"; break; case reflex::regex_error::invalid_escape: std::cerr << "invalid escape character"; break; case reflex::regex_error::invalid_anchor: std::cerr << "invalid anchor or boundary"; break; case reflex::regex_error::invalid_repeat: std::cerr << "invalid repeat, e.g. {10,1}"; break; case reflex::regex_error::invalid_quantifier: std::cerr << "invalid lazy or possessive quantifier"; break; case reflex::regex_error::invalid_modifier: std::cerr << "invalid (?ismux:) modifier"; break; case reflex::regex_error::invalid_collating: std::cerr << "invalid collating element"; break; case reflex::regex_error::invalid_backreference: std::cerr << "invalid backreference"; break; case reflex::regex_error::invalid_syntax: std::cerr << "invalid regex syntax"; break; case reflex::regex_error::exceeds_length: std::cerr << "exceeds length limit, pattern is too long"; break; case reflex::regex_error::exceeds_limits: std::cerr << "exceeds complexity limits, e.g. {n,m} range too large"; break; } std::cerr << std::endl << e.what(); } ``` -------------------------------- ### Configure fuzzy matching flags Source: https://www.genivia.com/doc/reflex/html/index.html Examples of using bitwise OR to combine maximum edit distance with specific fuzzy matching constraints. ```cpp reflex::FuzzyMatcher matcher(regex, 3 | reflex::FuzzyMatcher::INS, input); ``` ```cpp reflex::FuzzyMatcher matcher(regex, 3 | reflex::FuzzyMatcher::INS | reflex::FuzzyMatcher::DEL, input); ``` -------------------------------- ### Constructing a reflex::Matcher Source: https://www.genivia.com/doc/reflex/html/index.html Initialize a matcher using a pattern or string and an input source. ```cpp #include reflex::Matcher matcher( reflex::Pattern or string, reflex::Input [, "options"] ) ``` -------------------------------- ### Switching Input Sources for Reentrant Scanners Source: https://www.genivia.com/doc/reflex/html/index.html Examples of configuring input sources for reentrant lexers, which require an additional yyscan_t argument. ```cpp // read from a file, this also decodes UTF-8/16/32 encodings automatically FILE *fd = fopen("cow.txt", "r"); if (fd == NULL) ... // error, bail out yyget_in(yyscanner) = fd; yylex(); // read from a stream (ASCII or UTF-8) std::istream i = std::ifstream("file", std::ios::in); yyget_in(yyscanner) = &i; yylex(); // read from a string (0-terminated, ASCII or UTF-8) yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner); yy_scan_string("How now brown cow.", yyscanner); // new buffer to scan a string yylex(); // read from a memory segment (raw bytes, ASCII, or UTF-8) const char *ptr = ...; // points to memory segment size_t len = ...; // length of the memory segment yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner); yy_scan_bytes(ptr, len, yyscanner); // new buffer to scan memory yylex(); // read from a wide string, 0-terminated, encoding it to UTF-8 for matching yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner); yy_scan_wstring(L"How now brown cow.", yyscanner); // new buffer to scan a wide string yylex(); // read a 0-terminated buffer in place, buffer content is changed!! char *base = ...; // points to 0-terminated buffer size_t size = ...; // length of the buffer including final 0 byte yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner); yy_scan_buffer(base, size, yyscanner); yylex(); ```