phpDocumentor PHP_LexerGenerator
[ class tree: PHP_LexerGenerator ] [ index: PHP_LexerGenerator ] [ all elements ]

Source for file LexerGenerator.php

Documentation is available at LexerGenerator.php

  1. <?php
  2. /**
  3.  * PHP_LexerGenerator, a php 5 lexer generator.
  4.  * 
  5.  * This lexer generator translates a file in a format similar to
  6.  * re2c ({@link http://re2c.org}) and translates it into a PHP 5-based lexer
  7.  *
  8.  * PHP version 5
  9.  *
  10.  * LICENSE:
  11.  * 
  12.  * Copyright (c) 2006, Gregory Beaver <cellog@php.net>
  13.  * All rights reserved.
  14.  *
  15.  * Redistribution and use in source and binary forms, with or without
  16.  * modification, are permitted provided that the following conditions
  17.  * are met:
  18.  *
  19.  *     * Redistributions of source code must retain the above copyright
  20.  *       notice, this list of conditions and the following disclaimer.
  21.  *     * Redistributions in binary form must reproduce the above copyright
  22.  *       notice, this list of conditions and the following disclaimer in
  23.  *       the documentation and/or other materials provided with the distribution.
  24.  *     * Neither the name of the PHP_LexerGenerator nor the names of its
  25.  *       contributors may be used to endorse or promote products derived
  26.  *       from this software without specific prior written permission.
  27.  *
  28.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  29.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  30.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  31.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  32.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  33.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  34.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  35.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  36.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  37.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  38.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39.  *
  40.  * @category   php
  41.  * @package    PHP_LexerGenerator
  42.  * @author     Gregory Beaver <cellog@php.net>
  43.  * @copyright  2006 Gregory Beaver
  44.  * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
  45.  * @version    CVS: $Id$
  46.  * @since      File available since Release 0.1.0
  47.  */
  48. /**
  49.  * The Lexer generation parser
  50.  */
  51. require_once 'PHP/LexerGenerator/Parser.php';
  52. /**
  53.  * Hand-written lexer for lex2php format files
  54.  */
  55. require_once 'PHP/LexerGenerator/Lexer.php';
  56. /**
  57.  * The basic home class for the lexer generator.  A lexer scans text and
  58.  * organizes it into tokens for usage by a parser.
  59.  * 
  60.  * Sample Usage:
  61.  * <code>
  62.  * require_once 'PHP/LexerGenerator.php';
  63.  * $lex = new PHP_LexerGenerator('/path/to/lexerfile.plex');
  64.  * </code>
  65.  * 
  66.  * A file named "/path/to/lexerfile.php" will be created.
  67.  * 
  68.  * File format consists of a PHP file containing specially
  69.  * formatted comments like so:
  70.  * 
  71.  * <code>
  72.  * /*!lex2php
  73.  * {@*} 
  74.  * </code>
  75.  * 
  76.  * All lexer definition files must contain at least two lex2php comment blocks:
  77.  *  - 1 regex declaration block
  78.  *  - 1 or more rule declaration blocks
  79.  * 
  80.  * The first lex2php comment is the regex declaration block and must contain
  81.  * several processor instruction as well as defining a name for all
  82.  * regular expressions.  Processor instructions start with
  83.  * a "%" symbol and must be:
  84.  * 
  85.  *  - %counter
  86.  *  - %input
  87.  *  - %token
  88.  *  - %value
  89.  *  - %line
  90.  * 
  91.  * token and counter should define the class variables used to define lexer input
  92.  * and the index into the input.  token and value should be used to define the class
  93.  * variables used to store the token number and its textual value.  Finally, line
  94.  * should be used to define the class variable used to define the current line number
  95.  * of scanning.
  96.  * 
  97.  * For example:
  98.  * <code>
  99.  * /*!lex2php
  100.  * %counter {$this->N}
  101.  * %input {$this->data}
  102.  * %token {$this->token}
  103.  * %value {$this->value}
  104.  * %line {%this->linenumber}
  105.  * {@*} 
  106.  * </code>
  107.  * 
  108.  * Patterns consist of an identifier containing an letters or an underscore, and
  109.  * a descriptive match pattern.
  110.  * 
  111.  * Descriptive match patterns may either be regular expressions (regexes) or
  112.  * quoted literal strings.  Here are some examples:
  113.  * 
  114.  * <pre>
  115.  * pattern = "quoted literal"
  116.  * ANOTHER = /[a-zA-Z_]+/
  117.  * COMPLEX = @<([a-zA-Z_]+)( +(([a-zA-Z_]+)=((["\'])([^\6]*)\6))+){0,1}>[^<]*</\1>@
  118.  * </pre>
  119.  * 
  120.  * Quoted strings must escape the \ and " characters with \" and \\.
  121.  * 
  122.  * Regex patterns must be in Perl-compatible regular expression format (preg).
  123.  * special characters (like \t \n or \x3H) can only be used in regexes, all
  124.  * \ will be escaped in literal strings.
  125.  * 
  126.  * Sub-patterns may be defined and back-references (like \1) may be used.  Any sub-
  127.  * patterns detected will be passed to the token handler in the variable
  128.  * $yysubmatches.
  129.  * 
  130.  * In addition, lookahead expressions, and once-only expressions are allowed.
  131.  * Lookbehind expressions are impossible (scanning always occurs from the
  132.  * current position forward), and recursion (?R) can't work and is not allowed.
  133.  *
  134.  * <code>
  135.  * /*!lex2php
  136.  * %counter {$this->N}
  137.  * %input {$this->data}
  138.  * %token {$this->token}
  139.  * %value {$this->value}
  140.  * %line {%this->linenumber}
  141.  * alpha = /[a-zA-Z]/
  142.  * alphaplus = /[a-zA-Z]+/
  143.  * number = /[0-9]/
  144.  * numerals = /[0-9]+/
  145.  * whitespace = /[ \t\n]+/
  146.  * blah = "$\""
  147.  * blahblah = /a\$/
  148.  * GAMEEND = @(?:1\-0|0\-1|1/2\-1/2)@
  149.  * PAWNMOVE = /P?[a-h]([2-7]|[18]\=(Q|R|B|N))|P?[a-h]x[a-h]([2-7]|[18]\=(Q|R|B|N))/
  150.  * {@*} 
  151.  * </code>
  152.  * 
  153.  * All regexes must be delimited.  Any legal preg delimiter can be used (as in @ or / in
  154.  * the example above)
  155.  * 
  156.  * Rule lex2php blocks each define a lexer state.  You can optionally name the state
  157.  * with the %statename processor instruction.  State names can be used to transfer to
  158.  * a new lexer state with the yybegin() method
  159.  * 
  160.  * <code>
  161.  * /*!lexphp
  162.  * %statename INITIAL
  163.  * blah {
  164.  *     $this->yybegin(self::INBLAH);
  165.  *     // note - $this->yybegin(2) would also work
  166.  * }
  167.  * {@*} 
  168.  * /*!lex2php
  169.  * %statename INBLAH
  170.  * ANYTHING {
  171.  *     $this->yybegin(self::INITIAL);
  172.  *     // note - $this->yybegin(1) would also work
  173.  * }
  174.  * {@*} 
  175.  * </code>
  176.  * 
  177.  * You can maintain a parser state stack simply by using yypushstate() and
  178.  * yypopstate() instead of yybegin():
  179.  * 
  180.  * <code>
  181.  * /*!lexphp
  182.  * %statename INITIAL
  183.  * blah {
  184.  *     $this->yypushstate(self::INBLAH);
  185.  * }
  186.  * {@*} 
  187.  * /*!lex2php
  188.  * %statename INBLAH
  189.  * ANYTHING {
  190.  *     $this->yypopstate();
  191.  *     // now INBLAH doesn't care where it was called from
  192.  * }
  193.  * {@*} 
  194.  * </code>
  195.  * 
  196.  * Code blocks can choose to skip the current token and cycle to the next token by
  197.  * returning "false"
  198.  * 
  199.  * <code>
  200.  * /*!lex2php
  201.  * WHITESPACE {
  202.  *     return false;
  203.  * }
  204.  * {@*} 
  205.  * </code>
  206.  * 
  207.  * If you wish to re-process the current token in a new state, simply return true.
  208.  * If you forget to change lexer state, this will cause an unterminated loop,
  209.  * so be careful!
  210.  * 
  211.  * <code>
  212.  * /*!lex2php
  213.  * "(" {
  214.  *     $this->yypushstate(self::INPARAMS);
  215.  *     return true;
  216.  * }
  217.  * {@*} 
  218.  * </code>
  219.  * 
  220.  * Lastly, if you wish to cycle to the next matching rule, return any value other than
  221.  * true, false or null:
  222.  * 
  223.  * <code>
  224.  * /*!lex2php
  225.  * "{@" ALPHA {
  226.  *     if ($this->value == '{@internal') {
  227.  *         return 'more';
  228.  *     }
  229.  *     ...
  230.  * }
  231.  * "{@internal" {
  232.  *     ...
  233.  * }
  234.  * {@*} 
  235.  * </code>
  236.  * 
  237.  * Note that this procedure is exceptionally inefficient, and it would be far better
  238.  * to take advantage of PHP_LexerGenerator's top-down precedence and instead code:
  239.  * 
  240.  * <code>
  241.  * /*!lex2php
  242.  * "{@internal" {
  243.  *     ...
  244.  * }
  245.  * "{@" ALPHA {
  246.  *     ...
  247.  * }
  248.  * {@*} 
  249.  * </code>
  250.  * @package    PHP_LexerGenerator
  251.  * @author     Gregory Beaver <cellog@php.net>
  252.  * @copyright  2006 Gregory Beaver
  253.  * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
  254.  * @version    @package_version@
  255.  * @since      Class available since Release 0.1.0
  256.  * @example    TestLexer.plex Example lexer source
  257.  * @example    TestLexer.php  Example lexer generated php code
  258.  * @example    usage.php      Example usage of PHP_LexerGenerator
  259.  * @example    Lexer.plex     File_ChessPGN lexer source (complex)
  260.  * @example    Lexer.php      File_ChessPGN lexer generated php code
  261.  */
  262.  
  263. {
  264.     private $lex;
  265.     private $parser;
  266.     private $outfile;
  267.     /**
  268.      * Create a lexer file from its skeleton plex file.
  269.      *
  270.      * @param string $lexerfile path to the plex file
  271.      */
  272.     function __construct($lexerfile)
  273.     {
  274.         $this->lex new PHP_LexerGenerator_Lexer(file_get_contents($lexerfile));
  275.         $info pathinfo($lexerfile);
  276.         $this->outfile $info['dirname'DIRECTORY_SEPARATOR .
  277.             substr($info['basename']0,
  278.             strlen($info['basename']strlen($info['extension'])) 'php';
  279.         $this->parser new PHP_LexerGenerator_Parser($this->outfile$this->lex);
  280.         $this->parser->PrintTrace();
  281.         while ($this->lex->advance($this->parser)) {
  282.             $this->parser->doParse($this->lex->token$this->lex->value);
  283.         }
  284.         $this->parser->doParse(00);
  285.     }
  286. }
  287. //$a = new PHP_LexerGenerator('/development/File_ChessPGN/ChessPGN/Lexer.plex');
  288. ?>

Documentation generated on Sun, 02 Jul 2006 08:51:25 -0400 by phpDocumentor 1.3.0