Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.compilers > #1492 > unrolled thread
| Started by | "Costello, Roger L." <costello@mitre.org> |
|---|---|
| First post | 2015-01-20 16:08 +0000 |
| Last post | 2015-01-22 01:35 +0000 |
| Articles | 4 — 4 participants |
Back to article view | Back to comp.compilers
Algorithm(s) to convert textual regular expressions to a transition table? "Costello, Roger L." <costello@mitre.org> - 2015-01-20 16:08 +0000
Re: Algorithm(s) to convert textual regular expressions to a transition table? ioan <niciodata.eu@gmail.com> - 2015-01-21 01:46 -0800
Re: Algorithm(s) to convert textual regular expressions to a transition table? jeremy.p.wright@gmail.com - 2015-01-21 01:05 -0800
Re: Algorithm(s) to convert textual regular expressions to a transition table? Kaz Kylheku <kaz@kylheku.com> - 2015-01-22 01:35 +0000
| From | "Costello, Roger L." <costello@mitre.org> |
|---|---|
| Date | 2015-01-20 16:08 +0000 |
| Subject | Algorithm(s) to convert textual regular expressions to a transition table? |
| Message-ID | <15-01-035@comp.compilers> |
Hi Folks, I have read the section in Modern Compiler Design that discusses lexical analysis. I understand the subset algorithm it describes (neat algorithm!). With pencil and paper I can take a set of regular expressions and follow the subset algorithm to generate a transition table. But writing actual code to do this conversion will require more algorithms, I think. Is there an algorithm that describes how to read in a set of strings that represent regular expressions and create data structures that are well-suited to processing by the subset algorithm? More broadly, what are the set of algorithms needed to go from a set of strings that represent regular expressions to the precomputed transition table? Can you refer me to a book or article that does a good job in describing this? /Roger [Unless I misunderstand your question, this is exactly what lexer generators like lex and flex do. You give it a set of regular expressions, it generates tables that their state machine uses to match the RE's. -John]
[toc] | [next] | [standalone]
| From | ioan <niciodata.eu@gmail.com> |
|---|---|
| Date | 2015-01-21 01:46 -0800 |
| Message-ID | <15-01-036@comp.compilers> |
| In reply to | #1492 |
Hello, Some time ago I wrote this: http://sourceforge.net/p/nfa2dfa/code/HEAD/tree/nfa2dfa.sh implementation for the subset construction algorithm. I don't know how good my choices for data structures I have used in the implementation were.
[toc] | [prev] | [next] | [standalone]
| From | jeremy.p.wright@gmail.com |
|---|---|
| Date | 2015-01-21 01:05 -0800 |
| Message-ID | <15-01-037@comp.compilers> |
| In reply to | #1492 |
As John says, there are tools such as lex that already do this. If you need to use regular expressions, use an existing tool. If you want a good description of what is going on inside such tools, I recommend Chapter 2 of Engineering a Compiler, by Keith Cooper and Linda Torczon of Rice University. Jeremy
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2015-01-22 01:35 +0000 |
| Message-ID | <15-01-038@comp.compilers> |
| In reply to | #1492 |
On 2015-01-20, Costello, Roger L. <costello@mitre.org> wrote: > I have read the section in Modern Compiler Design that discusses lexical > analysis. I understand the subset algorithm it describes (neat algorithm!). > With pencil and paper I can take a set of regular expressions and follow the > subset algorithm to generate a transition table. This is not necessary. Regular expressions can also be compiled to an NFA graph, which can be simulated. This has different performance tradeoffs. For some regexes, the subset construction algorithm blows up to a large number of states, whereas the NFA graph is small. Regular expressions can also be retained as an abstract syntax tree, and evaluated directly, using the technique of Brzozowski derivatives. In the TXR language, I have a hybrid approach whereby a regular expression's abstract syntax tree is analyzed, and then the appropriate strategy is chosen: compile to NFA graph, or treat with derivatives. The strategy depends on whether the syntax tree contains the exotic operators complement or intersection. If they are absent then the NFA will work; the esoteric operators are not easily compilable to an NFA. (The NFA for them exists, but requires a substantial transformation of the regex.) > But writing actual code to do > this conversion will require more algorithms, I think. Is there an algorithm > that describes how to read in a set of strings that represent regular > expressions and create data structures that are well-suited to processing by > the subset algorithm? The subset algorithm is usually described as operating on the NFA graph. The NFA graph simulation dynamically evaluates the algorithm: as the input arrives, it calculates the transitive closures: *sets* of states which are reachable when that input symbol is processed. The subset construction essentially pre-computes all the possible state sets, leaving just a finite machine that doesn't have to perform the closure computations that the NFA simulator performs. > More broadly, what are the set of algorithms needed to > go from a set of strings that represent regular expressions to the precomputed > transition table? Can you refer me to a book or article that does a good job > in describing this? In my compiler, I first go from regex syntax to Lisp-based abstract syntax tree. This AST can then be compiled. The API's are open. From the shell prompt: $ txr -p '(regex-parse "a.*b")' (compound #\a (0+ wild) #\b) It's all prefix Lisp. (compound x y z) denotes xyz, (0+ x) is x*, the symbol wild denotes the . and such. #\a denotes a character object, the ASCII/Unicode 'a'. The regex compiler function accepts either this AST, or the original textual form: $ txr -p "(regex-compile '(compound #\a (0+ wild) #\b))" #/a.*b/ The printed output isn't informative. The compiler outputs a compiled regex object which is not printable. (We would have to look at its C representation, and inspect it in a C debugger to see its insides.) When we print that object using the TXR language itself, a stashed copy of the AST source code is pulled from that object to produce the understandable #/a.*b/ notation. That is to say, the object printer does not traverse the compiled NFA to reproduce a.*b: that is not really tractable!!! $ txr -p "(typeof (regex-compile '(compound #\a (0+ wild) #\b)))" sys:regex $ txr -p "(typeof #/abc/)" # this regex is compiled at S-exp read time sys:regex The abstract syntax tree is produced using easy parsing techniques. In my case, a Yacc grammar (or rather regex subgrammar in a larger language). The grammar is here: http://www.kylheku.com/cgit/txr/tree/parser.y The relvant productions are regex, regexpr, regbranch, regterm and others. The AST to regex object compiler is in regex.c. The regex_compile function is the master API. It checks whether the regex must be treated with derivatives and either uses dv_compile_regex, or nfa_compile_regex. dv_compile_regex doesn't do much: it expands the character set notations into charset objects that are faster to evaluate (NFA uses them too). It also expands the nongreedy operator R1%R2, which I designed as a syntactic sugar that transforms into other operations. The nfa_compile_regex function is based almost directly on the graphical representations of the proces (bubble and arrow diagrams) in the Red Dragon Book (_Compilers: Principles, Techniques and Tools_, 1988). Because the input is a Lisp-like data structure, the function is very easy to understand. Basically the whole compiler logic is in that one simple function, supported by subroutines to make and connect NFA states of various kinds, and produce character sets. Character sets are tricky under Unicode! I implemented radix trees of several different types (distinguished by their height), all with character bitmaps at the leaf level. The choice of radix tree depends on the range of the character set. Inverted character sets are handled as an uninverted representation, which is flagged as inverted.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.compilers
csiph-web