From dcaa96a9f804ecb75d5d8e0138482c1cdf8d5c0f Mon Sep 17 00:00:00 2001 From: "monte.ohrt" Date: Sun, 22 Mar 2009 16:09:05 +0000 Subject: [PATCH] rearrange things into distribution and development directories --- demo/configs/test.conf | 22 + demo/index.php | 48 + demo/templates/header.tpl | 5 + demo/templates/include.tpl | 3 + demo/templates/index.tpl | 10 + demo/templates/index_view.php | 11 + demo/templates/nocache_inc.tpl | 2 + demo/templates/test_debug.tpl | 3 + demo/templates/test_if.tpl | 5 + demo/templates/test_inc.tpl | 25 + demo/templates/test_inc2.tpl | 6 + demo/templates/test_insert.tpl | 3 + demo/templates/test_nocache.tpl | 11 + demo/templates/test_nocache2.tpl | 9 + demo/templates/test_object.tpl | 6 + demo/templates/test_object2.tpl | 5 + demo/templates/test_parser.tpl | 7 + demo/templates/test_plugin.tpl | 7 + demo/templates/test_security.tpl | 7 + demo/templates/test_smoke.tpl | 159 ++ libs/Smarty.class.php | 423 +++ libs/debug.tpl | 135 + libs/lexer/Create_Config_Parser.php | 11 + libs/lexer/Create_Template_Parser.php | 20 + libs/lexer/Exception.php | 397 +++ libs/lexer/Lempar.php | 930 +++++++ libs/lexer/LexerGenerator.php | 289 ++ libs/lexer/LexerGenerator/Exception.php | 55 + libs/lexer/LexerGenerator/Lexer.php | 470 ++++ libs/lexer/LexerGenerator/Parser.php | 1937 ++++++++++++++ libs/lexer/LexerGenerator/Parser.y | 768 ++++++ libs/lexer/LexerGenerator/Regex/Lexer.php | 938 +++++++ libs/lexer/LexerGenerator/Regex/Parser.php | 1933 ++++++++++++++ libs/lexer/LexerGenerator/cli.php | 4 + libs/lexer/ParserGenerator.php | 760 ++++++ libs/lexer/ParserGenerator/Action.php | 240 ++ libs/lexer/ParserGenerator/ActionTable.php | 293 ++ libs/lexer/ParserGenerator/Config.php | 570 ++++ libs/lexer/ParserGenerator/Data.php | 1854 +++++++++++++ libs/lexer/ParserGenerator/Parser.php | 844 ++++++ .../lexer/ParserGenerator/PropagationLink.php | 117 + libs/lexer/ParserGenerator/Rule.php | 140 + libs/lexer/ParserGenerator/State.php | 277 ++ libs/lexer/ParserGenerator/Symbol.php | 284 ++ libs/lexer/ParserGenerator/cli.php | 5 + libs/lexer/internal.configfilelexer.plex | 108 + libs/lexer/internal.configfileparser.y | 123 + libs/lexer/internal.templatelexer.php | 708 +++++ libs/lexer/internal.templatelexer.plex | 382 +++ libs/lexer/internal.templateparser.php | 2350 +++++++++++++++++ libs/lexer/internal.templateparser.y | 452 ++++ libs/plugins/block.textformat.php | 103 + libs/plugins/function.counter.php | 78 + libs/plugins/function.cycle.php | 97 + libs/plugins/function.fetch.php | 217 ++ libs/plugins/function.html_checkboxes.php | 144 + libs/plugins/function.html_image.php | 138 + libs/plugins/function.html_options.php | 121 + libs/plugins/function.html_radios.php | 155 ++ libs/plugins/function.html_select_date.php | 330 +++ libs/plugins/function.html_select_time.php | 195 ++ libs/plugins/function.html_table.php | 176 ++ libs/plugins/function.mailto.php | 157 ++ libs/plugins/function.math.php | 84 + libs/plugins/function.popup.php | 118 + libs/plugins/function.popup_init.php | 41 + libs/plugins/modifier.capitalize.php | 41 + libs/plugins/modifier.cat.php | 31 + libs/plugins/modifier.count_characters.php | 29 + libs/plugins/modifier.count_paragraphs.php | 26 + libs/plugins/modifier.count_sentences.php | 27 + libs/plugins/modifier.count_words.php | 25 + libs/plugins/modifier.date_format.php | 56 + libs/plugins/modifier.debug_print_var.php | 89 + libs/plugins/modifier.default.php | 29 + libs/plugins/modifier.escape.php | 111 + libs/plugins/modifier.indent.php | 28 + libs/plugins/modifier.lower.php | 26 + libs/plugins/modifier.nl2br.php | 35 + libs/plugins/modifier.noprint.php | 24 + libs/plugins/modifier.regex_replace.php | 46 + libs/plugins/modifier.replace.php | 44 + libs/plugins/modifier.spacify.php | 27 + libs/plugins/modifier.string_format.php | 27 + libs/plugins/modifier.strip.php | 30 + libs/plugins/modifier.strip_tags.php | 29 + libs/plugins/modifier.truncate.php | 48 + libs/plugins/modifier.upper.php | 26 + libs/plugins/modifier.wordwrap.php | 29 + libs/plugins/outputfilter.trimwhitespace.php | 76 + libs/plugins/securitypolicy.default.php | 74 + libs/plugins/shared.escape_special_chars.php | 31 + libs/plugins/shared.make_timestamp.php | 43 + libs/sysplugins/internal.base.php | 24 + .../sysplugins/internal.cacher_inlinecode.php | 113 + .../internal.cacheresource_file.php | 170 ++ libs/sysplugins/internal.compile_assign.php | 52 + .../internal.compile_assign_global.php | 47 + libs/sysplugins/internal.compile_block.php | 37 + .../internal.compile_block_plugin.php | 57 + .../internal.compile_blockclose.php | 47 + libs/sysplugins/internal.compile_capture.php | 46 + .../internal.compile_captureclose.php | 39 + .../internal.compile_config_load.php | 53 + libs/sysplugins/internal.compile_debug.php | 34 + libs/sysplugins/internal.compile_else.php | 33 + libs/sysplugins/internal.compile_elseif.php | 36 + libs/sysplugins/internal.compile_eval.php | 46 + libs/sysplugins/internal.compile_extend.php | 69 + libs/sysplugins/internal.compile_for.php | 80 + libs/sysplugins/internal.compile_forclose.php | 38 + libs/sysplugins/internal.compile_foreach.php | 72 + .../internal.compile_foreachclose.php | 35 + .../internal.compile_foreachelse.php | 33 + libs/sysplugins/internal.compile_forelse.php | 37 + .../internal.compile_function_plugin.php | 46 + libs/sysplugins/internal.compile_if.php | 34 + libs/sysplugins/internal.compile_ifclose.php | 31 + libs/sysplugins/internal.compile_include.php | 103 + .../internal.compile_include_php.php | 70 + libs/sysplugins/internal.compile_insert.php | 74 + libs/sysplugins/internal.compile_nocache.php | 35 + .../internal.compile_nocacheclose.php | 35 + ...internal.compile_object_block_function.php | 58 + .../internal.compile_object_function.php | 47 + .../internal.compile_print_expression.php | 48 + libs/sysplugins/internal.compile_section.php | 112 + .../internal.compile_sectionclose.php | 36 + .../internal.compile_sectionelse.php | 34 + libs/sysplugins/internal.compile_smarty.php | 106 + libs/sysplugins/internal.compile_strip.php | 36 + .../internal.compile_stripclose.php | 35 + libs/sysplugins/internal.compile_while.php | 34 + .../internal.compile_whileclose.php | 31 + libs/sysplugins/internal.compilebase.php | 113 + libs/sysplugins/internal.compiler.php | 269 ++ libs/sysplugins/internal.config.php | 249 ++ .../internal.config_file_compiler.php | 116 + libs/sysplugins/internal.configfilelexer.php | 267 ++ libs/sysplugins/internal.configfileparser.php | 1162 ++++++++ libs/sysplugins/internal.debug.php | 59 + .../internal.phpvariableobjects.php | 159 ++ libs/sysplugins/internal.plugin_handler.php | 63 + libs/sysplugins/internal.pluginbase.php | 16 + libs/sysplugins/internal.resource_file.php | 120 + libs/sysplugins/internal.resource_php.php | 102 + libs/sysplugins/internal.resource_string.php | 94 + libs/sysplugins/internal.run_filter.php | 62 + libs/sysplugins/internal.security_handler.php | 111 + .../internal.smartytemplatecompiler.php | 73 + libs/sysplugins/internal.template.php | 563 ++++ libs/sysplugins/internal.templatebase.php | 380 +++ .../internal.templatecompilerbase.php | 258 ++ libs/sysplugins/internal.templatelexer.php | 708 +++++ libs/sysplugins/internal.templateparser.php | 2350 +++++++++++++++++ libs/sysplugins/internal.write_file.php | 47 + libs/sysplugins/method.clear_all_assign.php | 35 + libs/sysplugins/method.clear_all_cache.php | 41 + libs/sysplugins/method.clear_assign.php | 44 + libs/sysplugins/method.clear_cache.php | 44 + libs/sysplugins/method.clear_compiled_tpl.php | 71 + libs/sysplugins/method.clear_config.php | 37 + libs/sysplugins/method.config_load.php | 35 + libs/sysplugins/method.get_config_vars.php | 40 + libs/sysplugins/method.get_global.php | 44 + .../method.get_registered_object.php | 37 + libs/sysplugins/method.get_template_vars.php | 55 + libs/sysplugins/method.load_filter.php | 43 + libs/sysplugins/method.register_block.php | 40 + .../method.register_compiler_function.php | 39 + libs/sysplugins/method.register_function.php | 39 + libs/sysplugins/method.register_modifier.php | 39 + libs/sysplugins/method.register_object.php | 53 + .../method.register_outputfilter.php | 32 + .../sysplugins/method.register_postfilter.php | 32 + libs/sysplugins/method.register_prefilter.php | 33 + libs/sysplugins/method.register_resource.php | 40 + libs/sysplugins/method.template_exists.php | 39 + libs/sysplugins/method.test.php | 93 + libs/sysplugins/method.trigger_error.php | 33 + libs/sysplugins/method.unregister_block.php | 33 + .../method.unregister_compiler_function.php | 32 + .../sysplugins/method.unregister_function.php | 32 + .../sysplugins/method.unregister_modifier.php | 33 + libs/sysplugins/method.unregister_object.php | 31 + .../method.unregister_outputfilter.php | 32 + .../method.unregister_postfilter.php | 31 + .../method.unregister_prefilter.php | 31 + .../sysplugins/method.unregister_resource.php | 31 + 189 files changed, 32300 insertions(+) create mode 100644 demo/configs/test.conf create mode 100644 demo/index.php create mode 100644 demo/templates/header.tpl create mode 100644 demo/templates/include.tpl create mode 100644 demo/templates/index.tpl create mode 100644 demo/templates/index_view.php create mode 100644 demo/templates/nocache_inc.tpl create mode 100644 demo/templates/test_debug.tpl create mode 100644 demo/templates/test_if.tpl create mode 100644 demo/templates/test_inc.tpl create mode 100644 demo/templates/test_inc2.tpl create mode 100644 demo/templates/test_insert.tpl create mode 100644 demo/templates/test_nocache.tpl create mode 100644 demo/templates/test_nocache2.tpl create mode 100644 demo/templates/test_object.tpl create mode 100644 demo/templates/test_object2.tpl create mode 100644 demo/templates/test_parser.tpl create mode 100644 demo/templates/test_plugin.tpl create mode 100644 demo/templates/test_security.tpl create mode 100644 demo/templates/test_smoke.tpl create mode 100644 libs/Smarty.class.php create mode 100644 libs/debug.tpl create mode 100644 libs/lexer/Create_Config_Parser.php create mode 100644 libs/lexer/Create_Template_Parser.php create mode 100644 libs/lexer/Exception.php create mode 100644 libs/lexer/Lempar.php create mode 100644 libs/lexer/LexerGenerator.php create mode 100644 libs/lexer/LexerGenerator/Exception.php create mode 100644 libs/lexer/LexerGenerator/Lexer.php create mode 100644 libs/lexer/LexerGenerator/Parser.php create mode 100644 libs/lexer/LexerGenerator/Parser.y create mode 100644 libs/lexer/LexerGenerator/Regex/Lexer.php create mode 100644 libs/lexer/LexerGenerator/Regex/Parser.php create mode 100644 libs/lexer/LexerGenerator/cli.php create mode 100644 libs/lexer/ParserGenerator.php create mode 100644 libs/lexer/ParserGenerator/Action.php create mode 100644 libs/lexer/ParserGenerator/ActionTable.php create mode 100644 libs/lexer/ParserGenerator/Config.php create mode 100644 libs/lexer/ParserGenerator/Data.php create mode 100644 libs/lexer/ParserGenerator/Parser.php create mode 100644 libs/lexer/ParserGenerator/PropagationLink.php create mode 100644 libs/lexer/ParserGenerator/Rule.php create mode 100644 libs/lexer/ParserGenerator/State.php create mode 100644 libs/lexer/ParserGenerator/Symbol.php create mode 100644 libs/lexer/ParserGenerator/cli.php create mode 100644 libs/lexer/internal.configfilelexer.plex create mode 100644 libs/lexer/internal.configfileparser.y create mode 100644 libs/lexer/internal.templatelexer.php create mode 100644 libs/lexer/internal.templatelexer.plex create mode 100644 libs/lexer/internal.templateparser.php create mode 100644 libs/lexer/internal.templateparser.y create mode 100644 libs/plugins/block.textformat.php create mode 100644 libs/plugins/function.counter.php create mode 100644 libs/plugins/function.cycle.php create mode 100644 libs/plugins/function.fetch.php create mode 100644 libs/plugins/function.html_checkboxes.php create mode 100644 libs/plugins/function.html_image.php create mode 100644 libs/plugins/function.html_options.php create mode 100644 libs/plugins/function.html_radios.php create mode 100644 libs/plugins/function.html_select_date.php create mode 100644 libs/plugins/function.html_select_time.php create mode 100644 libs/plugins/function.html_table.php create mode 100644 libs/plugins/function.mailto.php create mode 100644 libs/plugins/function.math.php create mode 100644 libs/plugins/function.popup.php create mode 100644 libs/plugins/function.popup_init.php create mode 100644 libs/plugins/modifier.capitalize.php create mode 100644 libs/plugins/modifier.cat.php create mode 100644 libs/plugins/modifier.count_characters.php create mode 100644 libs/plugins/modifier.count_paragraphs.php create mode 100644 libs/plugins/modifier.count_sentences.php create mode 100644 libs/plugins/modifier.count_words.php create mode 100644 libs/plugins/modifier.date_format.php create mode 100644 libs/plugins/modifier.debug_print_var.php create mode 100644 libs/plugins/modifier.default.php create mode 100644 libs/plugins/modifier.escape.php create mode 100644 libs/plugins/modifier.indent.php create mode 100644 libs/plugins/modifier.lower.php create mode 100644 libs/plugins/modifier.nl2br.php create mode 100644 libs/plugins/modifier.noprint.php create mode 100644 libs/plugins/modifier.regex_replace.php create mode 100644 libs/plugins/modifier.replace.php create mode 100644 libs/plugins/modifier.spacify.php create mode 100644 libs/plugins/modifier.string_format.php create mode 100644 libs/plugins/modifier.strip.php create mode 100644 libs/plugins/modifier.strip_tags.php create mode 100644 libs/plugins/modifier.truncate.php create mode 100644 libs/plugins/modifier.upper.php create mode 100644 libs/plugins/modifier.wordwrap.php create mode 100644 libs/plugins/outputfilter.trimwhitespace.php create mode 100644 libs/plugins/securitypolicy.default.php create mode 100644 libs/plugins/shared.escape_special_chars.php create mode 100644 libs/plugins/shared.make_timestamp.php create mode 100644 libs/sysplugins/internal.base.php create mode 100644 libs/sysplugins/internal.cacher_inlinecode.php create mode 100644 libs/sysplugins/internal.cacheresource_file.php create mode 100644 libs/sysplugins/internal.compile_assign.php create mode 100644 libs/sysplugins/internal.compile_assign_global.php create mode 100644 libs/sysplugins/internal.compile_block.php create mode 100644 libs/sysplugins/internal.compile_block_plugin.php create mode 100644 libs/sysplugins/internal.compile_blockclose.php create mode 100644 libs/sysplugins/internal.compile_capture.php create mode 100644 libs/sysplugins/internal.compile_captureclose.php create mode 100644 libs/sysplugins/internal.compile_config_load.php create mode 100644 libs/sysplugins/internal.compile_debug.php create mode 100644 libs/sysplugins/internal.compile_else.php create mode 100644 libs/sysplugins/internal.compile_elseif.php create mode 100644 libs/sysplugins/internal.compile_eval.php create mode 100644 libs/sysplugins/internal.compile_extend.php create mode 100644 libs/sysplugins/internal.compile_for.php create mode 100644 libs/sysplugins/internal.compile_forclose.php create mode 100644 libs/sysplugins/internal.compile_foreach.php create mode 100644 libs/sysplugins/internal.compile_foreachclose.php create mode 100644 libs/sysplugins/internal.compile_foreachelse.php create mode 100644 libs/sysplugins/internal.compile_forelse.php create mode 100644 libs/sysplugins/internal.compile_function_plugin.php create mode 100644 libs/sysplugins/internal.compile_if.php create mode 100644 libs/sysplugins/internal.compile_ifclose.php create mode 100644 libs/sysplugins/internal.compile_include.php create mode 100644 libs/sysplugins/internal.compile_include_php.php create mode 100644 libs/sysplugins/internal.compile_insert.php create mode 100644 libs/sysplugins/internal.compile_nocache.php create mode 100644 libs/sysplugins/internal.compile_nocacheclose.php create mode 100644 libs/sysplugins/internal.compile_object_block_function.php create mode 100644 libs/sysplugins/internal.compile_object_function.php create mode 100644 libs/sysplugins/internal.compile_print_expression.php create mode 100644 libs/sysplugins/internal.compile_section.php create mode 100644 libs/sysplugins/internal.compile_sectionclose.php create mode 100644 libs/sysplugins/internal.compile_sectionelse.php create mode 100644 libs/sysplugins/internal.compile_smarty.php create mode 100644 libs/sysplugins/internal.compile_strip.php create mode 100644 libs/sysplugins/internal.compile_stripclose.php create mode 100644 libs/sysplugins/internal.compile_while.php create mode 100644 libs/sysplugins/internal.compile_whileclose.php create mode 100644 libs/sysplugins/internal.compilebase.php create mode 100644 libs/sysplugins/internal.compiler.php create mode 100644 libs/sysplugins/internal.config.php create mode 100644 libs/sysplugins/internal.config_file_compiler.php create mode 100644 libs/sysplugins/internal.configfilelexer.php create mode 100644 libs/sysplugins/internal.configfileparser.php create mode 100644 libs/sysplugins/internal.debug.php create mode 100644 libs/sysplugins/internal.phpvariableobjects.php create mode 100644 libs/sysplugins/internal.plugin_handler.php create mode 100644 libs/sysplugins/internal.pluginbase.php create mode 100644 libs/sysplugins/internal.resource_file.php create mode 100644 libs/sysplugins/internal.resource_php.php create mode 100644 libs/sysplugins/internal.resource_string.php create mode 100644 libs/sysplugins/internal.run_filter.php create mode 100644 libs/sysplugins/internal.security_handler.php create mode 100644 libs/sysplugins/internal.smartytemplatecompiler.php create mode 100644 libs/sysplugins/internal.template.php create mode 100644 libs/sysplugins/internal.templatebase.php create mode 100644 libs/sysplugins/internal.templatecompilerbase.php create mode 100644 libs/sysplugins/internal.templatelexer.php create mode 100644 libs/sysplugins/internal.templateparser.php create mode 100644 libs/sysplugins/internal.write_file.php create mode 100644 libs/sysplugins/method.clear_all_assign.php create mode 100644 libs/sysplugins/method.clear_all_cache.php create mode 100644 libs/sysplugins/method.clear_assign.php create mode 100644 libs/sysplugins/method.clear_cache.php create mode 100644 libs/sysplugins/method.clear_compiled_tpl.php create mode 100644 libs/sysplugins/method.clear_config.php create mode 100644 libs/sysplugins/method.config_load.php create mode 100644 libs/sysplugins/method.get_config_vars.php create mode 100644 libs/sysplugins/method.get_global.php create mode 100644 libs/sysplugins/method.get_registered_object.php create mode 100644 libs/sysplugins/method.get_template_vars.php create mode 100644 libs/sysplugins/method.load_filter.php create mode 100644 libs/sysplugins/method.register_block.php create mode 100644 libs/sysplugins/method.register_compiler_function.php create mode 100644 libs/sysplugins/method.register_function.php create mode 100644 libs/sysplugins/method.register_modifier.php create mode 100644 libs/sysplugins/method.register_object.php create mode 100644 libs/sysplugins/method.register_outputfilter.php create mode 100644 libs/sysplugins/method.register_postfilter.php create mode 100644 libs/sysplugins/method.register_prefilter.php create mode 100644 libs/sysplugins/method.register_resource.php create mode 100644 libs/sysplugins/method.template_exists.php create mode 100644 libs/sysplugins/method.test.php create mode 100644 libs/sysplugins/method.trigger_error.php create mode 100644 libs/sysplugins/method.unregister_block.php create mode 100644 libs/sysplugins/method.unregister_compiler_function.php create mode 100644 libs/sysplugins/method.unregister_function.php create mode 100644 libs/sysplugins/method.unregister_modifier.php create mode 100644 libs/sysplugins/method.unregister_object.php create mode 100644 libs/sysplugins/method.unregister_outputfilter.php create mode 100644 libs/sysplugins/method.unregister_postfilter.php create mode 100644 libs/sysplugins/method.unregister_prefilter.php create mode 100644 libs/sysplugins/method.unregister_resource.php diff --git a/demo/configs/test.conf b/demo/configs/test.conf new file mode 100644 index 00000000..80cfea45 --- /dev/null +++ b/demo/configs/test.conf @@ -0,0 +1,22 @@ +title = Welcome to Smarty! +cutoff_size = 40 +bold = false +pageTitle = "This is mine" +bodyBgColor = '#eeeeee' +tableBorderSize = 3 +tableBgColor = "#bbbbbb" +rowBgColor = #cccccc + +Intro = """This is a value that spans more + than one line. you must enclose + it in triple quotes.""" + +Quote1 = """'value should contain a +sigle quote'""" + +Quote2 = """ "value should contain a " double quote" """ + +[setup] +bold = true + +[params] diff --git a/demo/index.php b/demo/index.php new file mode 100644 index 00000000..2ae64c0a --- /dev/null +++ b/demo/index.php @@ -0,0 +1,48 @@ + +* @package SmartyTestScripts +*/ +require('./libs/Smarty.class.php'); +ini_set('short_open_tag','1'); + + class Person +{ + private $m_szName; + private $m_iAge; + + public function setName($szName) + { + $this->m_szName = $szName; + return $this; // We now return $this (the Person) + } + + public function setAge($iAge) + { + $this->m_iAge = $iAge; + return $this; // Again, return our Person + } + + public function introduce() + { + return 'Hello my name is '.$this->m_szName.' and I am '.$this->m_iAge.' years old.'; + } +} + +$smarty = new Smarty(); +$smarty->force_compile = false; +$smarty->caching = false; +$smarty->caching_lifetime = 10; + +$smarty->assign('foo',''); + +$person = new Person; + +$smarty->assign('person',$person); + +$smarty->assign('array',array('a'=>array('aa'=>'This is a long string'),'b'=>2)); + +$smarty->display('php:index_view.php'); + +?> diff --git a/demo/templates/header.tpl b/demo/templates/header.tpl new file mode 100644 index 00000000..f161a929 --- /dev/null +++ b/demo/templates/header.tpl @@ -0,0 +1,5 @@ +This is the header + +gee is {$gee} foo is {$foo} + +done with header diff --git a/demo/templates/include.tpl b/demo/templates/include.tpl new file mode 100644 index 00000000..56088dc5 --- /dev/null +++ b/demo/templates/include.tpl @@ -0,0 +1,3 @@ + +Include file +
{assign var=inc value='assign include'}{$inc} diff --git a/demo/templates/index.tpl b/demo/templates/index.tpl new file mode 100644 index 00000000..2398756f --- /dev/null +++ b/demo/templates/index.tpl @@ -0,0 +1,10 @@ +This is an example of a compiled template. + +$foo = {$foo} +$foo[0] = {$foo[0]} +$foo[1] = {$foo[1]} +$foo[2] = {$foo[2]} + +function: + +End Test diff --git a/demo/templates/index_view.php b/demo/templates/index_view.php new file mode 100644 index 00000000..56f27386 --- /dev/null +++ b/demo/templates/index_view.php @@ -0,0 +1,11 @@ +PHP file test +$foo is +
Test modifier chaining +trim()->escape('html')?> +
Test objects +setName('Paul')->setAge(39)->introduce()->trim()->truncate(10)?> +
Arrays +truncate(5)?> +
Function +trim($array['a']['aa'])->truncate(10)?> +DONE diff --git a/demo/templates/nocache_inc.tpl b/demo/templates/nocache_inc.tpl new file mode 100644 index 00000000..81f5c359 --- /dev/null +++ b/demo/templates/nocache_inc.tpl @@ -0,0 +1,2 @@ +
This is from nocache_inc.tpl +
cached time is {time()} diff --git a/demo/templates/test_debug.tpl b/demo/templates/test_debug.tpl new file mode 100644 index 00000000..b55eeb49 --- /dev/null +++ b/demo/templates/test_debug.tpl @@ -0,0 +1,3 @@ + +Test debug +{debug} diff --git a/demo/templates/test_if.tpl b/demo/templates/test_if.tpl new file mode 100644 index 00000000..d7a00d49 --- /dev/null +++ b/demo/templates/test_if.tpl @@ -0,0 +1,5 @@ +Test of if tags
+{foreach item=value from=$values} +Value of {$value} is {if $value<10} less then 10 {elseif ($value GT 100) AND ($value <= 500)} something between 100 and 500 {else} somthing else {/if}
+{/foreach} + diff --git a/demo/templates/test_inc.tpl b/demo/templates/test_inc.tpl new file mode 100644 index 00000000..068017e7 --- /dev/null +++ b/demo/templates/test_inc.tpl @@ -0,0 +1,25 @@ +Test of { include } and local/global variable scope +
the original value of $foo = {$foo} +
+{assign var=foo2 value='yzx'} +
foo2 before { include } = {$foo2} +{include file='test_inc2.tpl'} +
+
Here we are back in test_inc.tpl +
$foo has its old value = {$foo} +
this is $foo2 a global variable created in test_inc2.tpl = {$foo2} +
{if isset($foo3)} $foo3 must be unknow here {/if} +
+
Test include with parent scope +{include file='test_inc2.tpl' scope='parent'} +
Here we are back in test_inc.tpl +
$foo has its new value = {$foo} +
this is $foo2 a global variable created in test_inc2.tpl = {$foo2} +
this is $foo3 a normal variable created in test_inc2.tpl = {$foo3} +
+
Test include with root scope +{include file='test_inc2.tpl' scope='root'} +
Here we are back in test_inc.tpl +
$foo has its new value = {$foo} +
this is $foo2 a global variable created in test_inc2.tpl = {$foo2} +
this is $foo3 a normal variable created in test_inc2.tpl = {$foo3} diff --git a/demo/templates/test_inc2.tpl b/demo/templates/test_inc2.tpl new file mode 100644 index 00000000..c4b0ef65 --- /dev/null +++ b/demo/templates/test_inc2.tpl @@ -0,0 +1,6 @@ +
Here starts test_inc2.tpl +
$foo in test_inc2 before changing = {$foo} +{assign var=foo value="bah"} +
$foo in test_inc2 after changing = {$foo} +{assign var=foo2 value="bla" global=true} +{assign var=foo3 value="foo3 was set"} diff --git a/demo/templates/test_insert.tpl b/demo/templates/test_insert.tpl new file mode 100644 index 00000000..84d9074b --- /dev/null +++ b/demo/templates/test_insert.tpl @@ -0,0 +1,3 @@ +Test of { insert } +
{insert name='test' foo='bar'} +
insert with assign {insert name='test' foo='bar' assign=var}{$var} diff --git a/demo/templates/test_nocache.tpl b/demo/templates/test_nocache.tpl new file mode 100644 index 00000000..39aba1ff --- /dev/null +++ b/demo/templates/test_nocache.tpl @@ -0,0 +1,11 @@ +Test caching and nocache attribute +
cached time is {time()} +
nocached time by '{time() nocache=true}' {time() nocache=true} +
+
calling '{include file="nocache_inc.tpl" caching_lifetime=25}' {include file="nocache_inc.tpl" caching_lifetime=25} +
+
calling '{include file="nocache_inc.tpl" nocache=true}' {include file="nocache_inc.tpl" nocache=true} +{nocache} +{assign var=a value=1} +
{if $a < 5}{$a|truncate} lt 5{else}a ge 5{/if} +{/nocache} \ No newline at end of file diff --git a/demo/templates/test_nocache2.tpl b/demo/templates/test_nocache2.tpl new file mode 100644 index 00000000..9da14b6d --- /dev/null +++ b/demo/templates/test_nocache2.tpl @@ -0,0 +1,9 @@ +Test caching and nocache attribute +
cached time is {$t1} +
nocached time is {$t2} +
+{$t1+$t1} {$t1+$t2} +
+{nocache} +{for $i=0;$i<10;$i++}{$i}{/for} +{/nocache} diff --git a/demo/templates/test_object.tpl b/demo/templates/test_object.tpl new file mode 100644 index 00000000..63004556 --- /dev/null +++ b/demo/templates/test_object.tpl @@ -0,0 +1,6 @@ + +Test methode chaining +{assign var=x value=33} +
{assign var=x2 value=10}{$person->object->setName('peter')->setAge($x+4)->introduce()} +
{$person->object->setAge($x+$x2)->setName('paul')->introduce()} + diff --git a/demo/templates/test_object2.tpl b/demo/templates/test_object2.tpl new file mode 100644 index 00000000..8d573d19 --- /dev/null +++ b/demo/templates/test_object2.tpl @@ -0,0 +1,5 @@ + +Test registered object +
{/test->hello} +
{/test->hello p1=1 p2=2} + diff --git a/demo/templates/test_parser.tpl b/demo/templates/test_parser.tpl new file mode 100644 index 00000000..3250958d --- /dev/null +++ b/demo/templates/test_parser.tpl @@ -0,0 +1,7 @@ +Input form for parser testing
+
+Template input + + +
+ diff --git a/demo/templates/test_plugin.tpl b/demo/templates/test_plugin.tpl new file mode 100644 index 00000000..e550dd6e --- /dev/null +++ b/demo/templates/test_plugin.tpl @@ -0,0 +1,7 @@ +Test of function plugin +{nocache} +{counter assign=foo start=10 skip=5} +
{$foo} +{counter} +
{$foo} +{/nocache} diff --git a/demo/templates/test_security.tpl b/demo/templates/test_security.tpl new file mode 100644 index 00000000..e550dd6e --- /dev/null +++ b/demo/templates/test_security.tpl @@ -0,0 +1,7 @@ +Test of function plugin +{nocache} +{counter assign=foo start=10 skip=5} +
{$foo} +{counter} +
{$foo} +{/nocache} diff --git a/demo/templates/test_smoke.tpl b/demo/templates/test_smoke.tpl new file mode 100644 index 00000000..d88e2bcf --- /dev/null +++ b/demo/templates/test_smoke.tpl @@ -0,0 +1,159 @@ +
SMARTY SMOKE TEST
+
+VARIABLE TESTS:
+
+$foo is {$foo}
+
+$baz[1] is {$baz[1]}
+
+$blah['b'] is {$blah['b']}
+
+$blah[$baz[1]] is {$blah[$baz[1]]}
+
+$foo.$baz[1] is {$foo.$baz[1]}
+
+$foo.$foo is {$foo.$foo}
+
+{"foo"}
+
+OBJECT TESTS:
+
+$myobj->foo is {$myobj->foo}
+
+$myobj->test is {$myobj->test}
+$myobj->test() is {$myobj->test()}
+$myobj->test(1) is {$myobj->test(1)}
+$myobj->test(1,'two') is {$myobj->test(1,'two')}
+$myobj->test(count($baz)) is {$myobj->test(count($baz))}
+$myobj->test($myobj->test(count($baz))) is {$myobj->test($myobj->test(count($baz)))}
+$myobj->test($foo|escape) is {$myobj->test($foo|escape)}
+
+PHP TESTS:
+
+
+COMMENT TESTS:
+
+{* this is a comment *}
+{* another $foo comment *}
+{* another  comment *}
+{* multi line
+   comment *}
+{* /* foo */ *}
+A{* comment *}B
+C
+D{* comment *}
+{* comment *}E
+F
+G{* multi
+ line *}H
+I{* multi
+line *}
+J
+
+ASSIGN:
+
+A
+{assign var=zoo value="blah"}
+B
+C{assign var=zoo value="blah"}D
+E{assign var=zoo value="blah"}
+F
+G
+{assign var=zoo value="blah"}H
+{assign var=zoo value="joe{$myobj->test(1)}bar"}
+
+zoo is {$zoo}
+
+SPACING TESTS:
+
+{$foo}
+
+{$foo}{$foo}
+
+A{$foo}
+
+A{$foo}B
+
+{$foo}B
+
+IF TESTS:
+
+{if $foo eq "baz"}
+  IS BAZ
+{elseif $foo == "lala"}
+  IS LALA
+{else}
+  IS NONE
+{/if}
+
+{if $myint+5 EQ 9}
+  IS NINE
+{else}
+  IS NOT NINE
+{/if}
+
+{if $myint + 5 eq 9}
+  IS NINE
+{else}
+  IS NOT NINE
+{/if}
+
+{if count($baz)-2 eq 1}
+  IS ONE
+{else}
+  IS NOT ONE
+{/if}
+
+{if $foo.$foo2 eq "barbar2"}
+  IS BARBAR2
+{else}
+  IS NOT BARBAR2
+{/if}
+
+{if $not_logged}
+  NOT LOGGED
+{/if}
+
+{if "joe{$myobj->test(1)}bar"}
+  FOO
+{/if}
+
+TEST INCLUDE:
+
+{include file="header.tpl" gee="joe"}
+{include file="header.tpl" gee="joe $foo bar"}
+{include file="header.tpl" gee="joe{$foo}bar"}
+{include file="header.tpl" gee="joe{$foo.$foo}bar"}
+{include file="header.tpl" gee="joe{$myobj->test(1)}bar"}
+{include file=$includeme}
+{include file=$includeme gee="joe"}
+{include file="{$top}.tpl"}
+
+JAVSCRIPT TEST
+
+
+
+MATH TESTS:
+
+$one+2 is {$one+2}
+$one + 2 - $one is {$one + 2 - $one}
+$one*$one is {$one*$one}
+$one/$one is {$one/$one}
+abs(-$one) is {abs(-$one)}
+
+$footest is {$footest}
+
+FOREACH TESTS:
+
+{foreach from=$blah key="idx" item="val"}
+  $idx/$val is {$idx}/{$val}
+{/foreach}
+
+TEST FINISHED
+
diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php new file mode 100644 index 00000000..27d79b4d --- /dev/null +++ b/libs/Smarty.class.php @@ -0,0 +1,423 @@ + +* @author Uwe Tews +* @package Smarty +* @version 3.0-alpha1 +*/ + +/** +* set SMARTY_DIR to absolute path to Smarty library files. +* if not defined, include_path will be used. Sets SMARTY_DIR only if user +* application has not already defined it. +*/ + +if (!defined('SMARTY_DIR')) { + define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); +} + +/** +* load required base class for creation of the smarty object +*/ +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'sysplugins' . DIRECTORY_SEPARATOR . 'internal.templatebase.php'); + +/** +* This is the main Smarty class +*/ +class Smarty extends Smarty_Internal_TemplateBase { + // smarty version + static $_version = 'Smarty3Alpha'; + // class used for templates + public $template_class = 'Smarty_Internal_Template'; + // display error on not assigned variabled + static $error_unassigned = false; + // template directory + public $template_dir = null; + // compile directory + public $compile_dir = null; + // plugins directory + public $plugins_dir = null; + // cache directory + public $cache_dir = null; + // config directory + public $config_dir = null; + // force template compiling? + public $force_compile = false; + // use sub dirs for compiled/cached files? + public $use_sub_dirs = false; + // php file extention + public $php_ext = '.php'; + // compile_error? + public $compile_error = false; + // caching enabled + public $caching = false; + // caching lifetime + public $caching_lifetime = 0; + // cache_id + public $cache_id = null; + // compile_id + public $compile_id = null; + // template delimiters + public $left_delimiter = "{"; + public $right_delimiter = "}"; + // security + public $security = false; + public $security_policy = null; + public $security_handler = null; + public $direct_access_security = true; + // debug mode + public $debugging = false; + public $debugging_ctrl = 'URL'; + public $smarty_debug_id = 'SMARTY_DEBUG'; + public $request_use_auto_globals = true; + public $debug_tpl = null; + // When set, smarty does uses this value as error_reporting-level. + public $error_reporting = null; + // config var settings + public $config_overwrite = true; //Controls whether variables with the same name overwrite each other. + public $config_booleanize = true; //Controls whether config values of on/true/yes and off/false/no get converted to boolean + public $config_read_hidden = true; //Controls whether hidden config sections/vars are read from the file. + // config vars + public $config_vars = array(); + // assigned tpl vars + public $tpl_vars = array(); + // assigned global tpl vars + public $global_tpl_vars = array(); + // dummy parent object + public $parent = null; + // system plugins directory + private $sysplugins_dir = null; + // resource type used if none given + public $default_resource_type = 'file'; + // charset of template + public $resource_char_set = 'UTF-8'; + // caching type + public $default_caching_type = 'file'; + // internal cache resource types + public $cache_resorce_types = array('file'); + // config type + public $default_config_type = 'file'; + // class used for cacher + public $cacher_class = 'Smarty_Internal_Cacher_InlineCode'; + // exception handler: set null to disable + public $exception_handler = array('SmartyException', 'getStaticException'); + // cached template objects + static $template_objects = null; + // autoload filter + public $autoload_filters = array(); + // check If-Modified-Since headers + public $cache_modified_check = false; + // registered plugins + public $registered_plugins = array(); + // plugin search order + public $plugin_search_order = array('function', 'block', 'compiler', 'class'); + // plugin handler object + public $plugin_handler = null; + // registered objects + public $registered_objects = array(); + // registered filters + public $registered_filters = array(); + // filter handler + public $filter_handler = null; + // cache resorce objects + public $cache_resource_objects = array(); + // write file object + public $write_file_object = null; + // global smarty vars + public $_smarty_vars = array(); + // start time for execution time calculation + public $start_time = 0; + + /** + * Class constructor, initializes basic smarty properties + */ + public function __construct() + { + mb_internal_encoding($this->resource_char_set); + $this->start_time = $this->_get_time(); + // set exception handler + if (!empty($this->exception_handler)) + set_exception_handler($this->exception_handler); + // set default dirs + $this->template_dir = '.' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR; + $this->compile_dir = '.' . DIRECTORY_SEPARATOR . 'templates_c' . DIRECTORY_SEPARATOR; + $this->plugins_dir = array(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR); + $this->cache_dir = '.' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR; + $this->config_dir = '.' . DIRECTORY_SEPARATOR . 'configs' . DIRECTORY_SEPARATOR; + $this->sysplugins_dir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'sysplugins' . DIRECTORY_SEPARATOR; + // set instance object + self::instance($this); + // load base plugins + $this->loadPlugin('Smarty_Internal_Base'); + $this->loadPlugin('Smarty_Internal_PluginBase'); + $this->loadPlugin($this->template_class); + $this->loadPlugin('Smarty_Internal_Plugin_Handler'); + $this->plugin_handler = new Smarty_Internal_Plugin_Handler; + if (!$this->debugging && $this->debugging_ctrl == 'URL') { + $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; + if (false !== strpos($_query_string, $this->smarty_debug_id)) { + if (false !== strpos($_query_string, $this->smarty_debug_id . '=on')) { + // enable debugging for this browser session + setcookie('SMARTY_DEBUG', true); + $this->debugging = true; + } elseif (false !== strpos($_query_string, $this->smarty_debug_id . '=off')) { + // disable debugging for this browser session + setcookie('SMARTY_DEBUG', false); + $this->debugging = false; + } else { + // enable debugging for this page + $this->debugging = true; + } + } else { + if ($this->request_use_auto_globals && isset($_COOKIE['SMARTY_DEBUG'])) { + $this->debugging = true; + } elseif (!$this->request_use_auto_globals && isset($GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG'])) { + $this->debugging = true; + } + } + } + } + + /** + * Class destructor + */ + public function __destruct() + { + // restore to previous exception handler, if any + if (!empty($this->exception_handler)) + restore_exception_handler(); + } + + /** + * Sets a static instance of the smarty object. Retrieve with: + * $smarty = Smarty::instance(); + * + * @param object $new_instance the Smarty object when setting + * @return object reference to Smarty object + */ + public static function &instance($new_instance = null) + { + static $instance = null; + if (isset($new_instance) && is_object($new_instance)) + $instance = $new_instance; + return $instance; + } + + /** + * fetches a rendered Smarty template + * + * @param string $template the resource handle of the template file or template object + * @param object $ |null $parent next higher level of Smarty variables + * @param mixed $cache_id cache id to be used with this template + * @param mixed $compile_id compile id to be used with this template + * @return string rendered template output + */ + public function fetch($template, $parent = null, $cache_id = null, $compile_id = null) + { + if ($parent === null) { + // get default Smarty data object + $parent = $this; + } + // create template object if necessary + ($template instanceof $this->template_class)? $_template = $template : + $_template = $this->createTemplate ($template, $parent , $cache_id, $compile_id); +// $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting) +// ? $this->error_reporting : error_reporting() &~E_NOTICE); + // return redered template + $_output = $_template->getRenderedTemplate(); + $_template->rendered_content = null; +// error_reporting($_smarty_old_error_level); + return $_output; + } + + /** + * displays a Smarty template + * + * @param string $ |object $template the resource handle of the template file or template object + * @param object $parent next higher level of Smarty variables + * @param mixed $cache_id cache id to be used with this template + * @param mixed $compile_id compile id to be used with this template + */ + public function display($template, $parent = null, $cache_id = null, $compile_id = null) + { + // display template + echo $this->fetch ($template, $parent , $cache_id, $compile_id); + // debug output? + if ($this->debugging) { + $this->loadPlugin('Smarty_Internal_Debug'); + Smarty_Internal_Debug::display_debug(); + } + return true; + } + + /** + * test if cache i valid + * + * @param string $ |object $template the resource handle of the template file or template object + * @param mixed $cache_id cache id to be used with this template + * @param mixed $compile_id compile id to be used with this template + * @return boolean cache status + */ + public function is_cached($template, $cache_id = null, $compile_id = null) + { + if (!($template instanceof $this->template_class)) { + $template = $this->createTemplate ($template, $this, $cache_id, $compile_id); + } + // return cache status of template + return $template->isCached(); + } + + /** + * Load the plugin with securty definition and enables security + * + * @param string $security_policy plugin to load + */ + public function enableSecurity($security_policy = 'Smarty_SecurityPolicy_Default') + { + if ($this->loadPlugin($security_policy)) { + if (!class_exists('Smarty_Security_Policy')) { + throw new Exception("Security policy must define class 'Smarty_Security_Policy'"); + } + $this->security_policy = new Smarty_Security_Policy(); + $this->loadPlugin('Smarty_Internal_Security_Handler'); + $this->security_handler = new Smarty_Internal_Security_Handler(); + $this->security = true; + } else { + throw new Exception("Security policy {$security_definition} not found"); + } + } + + /** + * Takes unknown classes and loads plugin files for them + * class name format: Smarty_PluginType_PluginName + * plugin filename format: plugintype.pluginname.php + * + * @param string $plugin_name class plugin name to load + * @return boolean + */ + public function loadPlugin($plugin_name) + { + // if class exists, exit silently (already loaded) + if (class_exists($plugin_name, false)) + return true; + // if callable as function, exit silently (already loaded) + if (is_callable($plugin_name)) + return true; + // Plugin name is expected to be: Smarty_[Type]_[Name] + $plugin_name = strtolower($plugin_name); + $name_parts = explode('_', $plugin_name, 3); + // class name must have three parts to be valid plugin + if (count($name_parts) < 3 || $name_parts[0] !== 'smarty') { + throw new Exception("plugin {$plugin_name} is not a valid name format"); + return false; + } + // plugin filename is expected to be: [type].[name].php + $plugin_filename = "{$name_parts[1]}.{$name_parts[2]}{$this->php_ext}"; + // if type is "internal", get plugin from sysplugins + if ($name_parts[1] == 'internal') { + if (file_exists($this->sysplugins_dir . $plugin_filename)) { + require_once($this->sysplugins_dir . $plugin_filename); + return true; + } else { + return false; + } + } + // loop through plugin dirs and find the plugin + foreach((array)$this->plugins_dir as $plugin_dir) { + if (file_exists($plugin_dir . $plugin_filename)) { + require_once($plugin_dir . $plugin_filename); + return true; + } + } + // no plugin loaded + return false; + } + + /** + * Sets the exception handler for Smarty. + * + * @param mixed $handler function name or array with object/method names + * @return string previous exception handler + */ + public function setExceptionHandler($handler) + { + $this->exception_handler = $handler; + return set_exception_handler($handler); + } + + /** + * Takes unknown class methods and lazy loads sysplugin files for them + * class name format: Smarty_Method_MethodName + * plugin filename format: method.methodname.php + * + * @param string $name unknown methode name + * @param array $args aurgument array + */ + public function __call($name, $args) + { + $class_name = "Smarty_Method_{$name}"; + if (!class_exists($class_name, false)) { + $plugin_filename = strtolower('method.' . $name . $this->php_ext); + if (!file_exists($this->sysplugins_dir . $plugin_filename)) { + throw new Exception("Sysplugin file " . $plugin_filename . " does not exist"); + die(); + } + require_once($this->sysplugins_dir . $plugin_filename); + if (!class_exists($class_name, false)) { + throw new Exception ("Sysplugin file " . $plugin_filename . " does not define class " . $class_name); + die(); + } + } + $method = new $class_name; + return call_user_func_array(array($method, 'execute'), $args); + } +} + +/** +* Smarty Exception Handler +* +* All errors thrown in Smarty will be handled here. +* +* @param string $message the error message +* @param string $code the error code +*/ +class SmartyException { + public function printException($e) + { + echo "Code: " . $e->getCode() . "
Error: " . htmlentities($e->getMessage()) . "
" + . "File: " . $e->getFile() . "
" + . "Line: " . $e->getLine() . "
" + . "\n"; + } + + public static function getStaticException($e) + { + self::printException($e); + } +} + +?> diff --git a/libs/debug.tpl b/libs/debug.tpl new file mode 100644 index 00000000..585573c4 --- /dev/null +++ b/libs/debug.tpl @@ -0,0 +1,135 @@ +{capture assign=debug_output} + + + + Smarty Debug Console + + + + +

Smarty Debug Console - Total Time {$execution_time|string_format:"%.5f"}

+ +

included templates & config files (load time in seconds)

+ +
+{for $template in $template_data} + {$template.name} + + (compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"}) + +
+{/for} +
+ +

assigned template variables

+ + + {for $vars in $assigned_vars} + + + + {/for} +
${$vars@key|escape:'html'}{$vars|debug_print_var}
+ +

assigned config file variables (outer template scope)

+ + + {for $vars in $config_vars} + + + + {/for} + +
{$vars@key|escape:'html'}{$vars|debug_print_var}
+ + +{/capture} + + diff --git a/libs/lexer/Create_Config_Parser.php b/libs/lexer/Create_Config_Parser.php new file mode 100644 index 00000000..6c58461a --- /dev/null +++ b/libs/lexer/Create_Config_Parser.php @@ -0,0 +1,11 @@ + diff --git a/libs/lexer/Create_Template_Parser.php b/libs/lexer/Create_Template_Parser.php new file mode 100644 index 00000000..a75062c2 --- /dev/null +++ b/libs/lexer/Create_Template_Parser.php @@ -0,0 +1,20 @@ +ldel."','".$this->rdel."'),$contents); +//$contents = preg_replace('%/\*[\s\S]+?\*/|(?://|#).*(?:\r\n|\n)%m', '', $contents); +file_put_contents('internal.templatelexer.php', $contents); +//$contents = file_get_contents('internal.templateparser.php'); +//$contents = preg_replace('%/\*[\s\S]+?\*/|(?://|#).*(?:\r\n|\n)%m', '', $contents); +//file_put_contents('internal.templateparser.php', $contents); +copy('internal.templatelexer.php','../sysplugins/internal.templatelexer.php'); +copy('internal.templateparser.php','../sysplugins/internal.templateparser.php'); +//unlink('internal.templatelexer.php'); +//unlink('internal.templateparser.php'); + +?> diff --git a/libs/lexer/Exception.php b/libs/lexer/Exception.php new file mode 100644 index 00000000..b16cc7bb --- /dev/null +++ b/libs/lexer/Exception.php @@ -0,0 +1,397 @@ + + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Exception.php,v 1.29 2008/01/03 20:26:35 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.3 + */ + + +/** + * Base PEAR_Exception Class + * + * 1) Features: + * + * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) + * - Definable triggers, shot when exceptions occur + * - Pretty and informative error messages + * - Added more context info available (like class, method or cause) + * - cause can be a PEAR_Exception or an array of mixed + * PEAR_Exceptions/PEAR_ErrorStack warnings + * - callbacks for specific exception classes and their children + * + * 2) Ideas: + * + * - Maybe a way to define a 'template' for the output + * + * 3) Inherited properties from PHP Exception Class: + * + * protected $message + * protected $code + * protected $line + * protected $file + * private $trace + * + * 4) Inherited methods from PHP Exception Class: + * + * __clone + * __construct + * getMessage + * getCode + * getFile + * getLine + * getTraceSafe + * getTraceSafeAsString + * __toString + * + * 5) Usage example + * + * + * require_once 'PEAR/Exception.php'; + * + * class Test { + * function foo() { + * throw new PEAR_Exception('Error Message', ERROR_CODE); + * } + * } + * + * function myLogger($pear_exception) { + * echo $pear_exception->getMessage(); + * } + * // each time a exception is thrown the 'myLogger' will be called + * // (its use is completely optional) + * PEAR_Exception::addObserver('myLogger'); + * $test = new Test; + * try { + * $test->foo(); + * } catch (PEAR_Exception $e) { + * print $e; + * } + * + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.3 + * + */ +class PEAR_Exception extends Exception +{ + const OBSERVER_PRINT = -2; + const OBSERVER_TRIGGER = -4; + const OBSERVER_DIE = -8; + protected $cause; + private static $_observers = array(); + private static $_uniqueid = 0; + private $_trace; + + /** + * Supported signatures: + * - PEAR_Exception(string $message); + * - PEAR_Exception(string $message, int $code); + * - PEAR_Exception(string $message, Exception $cause); + * - PEAR_Exception(string $message, Exception $cause, int $code); + * - PEAR_Exception(string $message, PEAR_Error $cause); + * - PEAR_Exception(string $message, PEAR_Error $cause, int $code); + * - PEAR_Exception(string $message, array $causes); + * - PEAR_Exception(string $message, array $causes, int $code); + * @param string exception message + * @param int|Exception|PEAR_Error|array|null exception cause + * @param int|null exception code or null + */ + public function __construct($message, $p2 = null, $p3 = null) + { + if (is_int($p2)) { + $code = $p2; + $this->cause = null; + } elseif (is_object($p2) || is_array($p2)) { + // using is_object allows both Exception and PEAR_Error + if (is_object($p2) && !($p2 instanceof Exception)) { + if (!class_exists('PEAR_Error',false) || !($p2 instanceof PEAR_Error)) { + throw new PEAR_Exception('exception cause must be Exception, ' . + 'array, or PEAR_Error'); + } + } + $code = $p3; + if (is_array($p2) && isset($p2['message'])) { + // fix potential problem of passing in a single warning + $p2 = array($p2); + } + $this->cause = $p2; + } else { + $code = null; + $this->cause = null; + } + parent::__construct($message, $code); + $this->signal(); + } + + /** + * @param mixed $callback - A valid php callback, see php func is_callable() + * - A PEAR_Exception::OBSERVER_* constant + * - An array(const PEAR_Exception::OBSERVER_*, + * mixed $options) + * @param string $label The name of the observer. Use this if you want + * to remove it later with removeObserver() + */ + public static function addObserver($callback, $label = 'default') + { + self::$_observers[$label] = $callback; + } + + public static function removeObserver($label = 'default') + { + unset(self::$_observers[$label]); + } + + /** + * @return int unique identifier for an observer + */ + public static function getUniqueId() + { + return self::$_uniqueid++; + } + + private function signal() + { + foreach (self::$_observers as $func) { + if (is_callable($func)) { + call_user_func($func, $this); + continue; + } + settype($func, 'array'); + switch ($func[0]) { + case self::OBSERVER_PRINT : + $f = (isset($func[1])) ? $func[1] : '%s'; + printf($f, $this->getMessage()); + break; + case self::OBSERVER_TRIGGER : + $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; + trigger_error($this->getMessage(), $f); + break; + case self::OBSERVER_DIE : + $f = (isset($func[1])) ? $func[1] : '%s'; + die(printf($f, $this->getMessage())); + break; + default: + trigger_error('invalid observer type', E_USER_WARNING); + } + } + } + + /** + * Return specific error information that can be used for more detailed + * error messages or translation. + * + * This method may be overridden in child exception classes in order + * to add functionality not present in PEAR_Exception and is a placeholder + * to define API + * + * The returned array must be an associative array of parameter => value like so: + *
+     * array('name' => $name, 'context' => array(...))
+     * 
+ * @return array + */ + public function getErrorData() + { + return array(); + } + + /** + * Returns the exception that caused this exception to be thrown + * @access public + * @return Exception|array The context of the exception + */ + public function getCause() + { + return $this->cause; + } + + /** + * Function must be public to call on caused exceptions + * @param array + */ + public function getCauseMessage(&$causes) + { + $trace = $this->getTraceSafe(); + $cause = array('class' => get_class($this), + 'message' => $this->message, + 'file' => 'unknown', + 'line' => 'unknown'); + if (isset($trace[0])) { + if (isset($trace[0]['file'])) { + $cause['file'] = $trace[0]['file']; + $cause['line'] = $trace[0]['line']; + } + } + $causes[] = $cause; + if ($this->cause instanceof PEAR_Exception) { + $this->cause->getCauseMessage($causes); + } elseif ($this->cause instanceof Exception) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => $this->cause->getFile(), + 'line' => $this->cause->getLine()); + } elseif (class_exists('PEAR_Error',false) && $this->cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($this->cause)) { + foreach ($this->cause as $cause) { + if ($cause instanceof PEAR_Exception) { + $cause->getCauseMessage($causes); + } elseif ($cause instanceof Exception) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => $cause->getFile(), + 'line' => $cause->getLine()); + } elseif (class_exists('PEAR_Error',false) && $cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($cause) && isset($cause['message'])) { + // PEAR_ErrorStack warning + $causes[] = array( + 'class' => $cause['package'], + 'message' => $cause['message'], + 'file' => isset($cause['context']['file']) ? + $cause['context']['file'] : + 'unknown', + 'line' => isset($cause['context']['line']) ? + $cause['context']['line'] : + 'unknown', + ); + } + } + } + } + + public function getTraceSafe() + { + if (!isset($this->_trace)) { + $this->_trace = $this->getTrace(); + if (empty($this->_trace)) { + $backtrace = debug_backtrace(); + $this->_trace = array($backtrace[count($backtrace)-1]); + } + } + return $this->_trace; + } + + public function getErrorClass() + { + $trace = $this->getTraceSafe(); + return $trace[0]['class']; + } + + public function getErrorMethod() + { + $trace = $this->getTraceSafe(); + return $trace[0]['function']; + } + + public function __toString() + { + if (isset($_SERVER['REQUEST_URI'])) { + return $this->toHtml(); + } + return $this->toText(); + } + + public function toHtml() + { + $trace = $this->getTraceSafe(); + $causes = array(); + $this->getCauseMessage($causes); + $html = '' . "\n"; + foreach ($causes as $i => $cause) { + $html .= '\n"; + } + $html .= '' . "\n" + . '' + . '' + . '' . "\n"; + + foreach ($trace as $k => $v) { + $html .= '' + . '' + . '' . "\n"; + } + $html .= '' + . '' + . '' . "\n" + . '
' + . str_repeat('-', $i) . ' ' . $cause['class'] . ': ' + . htmlspecialchars($cause['message']) . ' in ' . $cause['file'] . ' ' + . 'on line ' . $cause['line'] . '' + . "
Exception trace
#FunctionLocation
' . $k . ''; + if (!empty($v['class'])) { + $html .= $v['class'] . $v['type']; + } + $html .= $v['function']; + $args = array(); + if (!empty($v['args'])) { + foreach ($v['args'] as $arg) { + if (is_null($arg)) $args[] = 'null'; + elseif (is_array($arg)) $args[] = 'Array'; + elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')'; + elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false'; + elseif (is_int($arg) || is_double($arg)) $args[] = $arg; + else { + $arg = (string)$arg; + $str = htmlspecialchars(substr($arg, 0, 16)); + if (strlen($arg) > 16) $str .= '…'; + $args[] = "'" . $str . "'"; + } + } + } + $html .= '(' . implode(', ',$args) . ')' + . '' . (isset($v['file']) ? $v['file'] : 'unknown') + . ':' . (isset($v['line']) ? $v['line'] : 'unknown') + . '
' . ($k+1) . '{main} 
'; + return $html; + } + + public function toText() + { + $causes = array(); + $this->getCauseMessage($causes); + $causeMsg = ''; + foreach ($causes as $i => $cause) { + $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' + . $cause['message'] . ' in ' . $cause['file'] + . ' on line ' . $cause['line'] . "\n"; + } + return $causeMsg . $this->getTraceAsString(); + } +} + +?> diff --git a/libs/lexer/Lempar.php b/libs/lexer/Lempar.php new file mode 100644 index 00000000..1ba5a9aa --- /dev/null +++ b/libs/lexer/Lempar.php @@ -0,0 +1,930 @@ +string = $s->string; + $this->metadata = $s->metadata; + } else { + $this->string = (string) $s; + if ($m instanceof ParseyyToken) { + $this->metadata = $m->metadata; + } elseif (is_array($m)) { + $this->metadata = $m; + } + } + } + + function __toString() + { + return $this->_string; + } + + function offsetExists($offset) + { + return isset($this->metadata[$offset]); + } + + function offsetGet($offset) + { + return $this->metadata[$offset]; + } + + function offsetSet($offset, $value) + { + if ($offset === null) { + if (isset($value[0])) { + $x = ($value instanceof ParseyyToken) ? + $value->metadata : $value; + $this->metadata = array_merge($this->metadata, $x); + return; + } + $offset = count($this->metadata); + } + if ($value === null) { + return; + } + if ($value instanceof ParseyyToken) { + if ($value->metadata) { + $this->metadata[$offset] = $value->metadata; + } + } elseif ($value) { + $this->metadata[$offset] = $value; + } + } + + function offsetUnset($offset) + { + unset($this->metadata[$offset]); + } +} + +/** The following structure represents a single element of the + * parser's stack. Information stored includes: + * + * + The state number for the parser at this level of the stack. + * + * + The value of the token stored at this level of the stack. + * (In other words, the "major" token.) + * + * + The semantic value stored at this level of the stack. This is + * the information used by the action routines in the grammar. + * It is sometimes called the "minor" token. + */ +class ParseyyStackEntry +{ + public $stateno; /* The state-number */ + public $major; /* The major token value. This is the code + ** number for the token at this stack level */ + public $minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; + +// code external to the class is included here +%% + +// declare_class is output here +%% +{ +/* First off, code is included which follows the "include_class" declaration +** in the input file. */ +%% + +/* Next is all token values, as class constants +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ +%% + +/* Next are that tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N < self::YYNSTATE Shift N. That is, +** push the lookahead +** token onto the stack +** and goto state N. +** +** self::YYNSTATE <= N < self::YYNSTATE+self::YYNRULE Reduce by rule N-YYNSTATE. +** +** N == self::YYNSTATE+self::YYNRULE A syntax error has occurred. +** +** N == self::YYNSTATE+self::YYNRULE+1 The parser accepts its +** input. (and concludes parsing) +** +** N == self::YYNSTATE+self::YYNRULE+2 No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large static array $yy_action. +** Given state S and lookahead X, the action is computed as +** +** self::$yy_action[self::$yy_shift_ofst[S] + X ] +** +** If the index value self::$yy_shift_ofst[S]+X is out of range or if the value +** self::$yy_lookahead[self::$yy_shift_ofst[S]+X] is not equal to X or if +** self::$yy_shift_ofst[S] is equal to self::YY_SHIFT_USE_DFLT, it means that +** the action is not in the table and that self::$yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the static $yy_reduce_ofst array is used in place of +** the static $yy_shift_ofst array and self::YY_REDUCE_USE_DFLT is used in place of +** self::YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** self::$yy_action A single table containing all actions. +** self::$yy_lookahead A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** self::$yy_shift_ofst For each state, the offset into self::$yy_action for +** shifting terminals. +** self::$yy_reduce_ofst For each state, the offset into self::$yy_action for +** shifting non-terminals after a reduce. +** self::$yy_default Default action for each state. +*/ +%% +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** self::YYNOCODE is a number which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** self::YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** self::YYSTACKDEPTH is the maximum depth of the parser's stack. +** self::YYNSTATE the combined number of states. +** self::YYNRULE the number of rules in the grammar +** self::YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ +%% + /** The next table maps tokens into fallback tokens. If a construct + * like the following: + * + * %fallback ID X Y Z. + * + * appears in the grammer, then ID becomes a fallback token for X, Y, + * and Z. Whenever one of the tokens X, Y, or Z is input to the parser + * but it does not parse, the type of the token is changed to ID and + * the parse is retried before an error is thrown. + */ + static public $yyFallback = array( +%% + ); + /** + * Turn parser tracing on by giving a stream to which to write the trace + * and a prompt to preface each trace message. Tracing is turned off + * by making either argument NULL + * + * Inputs: + * + * - A stream resource to which trace output should be written. + * If NULL, then tracing is turned off. + * - A prefix string written at the beginning of every + * line of trace output. If NULL, then tracing is + * turned off. + * + * Outputs: + * + * - None. + * @param resource + * @param string + */ + static function Trace($TraceFILE, $zTracePrompt) + { + if (!$TraceFILE) { + $zTracePrompt = 0; + } elseif (!$zTracePrompt) { + $TraceFILE = 0; + } + self::$yyTraceFILE = $TraceFILE; + self::$yyTracePrompt = $zTracePrompt; + } + + /** + * Output debug information to output (php://output stream) + */ + static function PrintTrace() + { + self::$yyTraceFILE = fopen('php://output', 'w'); + self::$yyTracePrompt = '
'; + } + + /** + * @var resource|0 + */ + static public $yyTraceFILE; + /** + * String to prepend to debug output + * @var string|0 + */ + static public $yyTracePrompt; + /** + * @var int + */ + public $yyidx; /* Index of top element in stack */ + /** + * @var int + */ + public $yyerrcnt; /* Shifts left before out of the error */ + /** + * @var array + */ + public $yystack = array(); /* The parser's stack */ + + /** + * For tracing shifts, the names of all terminals and nonterminals + * are required. The following table supplies these names + * @var array + */ + public $yyTokenName = array( +%% + ); + + /** + * For tracing reduce actions, the names of all rules are required. + * @var array + */ + static public $yyRuleName = array( +%% + ); + + /** + * This function returns the symbolic name associated with a token + * value. + * @param int + * @return string + */ + function tokenName($tokenType) + { + if ($tokenType === 0) { + return 'End of Input'; + } + if ($tokenType > 0 && $tokenType < count($this->yyTokenName)) { + return $this->yyTokenName[$tokenType]; + } else { + return "Unknown"; + } + } + + /** + * The following function deletes the value associated with a + * symbol. The symbol can be either a terminal or nonterminal. + * @param int the symbol code + * @param mixed the symbol's value + */ + static function yy_destructor($yymajor, $yypminor) + { + switch ($yymajor) { + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ +%% + default: break; /* If no destructor action specified: do nothing */ + } + } + + /** + * Pop the parser's stack once. + * + * If there is a destructor routine associated with the token which + * is popped from the stack, then call it. + * + * Return the major token number for the symbol popped. + * @param ParseyyParser + * @return int + */ + function yy_pop_parser_stack() + { + if (!count($this->yystack)) { + return; + } + $yytos = array_pop($this->yystack); + if (self::$yyTraceFILE && $this->yyidx >= 0) { + fwrite(self::$yyTraceFILE, + self::$yyTracePrompt . 'Popping ' . $this->yyTokenName[$yytos->major] . + "\n"); + } + $yymajor = $yytos->major; + self::yy_destructor($yymajor, $yytos->minor); + $this->yyidx--; + return $yymajor; + } + + /** + * Deallocate and destroy a parser. Destructors are all called for + * all stack elements before shutting the parser down. + */ + function __destruct() + { + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + if (is_resource(self::$yyTraceFILE)) { + fclose(self::$yyTraceFILE); + } + } + + /** + * Based on the current state and parser stack, get a list of all + * possible lookahead tokens + * @param int + * @return array + */ + function yy_get_expected_tokens($token) + { + $state = $this->yystack[$this->yyidx]->stateno; + $expected = self::$yyExpectedTokens[$state]; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return $expected; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return array_unique($expected); + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate])) { + $expected += self::$yyExpectedTokens[$nextstate]; + if (in_array($token, + self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return array_unique($expected); + } + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new ParseyyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return array_unique($expected); + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return $expected; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + return array_unique($expected); + } + + /** + * Based on the parser state and current parser stack, determine whether + * the lookahead token is possible. + * + * The parser will convert the token value to an error token if not. This + * catches some unusual edge cases where the parser would fail. + * @param int + * @return bool + */ + function yy_is_expected_token($token) + { + if ($token === 0) { + return true; // 0 is not part of this + } + $state = $this->yystack[$this->yyidx]->stateno; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return true; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return true; + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate]) && + in_array($token, self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new ParseyyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + if (!$token) { + // end of input: this is valid + return true; + } + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return false; + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return true; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + + /** + * Find the appropriate action for a parser given the terminal + * look-ahead token iLookAhead. + * + * If the look-ahead token is YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return YY_NO_ACTION. + * @param int The look-ahead token + */ + function yy_find_shift_action($iLookAhead) + { + $stateno = $this->yystack[$this->yyidx]->stateno; + + /* if ($this->yyidx < 0) return self::YY_NO_ACTION; */ + if (!isset(self::$yy_shift_ofst[$stateno])) { + // no shift actions + return self::$yy_default[$stateno]; + } + $i = self::$yy_shift_ofst[$stateno]; + if ($i === self::YY_SHIFT_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback) + && ($iFallback = self::$yyFallback[$iLookAhead]) != 0) { + if (self::$yyTraceFILE) { + fwrite(self::$yyTraceFILE, self::$yyTracePrompt . "FALLBACK " . + $this->yyTokenName[$iLookAhead] . " => " . + $this->yyTokenName[$iFallback] . "\n"); + } + return $this->yy_find_shift_action($iFallback); + } + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Find the appropriate action for a parser given the non-terminal + * look-ahead token $iLookAhead. + * + * If the look-ahead token is self::YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return self::YY_NO_ACTION. + * @param int Current state number + * @param int The look-ahead token + */ + function yy_find_reduce_action($stateno, $iLookAhead) + { + /* $stateno = $this->yystack[$this->yyidx]->stateno; */ + + if (!isset(self::$yy_reduce_ofst[$stateno])) { + return self::$yy_default[$stateno]; + } + $i = self::$yy_reduce_ofst[$stateno]; + if ($i == self::YY_REDUCE_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Perform a shift action. + * @param int The new state to shift in + * @param int The major token to shift in + * @param mixed the minor token to shift in + */ + function yy_shift($yyNewState, $yyMajor, $yypMinor) + { + $this->yyidx++; + if ($this->yyidx >= self::YYSTACKDEPTH) { + $this->yyidx--; + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sStack Overflow!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will execute if the parser + ** stack ever overflows */ +%% + return; + } + $yytos = new ParseyyStackEntry; + $yytos->stateno = $yyNewState; + $yytos->major = $yyMajor; + $yytos->minor = $yypMinor; + array_push($this->yystack, $yytos); + if (self::$yyTraceFILE && $this->yyidx > 0) { + fprintf(self::$yyTraceFILE, "%sShift %d\n", self::$yyTracePrompt, + $yyNewState); + fprintf(self::$yyTraceFILE, "%sStack:", self::$yyTracePrompt); + for($i = 1; $i <= $this->yyidx; $i++) { + fprintf(self::$yyTraceFILE, " %s", + $this->yyTokenName[$this->yystack[$i]->major]); + } + fwrite(self::$yyTraceFILE,"\n"); + } + } + + /** + * The following table contains information about every rule that + * is used during the reduce. + * + *
+     * array(
+     *  array(
+     *   int $lhs;         Symbol on the left-hand side of the rule
+     *   int $nrhs;     Number of right-hand side symbols in the rule
+     *  ),...
+     * );
+     * 
+ */ + static public $yyRuleInfo = array( +%% + ); + + /** + * The following table contains a mapping of reduce action to method name + * that handles the reduction. + * + * If a rule is not set, it has no handler. + */ + static public $yyReduceMap = array( +%% + ); + /* Beginning here are the reduction cases. A typical example + ** follows: + ** #line + ** function yy_r0($yymsp){ ... } // User supplied code + ** #line + */ +%% + + /** + * placeholder for the left hand side in a reduce operation. + * + * For a parser with a rule like this: + *
+     * rule(A) ::= B. { A = 1; }
+     * 
+ * + * The parser will translate to something like: + * + * + * function yy_r0(){$this->_retvalue = 1;} + * + */ + private $_retvalue; + + /** + * Perform a reduce action and the shift that must immediately + * follow the reduce. + * + * For a rule such as: + * + *
+     * A ::= B blah C. { dosomething(); }
+     * 
+ * + * This function will first call the action, if any, ("dosomething();" in our + * example), and then it will pop three states from the stack, + * one for each entry on the right-hand side of the expression + * (B, blah, and C in our example rule), and then push the result of the action + * back on to the stack with the resulting state reduced to (as described in the .out + * file) + * @param int Number of the rule by which to reduce + */ + function yy_reduce($yyruleno) + { + //int $yygoto; /* The next state */ + //int $yyact; /* The next action */ + //mixed $yygotominor; /* The LHS of the rule reduced */ + //ParseyyStackEntry $yymsp; /* The top of the parser's stack */ + //int $yysize; /* Amount to pop the stack */ + $yymsp = $this->yystack[$this->yyidx]; + if (self::$yyTraceFILE && $yyruleno >= 0 + && $yyruleno < count(self::$yyRuleName)) { + fprintf(self::$yyTraceFILE, "%sReduce (%d) [%s].\n", + self::$yyTracePrompt, $yyruleno, + self::$yyRuleName[$yyruleno]); + } + + $this->_retvalue = $yy_lefthand_side = null; + if (array_key_exists($yyruleno, self::$yyReduceMap)) { + // call the action + $this->_retvalue = null; + $this->{'yy_r' . self::$yyReduceMap[$yyruleno]}(); + $yy_lefthand_side = $this->_retvalue; + } + $yygoto = self::$yyRuleInfo[$yyruleno]['lhs']; + $yysize = self::$yyRuleInfo[$yyruleno]['rhs']; + $this->yyidx -= $yysize; + for($i = $yysize; $i; $i--) { + // pop all of the right-hand side parameters + array_pop($this->yystack); + } + $yyact = $this->yy_find_reduce_action($this->yystack[$this->yyidx]->stateno, $yygoto); + if ($yyact < self::YYNSTATE) { + /* If we are not debugging and the reduce action popped at least + ** one element off the stack, then we can push the new element back + ** onto the stack here, and skip the stack overflow test in yy_shift(). + ** That gives a significant speed improvement. */ + if (!self::$yyTraceFILE && $yysize) { + $this->yyidx++; + $x = new ParseyyStackEntry; + $x->stateno = $yyact; + $x->major = $yygoto; + $x->minor = $yy_lefthand_side; + $this->yystack[$this->yyidx] = $x; + } else { + $this->yy_shift($yyact, $yygoto, $yy_lefthand_side); + } + } elseif ($yyact == self::YYNSTATE + self::YYNRULE + 1) { + $this->yy_accept(); + } + } + + /** + * The following code executes when the parse fails + * + * Code from %parse_fail is inserted here + */ + function yy_parse_failed() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sFail!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser fails */ +%% + } + + /** + * The following code executes when a syntax error first occurs. + * + * %syntax_error code is inserted here + * @param int The major type of the error token + * @param mixed The minor type of the error token + */ + function yy_syntax_error($yymajor, $TOKEN) + { +%% + } + + /** + * The following is executed when the parser accepts + * + * %parse_accept code is inserted here + */ + function yy_accept() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sAccept!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $stack = $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser accepts */ +%% + } + + /** + * The main parser program. + * + * The first argument is the major token number. The second is + * the token value string as scanned from the input. + * + * @param int the token number + * @param mixed the token value + * @param mixed any extra arguments that should be passed to handlers + */ + function doParse($yymajor, $yytokenvalue) + { +// $yyact; /* The parser action. */ +// $yyendofinput; /* True if we are at the end of input */ + $yyerrorhit = 0; /* True if yymajor has invoked an error */ + + /* (re)initialize the parser, if necessary */ + if ($this->yyidx === null || $this->yyidx < 0) { + /* if ($yymajor == 0) return; // not sure why this was here... */ + $this->yyidx = 0; + $this->yyerrcnt = -1; + $x = new ParseyyStackEntry; + $x->stateno = 0; + $x->major = 0; + $this->yystack = array(); + array_push($this->yystack, $x); + } + $yyendofinput = ($yymajor==0); + + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sInput %s\n", + self::$yyTracePrompt, $this->yyTokenName[$yymajor]); + } + + do { + $yyact = $this->yy_find_shift_action($yymajor); + if ($yymajor < self::YYERRORSYMBOL && + !$this->yy_is_expected_token($yymajor)) { + // force a syntax error + $yyact = self::YY_ERROR_ACTION; + } + if ($yyact < self::YYNSTATE) { + $this->yy_shift($yyact, $yymajor, $yytokenvalue); + $this->yyerrcnt--; + if ($yyendofinput && $this->yyidx >= 0) { + $yymajor = 0; + } else { + $yymajor = self::YYNOCODE; + } + } elseif ($yyact < self::YYNSTATE + self::YYNRULE) { + $this->yy_reduce($yyact - self::YYNSTATE); + } elseif ($yyact == self::YY_ERROR_ACTION) { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sSyntax Error!\n", + self::$yyTracePrompt); + } + if (self::YYERRORSYMBOL) { + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if ($this->yyerrcnt < 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $yymx = $this->yystack[$this->yyidx]->major; + if ($yymx == self::YYERRORSYMBOL || $yyerrorhit ){ + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sDiscard input token %s\n", + self::$yyTracePrompt, $this->yyTokenName[$yymajor]); + } + $this->yy_destructor($yymajor, $yytokenvalue); + $yymajor = self::YYNOCODE; + } else { + while ($this->yyidx >= 0 && + $yymx != self::YYERRORSYMBOL && + ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE + ){ + $this->yy_pop_parser_stack(); + } + if ($this->yyidx < 0 || $yymajor==0) { + $this->yy_destructor($yymajor, $yytokenvalue); + $this->yy_parse_failed(); + $yymajor = self::YYNOCODE; + } elseif ($yymx != self::YYERRORSYMBOL) { + $u2 = 0; + $this->yy_shift($yyact, self::YYERRORSYMBOL, $u2); + } + } + $this->yyerrcnt = 3; + $yyerrorhit = 1; + } else { + /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if ($this->yyerrcnt <= 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $this->yyerrcnt = 3; + $this->yy_destructor($yymajor, $yytokenvalue); + if ($yyendofinput) { + $this->yy_parse_failed(); + } + $yymajor = self::YYNOCODE; + } + } else { + $this->yy_accept(); + $yymajor = self::YYNOCODE; + } + } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0); + } +} diff --git a/libs/lexer/LexerGenerator.php b/libs/lexer/LexerGenerator.php new file mode 100644 index 00000000..8af64884 --- /dev/null +++ b/libs/lexer/LexerGenerator.php @@ -0,0 +1,289 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_LexerGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_LexerGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: LexerGenerator.php,v 1.1 2006/07/18 00:47:06 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** + * The Lexer generation parser + */ +require_once './LexerGenerator/Parser.php'; +/** + * Hand-written lexer for lex2php format files + */ +require_once './LexerGenerator/Lexer.php'; +/** + * The basic home class for the lexer generator. A lexer scans text and + * organizes it into tokens for usage by a parser. + * + * Sample Usage: + * + * require_once 'PHP/LexerGenerator.php'; + * $lex = new PHP_LexerGenerator('/path/to/lexerfile.plex'); + * + * + * A file named "/path/to/lexerfile.php" will be created. + * + * File format consists of a PHP file containing specially + * formatted comments like so: + * + * + * /*!lex2php + * {@*} + * + * + * All lexer definition files must contain at least two lex2php comment blocks: + * - 1 regex declaration block + * - 1 or more rule declaration blocks + * + * The first lex2php comment is the regex declaration block and must contain + * several processor instruction as well as defining a name for all + * regular expressions. Processor instructions start with + * a "%" symbol and must be: + * + * - %counter + * - %input + * - %token + * - %value + * - %line + * + * token and counter should define the class variables used to define lexer input + * and the index into the input. token and value should be used to define the class + * variables used to store the token number and its textual value. Finally, line + * should be used to define the class variable used to define the current line number + * of scanning. + * + * For example: + * + * /*!lex2php + * %counter {$this->N} + * %input {$this->data} + * %token {$this->token} + * %value {$this->value} + * %line {%this->linenumber} + * {@*} + * + * + * Patterns consist of an identifier containing an letters or an underscore, and + * a descriptive match pattern. + * + * Descriptive match patterns may either be regular expressions (regexes) or + * quoted literal strings. Here are some examples: + * + *
+ * pattern = "quoted literal"
+ * ANOTHER = /[a-zA-Z_]+/
+ * COMPLEX = @<([a-zA-Z_]+)( +(([a-zA-Z_]+)=((["\'])([^\6]*)\6))+){0,1}>[^<]*@
+ * 
+ * + * Quoted strings must escape the \ and " characters with \" and \\. + * + * Regex patterns must be in Perl-compatible regular expression format (preg). + * special characters (like \t \n or \x3H) can only be used in regexes, all + * \ will be escaped in literal strings. + * + * Sub-patterns may be defined and back-references (like \1) may be used. Any sub- + * patterns detected will be passed to the token handler in the variable + * $yysubmatches. + * + * In addition, lookahead expressions, and once-only expressions are allowed. + * Lookbehind expressions are impossible (scanning always occurs from the + * current position forward), and recursion (?R) can't work and is not allowed. + * + * + * /*!lex2php + * %counter {$this->N} + * %input {$this->data} + * %token {$this->token} + * %value {$this->value} + * %line {%this->linenumber} + * alpha = /[a-zA-Z]/ + * alphaplus = /[a-zA-Z]+/ + * number = /[0-9]/ + * numerals = /[0-9]+/ + * whitespace = /[ \t\n]+/ + * blah = "$\"" + * blahblah = /a\$/ + * GAMEEND = @(?:1\-0|0\-1|1/2\-1/2)@ + * PAWNMOVE = /P?[a-h]([2-7]|[18]\=(Q|R|B|N))|P?[a-h]x[a-h]([2-7]|[18]\=(Q|R|B|N))/ + * {@*} + * + * + * All regexes must be delimited. Any legal preg delimiter can be used (as in @ or / in + * the example above) + * + * Rule lex2php blocks each define a lexer state. You can optionally name the state + * with the %statename processor instruction. State names can be used to transfer to + * a new lexer state with the yybegin() method + * + * + * /*!lexphp + * %statename INITIAL + * blah { + * $this->yybegin(self::INBLAH); + * // note - $this->yybegin(2) would also work + * } + * {@*} + * /*!lex2php + * %statename INBLAH + * ANYTHING { + * $this->yybegin(self::INITIAL); + * // note - $this->yybegin(1) would also work + * } + * {@*} + * + * + * You can maintain a parser state stack simply by using yypushstate() and + * yypopstate() instead of yybegin(): + * + * + * /*!lexphp + * %statename INITIAL + * blah { + * $this->yypushstate(self::INBLAH); + * } + * {@*} + * /*!lex2php + * %statename INBLAH + * ANYTHING { + * $this->yypopstate(); + * // now INBLAH doesn't care where it was called from + * } + * {@*} + * + * + * Code blocks can choose to skip the current token and cycle to the next token by + * returning "false" + * + * + * /*!lex2php + * WHITESPACE { + * return false; + * } + * {@*} + * + * + * If you wish to re-process the current token in a new state, simply return true. + * If you forget to change lexer state, this will cause an unterminated loop, + * so be careful! + * + * + * /*!lex2php + * "(" { + * $this->yypushstate(self::INPARAMS); + * return true; + * } + * {@*} + * + * + * Lastly, if you wish to cycle to the next matching rule, return any value other than + * true, false or null: + * + * + * /*!lex2php + * "{@" ALPHA { + * if ($this->value == '{@internal') { + * return 'more'; + * } + * ... + * } + * "{@internal" { + * ... + * } + * {@*} + * + * + * Note that this procedure is exceptionally inefficient, and it would be far better + * to take advantage of PHP_LexerGenerator's top-down precedence and instead code: + * + * + * /*!lex2php + * "{@internal" { + * ... + * } + * "{@" ALPHA { + * ... + * } + * {@*} + * + * @package PHP_LexerGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version 0.3.4 + * @since Class available since Release 0.1.0 + * @example TestLexer.plex Example lexer source + * @example TestLexer.php Example lexer generated php code + * @example usage.php Example usage of PHP_LexerGenerator + * @example Lexer.plex File_ChessPGN lexer source (complex) + * @example Lexer.php File_ChessPGN lexer generated php code + */ + +class PHP_LexerGenerator +{ + private $lex; + private $parser; + private $outfile; + /** + * Create a lexer file from its skeleton plex file. + * + * @param string $lexerfile path to the plex file + */ + function __construct($lexerfile) + { + $this->lex = new PHP_LexerGenerator_Lexer(file_get_contents($lexerfile)); + $info = pathinfo($lexerfile); + $this->outfile = $info['dirname'] . DIRECTORY_SEPARATOR . + substr($info['basename'], 0, + strlen($info['basename']) - strlen($info['extension'])) . 'php'; + $this->parser = new PHP_LexerGenerator_Parser($this->outfile, $this->lex); +// $this->parser->PrintTrace(); + while ($this->lex->advance($this->parser)) { + $this->parser->doParse($this->lex->token, $this->lex->value); + } + $this->parser->doParse(0, 0); + } +} +//$a = new PHP_LexerGenerator('/development/File_ChessPGN/ChessPGN/Lexer.plex'); +?> diff --git a/libs/lexer/LexerGenerator/Exception.php b/libs/lexer/LexerGenerator/Exception.php new file mode 100644 index 00000000..544d3dfc --- /dev/null +++ b/libs/lexer/LexerGenerator/Exception.php @@ -0,0 +1,55 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_LexerGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_LexerGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + */ +require_once './Exception.php'; +/** + * @package PHP_LexerGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version @package_version@ + * @since File available since Release 0.1.0 + */ +class PHP_LexerGenerator_Exception extends PEAR_Exception {} +?> diff --git a/libs/lexer/LexerGenerator/Lexer.php b/libs/lexer/LexerGenerator/Lexer.php new file mode 100644 index 00000000..098b2a35 --- /dev/null +++ b/libs/lexer/LexerGenerator/Lexer.php @@ -0,0 +1,470 @@ + + * @copyright 2006 Gregory Beaver + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version CVS: $Id: Lexer.php,v 1.1 2006/07/18 00:47:06 cellog Exp $ + * @since File available since Release 0.1.0 + */ +require_once './LexerGenerator/Parser.php'; +/** + * Token scanner for plex files. + * + * This scanner detects comments beginning with "/*!lex2php" and + * then returns their components (processing instructions, patterns, strings + * action code, and regexes) + * @package PHP_LexerGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version 0.3.4 + * @since Class available since Release 0.1.0 + */ +class PHP_LexerGenerator_Lexer +{ + private $data; + private $N; + private $state; + /** + * Current line number in input + * @var int + */ + public $line; + /** + * Number of scanning errors detected + * @var int + */ + public $errors = 0; + /** + * integer identifier of the current token + * @var int + */ + public $token; + /** + * string content of current token + * @var string + */ + public $value; + + const PHPCODE = PHP_LexerGenerator_Parser::PHPCODE; + const COMMENTSTART = PHP_LexerGenerator_Parser::COMMENTSTART; + const COMMENTEND = PHP_LexerGenerator_Parser::COMMENTEND; + const QUOTE = PHP_LexerGenerator_Parser::QUOTE; + const PATTERN = PHP_LexerGenerator_Parser::PATTERN; + const CODE = PHP_LexerGenerator_Parser::CODE; + const SUBPATTERN = PHP_LexerGenerator_Parser::SUBPATTERN; + const PI = PHP_LexerGenerator_Parser::PI; + + /** + * prepare scanning + * @param string the input + */ + function __construct($data) + { + $this->data = str_replace("\r\n", "\n", $data); + $this->N = 0; + $this->line = 1; + $this->state = 'Start'; + $this->errors = 0; + } + + /** + * Output an error message + * @param string + */ + private function error($msg) + { + echo 'Error on line ' . $this->line . ': ' . $msg; + $this->errors++; + } + + /** + * Initial scanning state lexer + * @return boolean + */ + private function lexStart() + { + if ($this->N >= strlen($this->data)) { + return false; + } + $a = strpos($this->data, '/*!lex2php' . "\n", $this->N); + if ($a === false) { + $this->value = substr($this->data, $this->N); + $this->N = strlen($this->data); + $this->token = self::PHPCODE; + return true; + } + if ($a > $this->N) { + $this->value = substr($this->data, $this->N, $a - $this->N); + $this->N = $a; + $this->token = self::PHPCODE; + return true; + } + $this->value = '/*!lex2php' . "\n"; + $this->N += 11; // strlen("/*lex2php\n") + $this->token = self::COMMENTSTART; + $this->state = 'Declare'; + return true; + } + + /** + * lexer for top-level canning state after the initial declaration comment + * @return boolean + */ + private function lexStartNonDeclare() + { + if ($this->N >= strlen($this->data)) { + return false; + } + $a = strpos($this->data, '/*!lex2php' . "\n", $this->N); + if ($a === false) { + $this->value = substr($this->data, $this->N); + $this->N = strlen($this->data); + $this->token = self::PHPCODE; + return true; + } + if ($a > $this->N) { + $this->value = substr($this->data, $this->N, $a - $this->N); + $this->N = $a; + $this->token = self::PHPCODE; + return true; + } + $this->value = '/*!lex2php' . "\n"; + $this->N += 11; // strlen("/*lex2php\n") + $this->token = self::COMMENTSTART; + $this->state = 'Rule'; + return true; + } + + /** + * lexer for declaration comment state + * @return boolean + */ + private function lexDeclare() + { + if ($this->data[$this->N] == '*' && $this->data[$this->N + 1] == '/') { + $this->state = 'StartNonDeclare'; + $this->value = '*/'; + $this->N += 2; + $this->token = self::COMMENTEND; + return true; + } + if (preg_match('/^%([a-z]+)/', substr($this->data, $this->N), $token)) { + $this->value = $token[1]; + $this->N += strlen($token[1]) + 1; + $this->state = 'DeclarePI'; + $this->token = self::PI; + return true; + } + if (preg_match('/^[a-zA-Z_]+/', substr($this->data, $this->N), $token)) { + $this->value = $token[0]; + $this->token = self::PATTERN; + $this->N += strlen($token[0]); + $this->state = 'DeclareEquals'; + return true; + } else { + $this->error('expecting declaration of sub-patterns'); + return false; + } + } + + /** + * lexer for processor instructions within declaration comment + * @return boolean + */ + private function lexDeclarePI() + { + while ($this->N < strlen($this->data) && + ($this->data[$this->N] == ' ' || + $this->data[$this->N] == "\t")) { + $this->N++; // skip whitespace + } + if ($this->data[$this->N] == "\n") { + $this->N++; + $this->state = 'Declare'; + $this->line++; + return $this->lexDeclare(); + } + if ($this->data[$this->N] == '{') { + return $this->lexCode(); + } + if (!preg_match("/[^\n]+/", substr($this->data, $this->N), $token)) { + $this->error('Unexpected end of file'); + return false; + } + $this->value = $token[0]; + $this->N += strlen($this->value); + $this->token = self::SUBPATTERN; + return true; + } + + /** + * lexer for processor instructions inside rule comments + * @return boolean + */ + private function lexDeclarePIRule() + { + while ($this->N < strlen($this->data) && + ($this->data[$this->N] == ' ' || + $this->data[$this->N] == "\t")) { + $this->N++; // skip whitespace + } + if ($this->data[$this->N] == "\n") { + $this->N++; + $this->state = 'Rule'; + $this->line++; + return $this->lexRule(); + } + if ($this->data[$this->N] == '{') { + return $this->lexCode(); + } + if (!preg_match("/[^\n]+/", substr($this->data, $this->N), $token)) { + $this->error('Unexpected end of file'); + return false; + } + $this->value = $token[0]; + $this->N += strlen($this->value); + $this->token = self::SUBPATTERN; + return true; + } + + /** + * lexer for the state representing scanning between a pattern and the "=" sign + * @return boolean + */ + private function lexDeclareEquals() + { + while ($this->N < strlen($this->data) && + ($this->data[$this->N] == ' ' || $this->data[$this->N] == "\t")) { + $this->N++; // skip whitespace + } + if ($this->N >= strlen($this->data)) { + $this->error('unexpected end of input, expecting "=" for sub-pattern declaration'); + } + if ($this->data[$this->N] != '=') { + $this->error('expecting "=" for sub-pattern declaration'); + return false; + } + $this->N++; + $this->state = 'DeclareRightside'; + while ($this->N < strlen($this->data) && + ($this->data[$this->N] == ' ' || $this->data[$this->N] == "\t")) { + $this->N++; // skip whitespace + } + if ($this->N >= strlen($this->data)) { + $this->error('unexpected end of file, expecting right side of sub-pattern declaration'); + return false; + } + return $this->lexDeclareRightside(); + } + + /** + * lexer for the right side of a pattern, detects quotes or regexes + * @return boolean + */ + private function lexDeclareRightside() + { + if ($this->data[$this->N] == "\n") { + $this->state = 'lexDeclare'; + $this->N++; + $this->line++; + return $this->lexDeclare(); + } + if ($this->data[$this->N] == '"') { + return $this->lexQuote(); + } + while ($this->N < strlen($this->data) && + ($this->data[$this->N] == ' ' || + $this->data[$this->N] == "\t")) { + $this->N++; // skip all whitespace + } + // match a pattern + $test = $this->data[$this->N]; + $token = $this->N + 1; + $a = 0; + do { + if ($a++) { + $token++; + } + $token = strpos($this->data, $test, $token); + } while ($token !== false && ($this->data[$token - 1] == '\\' + && $this->data[$token - 2] != '\\')); + if ($token === false) { + $this->error('Unterminated regex pattern (started with "' . $test . '"'); + return false; + } + if (substr_count($this->data, "\n", $this->N, $token - $this->N)) { + $this->error('Regex pattern extends over multiple lines'); + return false; + } + $this->value = substr($this->data, $this->N + 1, $token - $this->N - 1); + // unescape the regex marker + // we will re-escape when creating the final regex + $this->value = str_replace('\\' . $test, $test, $this->value); + $this->N = $token + 1; + $this->token = self::SUBPATTERN; + return true; + } + + /** + * lexer for quoted literals + * @return boolean + */ + private function lexQuote() + { + $token = $this->N + 1; + $a = 0; + do { + if ($a++) { + $token++; + } + $token = strpos($this->data, '"', $token); + } while ($token !== false && $token < strlen($this->data) && + ($this->data[$token - 1] == '\\' && $this->data[$token - 2] != '\\')); + if ($token === false) { + $this->error('unterminated quote'); + return false; + } + if (substr_count($this->data, "\n", $this->N, $token - $this->N)) { + $this->error('quote extends over multiple lines'); + return false; + } + $this->value = substr($this->data, $this->N + 1, $token - $this->N - 1); + $this->value = str_replace('\\"', '"', $this->value); + $this->value = str_replace('\\\\', '\\', $this->value); + $this->N = $token + 1; + $this->token = self::QUOTE; + return true; + } + + /** + * lexer for rules + * @return boolean + */ + private function lexRule() + { + while ($this->N < strlen($this->data) && + ($this->data[$this->N] == ' ' || + $this->data[$this->N] == "\t" || + $this->data[$this->N] == "\n")) { + if ($this->data[$this->N] == "\n") { + $this->line++; + } + $this->N++; // skip all whitespace + } + if ($this->N >= strlen($this->data)) { + $this->error('unexpected end of input, expecting rule declaration'); + } + if ($this->data[$this->N] == '*' && $this->data[$this->N + 1] == '/') { + $this->state = 'StartNonDeclare'; + $this->value = '*/'; + $this->N += 2; + $this->token = self::COMMENTEND; + return true; + } + if (preg_match('/^%([a-z]+)/', substr($this->data, $this->N), $token)) { + $this->value = $token[1]; + $this->N += strlen($token[1]) + 1; + $this->state = 'DeclarePIRule'; + $this->token = self::PI; + return true; + } + if ($this->data[$this->N] == "{") { + return $this->lexCode(); + } + if ($this->data[$this->N] == '"') { + return $this->lexQuote(); + } + if (preg_match('/^[a-zA-Z_]+/', substr($this->data, $this->N), $token)) { + $this->value = $token[0]; + $this->N += strlen($token[0]); + $this->token = self::SUBPATTERN; + return true; + } else { + $this->error('expecting token rule (quotes or sub-patterns)'); + return false; + } + } + + /** + * lexer for php code blocks + * @return boolean + */ + private function lexCode() + { + $cp = $this->N + 1; + for ($level = 1; $cp < strlen($this->data) && ($level > 1 || $this->data[$cp] != '}'); $cp++) { + if ($this->data[$cp] == '{') { + $level++; + } elseif ($this->data[$cp] == '}') { + $level--; + } elseif ($this->data[$cp] == '/' && $this->data[$cp + 1] == '/') { + /* Skip C++ style comments */ + $cp += 2; + $z = strpos($this->data, "\n", $cp); + if ($z === false) { + $cp = strlen($this->data); + break; + } + $cp = $z; + } elseif ($this->data[$cp] == "'" || $this->data[$cp] == '"') { + /* String a character literals */ + $startchar = $this->data[$cp]; + $prevc = 0; + for ($cp++; $cp < strlen($this->data) && ($this->data[$cp] != $startchar || $prevc === '\\'); $cp++) { + if ($prevc === '\\') { + $prevc = 0; + } else { + $prevc = $this->data[$cp]; + } + } + } + } + if ($cp >= strlen($this->data)) { + $this->error("PHP code starting on this line is not terminated before the end of the file."); + $this->error++; + return false; + } else { + $this->value = substr($this->data, $this->N + 1, $cp - $this->N - 1); + $this->token = self::CODE; + $this->N = $cp + 1; + return true; + } + } + + /** + * Primary scanner + * + * In addition to lexing, this properly increments the line number of lexing. + * This calls the proper sub-lexer based on the parser state + * @param unknown_type $parser + * @return unknown + */ + public function advance($parser) + { + if ($this->N >= strlen($this->data)) { + return false; + } + if ($this->{'lex' . $this->state}()) { + $this->line += substr_count($this->value, "\n"); + return true; + } + return false; + } +} +?> diff --git a/libs/lexer/LexerGenerator/Parser.php b/libs/lexer/LexerGenerator/Parser.php new file mode 100644 index 00000000..a4a0a8c7 --- /dev/null +++ b/libs/lexer/LexerGenerator/Parser.php @@ -0,0 +1,1937 @@ +string = $s->string; + $this->metadata = $s->metadata; + } else { + $this->string = (string) $s; + if ($m instanceof PHP_LexerGenerator_ParseryyToken) { + $this->metadata = $m->metadata; + } elseif (is_array($m)) { + $this->metadata = $m; + } + } + } + + function __toString() + { + return $this->_string; + } + + function offsetExists($offset) + { + return isset($this->metadata[$offset]); + } + + function offsetGet($offset) + { + return $this->metadata[$offset]; + } + + function offsetSet($offset, $value) + { + if ($offset === null) { + if (isset($value[0])) { + $x = ($value instanceof PHP_LexerGenerator_ParseryyToken) ? + $value->metadata : $value; + $this->metadata = array_merge($this->metadata, $x); + return; + } + $offset = count($this->metadata); + } + if ($value === null) { + return; + } + if ($value instanceof PHP_LexerGenerator_ParseryyToken) { + if ($value->metadata) { + $this->metadata[$offset] = $value->metadata; + } + } elseif ($value) { + $this->metadata[$offset] = $value; + } + } + + function offsetUnset($offset) + { + unset($this->metadata[$offset]); + } +} + +/** The following structure represents a single element of the + * parser's stack. Information stored includes: + * + * + The state number for the parser at this level of the stack. + * + * + The value of the token stored at this level of the stack. + * (In other words, the "major" token.) + * + * + The semantic value stored at this level of the stack. This is + * the information used by the action routines in the grammar. + * It is sometimes called the "minor" token. + */ +class PHP_LexerGenerator_ParseryyStackEntry +{ + public $stateno; /* The state-number */ + public $major; /* The major token value. This is the code + ** number for the token at this stack level */ + public $minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; + +// code external to the class is included here +#line 3 "Parser.y" + +/* ?> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_LexerGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_LexerGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Parser.php,v 1.9 2007/08/18 23:50:28 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** + * For regular expression validation + */ +require_once './LexerGenerator/Regex/Lexer.php'; +require_once './LexerGenerator/Regex/Parser.php'; +require_once './LexerGenerator/Exception.php'; +/** + * Token parser for plex files. + * + * This parser converts tokens pulled from {@link PHP_LexerGenerator_Lexer} + * into abstract patterns and rules, then creates the output file + * @package PHP_LexerGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version 0.3.4 + * @since Class available since Release 0.1.0 + */ +#line 166 "Parser.php" + +// declare_class is output here +#line 2 "Parser.y" +class PHP_LexerGenerator_Parser#line 171 "Parser.php" +{ +/* First off, code is included which follows the "include_class" declaration +** in the input file. */ +#line 78 "Parser.y" + + private $patterns; + private $out; + private $lex; + private $input; + private $counter; + private $token; + private $value; + private $line; + private $matchlongest; + private $_regexLexer; + private $_regexParser; + private $_patternIndex = 0; + + public $transTable = array( + 1 => self::PHPCODE, + 2 => self::COMMENTSTART, + 3 => self::COMMENTEND, + 4 => self::QUOTE, + 5 => self::PATTERN, + 6 => self::CODE, + 7 => self::SUBPATTERN, + 8 => self::PI, + ); + + function __construct($outfile, $lex) + { + $this->out = fopen($outfile, 'wb'); + if (!$this->out) { + throw new Exception('unable to open lexer output file "' . $outfile . '"'); + } + $this->lex = $lex; + $this->_regexLexer = new PHP_LexerGenerator_Regex_Lexer(''); + $this->_regexParser = new PHP_LexerGenerator_Regex_Parser($this->_regexLexer); + } + + function doLongestMatch($rules, $statename, $ruleindex) + { + fwrite($this->out, ' + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + do { + $rules = array('); + foreach ($rules as $rule) { + fwrite($this->out, ' + \'/^' . $rule['pattern'] . '/\','); + } + fwrite($this->out, ' + ); + $match = false; + foreach ($rules as $index => $rule) { + if (preg_match($rule, substr(' . $this->input . ', ' . + $this->counter . '), $yymatches)) { + if ($match) { + if (strlen($yymatches[0]) > strlen($match[0][0])) { + $match = array($yymatches, $index); // matches, token + } + } else { + $match = array($yymatches, $index); + } + } + } + if (!$match) { + throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' . + \': \' . ' . $this->input . '[' . $this->counter . ']); + } + ' . $this->token . ' = $match[1]; + ' . $this->value . ' = $match[0][0]; + $yysubmatches = $match[0]; + array_shift($yysubmatches); + if (!$yysubmatches) { + $yysubmatches = array(); + } + $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches); + if ($r === null) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + // skip this token + continue; + } else {'); + fwrite($this->out, ' + $yy_yymore_patterns = array_slice($rules, $this->token, true); + // yymore is needed + do { + if (!isset($yy_yymore_patterns[' . $this->token . '])) { + throw new Exception(\'cannot do yymore for the last token\'); + } + $match = false; + foreach ($yy_yymore_patterns[' . $this->token . '] as $index => $rule) { + if (preg_match(\'/\' . $rule . \'/\', + substr(' . $this->input . ', ' . $this->counter . '), $yymatches)) { + $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns + if ($match) { + if (strlen($yymatches[0]) > strlen($match[0][0])) { + $match = array($yymatches, $index); // matches, token + } + } else { + $match = array($yymatches, $index); + } + } + } + if (!$match) { + throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' . + \': \' . ' . $this->input . '[' . $this->counter . ']); + } + ' . $this->token . ' = $match[1]; + ' . $this->value . ' = $match[0][0]; + $yysubmatches = $match[0]; + array_shift($yysubmatches); + if (!$yysubmatches) { + $yysubmatches = array(); + } + ' . $this->line . ' = substr_count(' . $this->value . ', "\n"); + $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}(); + } while ($r !== null || !$r); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } else { + // accept + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + return true; + } + } + } while (true); +'); + } + + function doFirstMatch($rules, $statename, $ruleindex) + { + $patterns = array(); + $pattern = '/'; + $ruleMap = array(); + $tokenindex = array(); + $actualindex = 1; + $i = 0; + foreach ($rules as $rule) { + $ruleMap[$i++] = $actualindex; + $tokenindex[$actualindex] = $rule['subpatterns']; + $actualindex += $rule['subpatterns'] + 1; + $patterns[] = '^(' . $rule['pattern'] . ')'; + } + $tokencount = $tokenindex; + $tokenindex = var_export($tokenindex, true); + $tokenindex = explode("\n", $tokenindex); + // indent for prettiness + $tokenindex = implode("\n ", $tokenindex); + $pattern .= implode('|', $patterns); + $pattern .= '/'; + fwrite($this->out, ' + $tokenMap = ' . $tokenindex . '; + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + '); + fwrite($this->out, '$yy_global_pattern = "' . + $pattern . '";' . "\n"); + fwrite($this->out, ' + do { + if (preg_match($yy_global_pattern, substr(' . $this->input . ', ' . + $this->counter . + '), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns + if (!count($yymatches)) { + throw new Exception(\'Error: lexing failed because a rule matched\' . + \'an empty string. Input "\' . substr(' . $this->input . ', + ' . $this->counter . ', 5) . \'... state ' . $statename . '\'); + } + next($yymatches); // skip global match + ' . $this->token . ' = key($yymatches); // token number + if ($tokenMap[' . $this->token . ']) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, ' . $this->token . ' + 1, + $tokenMap[' . $this->token . ']); + } else { + $yysubmatches = array(); + } + ' . $this->value . ' = current($yymatches); // token value + $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches); + if ($r === null) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + // skip this token + continue; + } else {'); + fwrite($this->out, ' $yy_yymore_patterns = array(' . "\n"); + $extra = 0; + for($i = 0; count($patterns); $i++) { + unset($patterns[$i]); + $extra += $tokencount[0]; + array_shift($tokencount); + fwrite($this->out, ' ' . $ruleMap[$i] . ' => array(' . $extra . ', "' . + implode('|', $patterns) . "\"),\n"); + } + fwrite($this->out, ' );' . "\n"); + fwrite($this->out, ' + // yymore is needed + do { + if (!strlen($yy_yymore_patterns[' . $this->token . '][1])) { + throw new Exception(\'cannot do yymore for the last token\'); + } + $yysubmatches = array(); + if (preg_match(\'/\' . $yy_yymore_patterns[' . $this->token . '][1] . \'/\', + substr(' . $this->input . ', ' . $this->counter . '), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns + next($yymatches); // skip global match + ' . $this->token . ' += key($yymatches) + $yy_yymore_patterns[' . $this->token . '][0]; // token number + ' . $this->value . ' = current($yymatches); // token value + ' . $this->line . ' = substr_count(' . $this->value . ', "\n"); + if ($tokenMap[' . $this->token . ']) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, ' . $this->token . ' + 1, + $tokenMap[' . $this->token . ']); + } else { + $yysubmatches = array(); + } + } + $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches); + } while ($r !== null && !is_bool($r)); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + // skip this token + continue; + } else { + // accept + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + return true; + } + } + } else { + throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' . + \': \' . ' . $this->input . '[' . $this->counter . ']); + } + break; + } while (true); +'); + } + + function outputRules($rules, $statename) + { + static $ruleindex = 1; + if (!$statename) { + $statename = $ruleindex; + } + fwrite($this->out, ' + function yylex' . $ruleindex . '() + {'); + if ($this->matchlongest) { + $ruleMap = array(); + foreach ($rules as $i => $rule) { + $ruleMap[$i] = $i; + } + $this->doLongestMatch($rules, $statename, $ruleindex); + } else { + $ruleMap = array(); + $actualindex = 1; + $i = 0; + foreach ($rules as $rule) { + $ruleMap[$i++] = $actualindex; + $actualindex += $rule['subpatterns'] + 1; + } + $this->doFirstMatch($rules, $statename, $ruleindex); + } + fwrite($this->out, ' + } // end function + +'); + if (is_string($statename)) { + fwrite($this->out, ' + const ' . $statename . ' = ' . $ruleindex . '; +'); + } + foreach ($rules as $i => $rule) { + fwrite($this->out, ' function yy_r' . $ruleindex . '_' . $ruleMap[$i] . '($yy_subpatterns) + { +' . $rule['code'] . +' } +'); + } + $ruleindex++; // for next set of rules + } + + function error($msg) + { + echo 'Error on line ' . $this->lex->line . ': ' , $msg; + } + + function _validatePattern($pattern, $update = false) + { + $this->_regexLexer->reset($pattern, $this->lex->line); + $this->_regexParser->reset($this->_patternIndex, $update); + try { + while ($this->_regexLexer->yylex()) { + $this->_regexParser->doParse( + $this->_regexLexer->token, $this->_regexLexer->value); + } + $this->_regexParser->doParse(0, 0); + } catch (PHP_LexerGenerator_Exception $e) { + $this->error($e->getMessage()); + throw new PHP_LexerGenerator_Exception('Invalid pattern "' . $pattern . '"'); + } + return $this->_regexParser->result; + } +#line 518 "Parser.php" + +/* Next is all token values, as class constants +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ + const PHPCODE = 1; + const COMMENTSTART = 2; + const COMMENTEND = 3; + const PI = 4; + const SUBPATTERN = 5; + const CODE = 6; + const PATTERN = 7; + const QUOTE = 8; + const YY_NO_ACTION = 91; + const YY_ACCEPT_ACTION = 90; + const YY_ERROR_ACTION = 89; + +/* Next are that tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N < self::YYNSTATE Shift N. That is, +** push the lookahead +** token onto the stack +** and goto state N. +** +** self::YYNSTATE <= N < self::YYNSTATE+self::YYNRULE Reduce by rule N-YYNSTATE. +** +** N == self::YYNSTATE+self::YYNRULE A syntax error has occurred. +** +** N == self::YYNSTATE+self::YYNRULE+1 The parser accepts its +** input. (and concludes parsing) +** +** N == self::YYNSTATE+self::YYNRULE+2 No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large static array $yy_action. +** Given state S and lookahead X, the action is computed as +** +** self::$yy_action[self::$yy_shift_ofst[S] + X ] +** +** If the index value self::$yy_shift_ofst[S]+X is out of range or if the value +** self::$yy_lookahead[self::$yy_shift_ofst[S]+X] is not equal to X or if +** self::$yy_shift_ofst[S] is equal to self::YY_SHIFT_USE_DFLT, it means that +** the action is not in the table and that self::$yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the static $yy_reduce_ofst array is used in place of +** the static $yy_shift_ofst array and self::YY_REDUCE_USE_DFLT is used in place of +** self::YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** self::$yy_action A single table containing all actions. +** self::$yy_lookahead A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** self::$yy_shift_ofst For each state, the offset into self::$yy_action for +** shifting terminals. +** self::$yy_reduce_ofst For each state, the offset into self::$yy_action for +** shifting non-terminals after a reduce. +** self::$yy_default Default action for each state. +*/ + const YY_SZ_ACTTAB = 80; +static public $yy_action = array( + /* 0 */ 35, 24, 50, 50, 48, 51, 51, 54, 47, 43, + /* 10 */ 53, 54, 45, 31, 53, 32, 30, 50, 50, 1, + /* 20 */ 51, 51, 34, 50, 17, 8, 51, 90, 52, 6, + /* 30 */ 3, 29, 50, 50, 25, 51, 51, 11, 38, 18, + /* 40 */ 1, 41, 42, 39, 10, 36, 18, 12, 37, 18, + /* 50 */ 20, 7, 2, 16, 13, 15, 18, 27, 9, 2, + /* 60 */ 5, 28, 14, 1, 44, 40, 33, 49, 56, 46, + /* 70 */ 26, 19, 1, 55, 2, 21, 4, 23, 22, 8, + ); + static public $yy_lookahead = array( + /* 0 */ 3, 3, 5, 5, 1, 8, 8, 5, 6, 2, + /* 10 */ 8, 5, 6, 13, 8, 3, 3, 5, 5, 19, + /* 20 */ 8, 8, 4, 5, 1, 2, 8, 10, 11, 12, + /* 30 */ 5, 4, 5, 5, 13, 8, 8, 18, 5, 20, + /* 40 */ 19, 8, 5, 6, 18, 5, 20, 18, 8, 20, + /* 50 */ 4, 1, 2, 7, 18, 7, 20, 13, 1, 2, + /* 60 */ 5, 14, 15, 19, 5, 6, 13, 1, 1, 1, + /* 70 */ 16, 20, 19, 3, 2, 17, 12, 4, 17, 2, +); + const YY_SHIFT_USE_DFLT = -4; + const YY_SHIFT_MAX = 35; + static public $yy_shift_ofst = array( + /* 0 */ 23, 27, 18, 28, 50, 28, 57, 72, 73, 72, + /* 10 */ 13, 12, -3, -2, 46, 40, 40, 77, 2, 6, + /* 20 */ 59, 33, 33, 37, 3, 7, 48, 7, 70, 55, + /* 30 */ 68, 7, 67, 7, 25, 66, +); + const YY_REDUCE_USE_DFLT = -1; + const YY_REDUCE_MAX = 17; + static public $yy_reduce_ofst = array( + /* 0 */ 17, 29, 19, 26, 21, 36, 53, 44, 47, 0, + /* 10 */ 51, 51, 51, 51, 54, 58, 61, 64, +); + static public $yyExpectedTokens = array( + /* 0 */ array(1, 2, ), + /* 1 */ array(4, 5, 8, ), + /* 2 */ array(4, 5, 8, ), + /* 3 */ array(5, 8, ), + /* 4 */ array(1, 2, ), + /* 5 */ array(5, 8, ), + /* 6 */ array(1, 2, ), + /* 7 */ array(2, ), + /* 8 */ array(4, ), + /* 9 */ array(2, ), + /* 10 */ array(3, 5, 8, ), + /* 11 */ array(3, 5, 8, ), + /* 12 */ array(3, 5, 8, ), + /* 13 */ array(3, 5, 8, ), + /* 14 */ array(4, 7, ), + /* 15 */ array(5, 8, ), + /* 16 */ array(5, 8, ), + /* 17 */ array(2, ), + /* 18 */ array(5, 6, 8, ), + /* 19 */ array(5, 6, 8, ), + /* 20 */ array(5, 6, ), + /* 21 */ array(5, 8, ), + /* 22 */ array(5, 8, ), + /* 23 */ array(5, 6, ), + /* 24 */ array(1, ), + /* 25 */ array(2, ), + /* 26 */ array(7, ), + /* 27 */ array(2, ), + /* 28 */ array(3, ), + /* 29 */ array(5, ), + /* 30 */ array(1, ), + /* 31 */ array(2, ), + /* 32 */ array(1, ), + /* 33 */ array(2, ), + /* 34 */ array(5, ), + /* 35 */ array(1, ), + /* 36 */ array(), + /* 37 */ array(), + /* 38 */ array(), + /* 39 */ array(), + /* 40 */ array(), + /* 41 */ array(), + /* 42 */ array(), + /* 43 */ array(), + /* 44 */ array(), + /* 45 */ array(), + /* 46 */ array(), + /* 47 */ array(), + /* 48 */ array(), + /* 49 */ array(), + /* 50 */ array(), + /* 51 */ array(), + /* 52 */ array(), + /* 53 */ array(), + /* 54 */ array(), + /* 55 */ array(), + /* 56 */ array(), +); + static public $yy_default = array( + /* 0 */ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + /* 10 */ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + /* 20 */ 89, 69, 68, 89, 75, 60, 63, 61, 89, 89, + /* 30 */ 71, 59, 70, 58, 89, 74, 86, 85, 88, 65, + /* 40 */ 67, 87, 64, 78, 66, 80, 73, 79, 77, 76, + /* 50 */ 82, 81, 57, 83, 84, 62, 72, +); +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** self::YYNOCODE is a number which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** self::YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** self::YYSTACKDEPTH is the maximum depth of the parser's stack. +** self::YYNSTATE the combined number of states. +** self::YYNRULE the number of rules in the grammar +** self::YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ + const YYNOCODE = 22; + const YYSTACKDEPTH = 100; + const YYNSTATE = 57; + const YYNRULE = 32; + const YYERRORSYMBOL = 9; + const YYERRSYMDT = 'yy0'; + const YYFALLBACK = 0; + /** The next table maps tokens into fallback tokens. If a construct + * like the following: + * + * %fallback ID X Y Z. + * + * appears in the grammer, then ID becomes a fallback token for X, Y, + * and Z. Whenever one of the tokens X, Y, or Z is input to the parser + * but it does not parse, the type of the token is changed to ID and + * the parse is retried before an error is thrown. + */ + static public $yyFallback = array( + ); + /** + * Turn parser tracing on by giving a stream to which to write the trace + * and a prompt to preface each trace message. Tracing is turned off + * by making either argument NULL + * + * Inputs: + * + * - A stream resource to which trace output should be written. + * If NULL, then tracing is turned off. + * - A prefix string written at the beginning of every + * line of trace output. If NULL, then tracing is + * turned off. + * + * Outputs: + * + * - None. + * @param resource + * @param string + */ + static function Trace($TraceFILE, $zTracePrompt) + { + if (!$TraceFILE) { + $zTracePrompt = 0; + } elseif (!$zTracePrompt) { + $TraceFILE = 0; + } + self::$yyTraceFILE = $TraceFILE; + self::$yyTracePrompt = $zTracePrompt; + } + + /** + * Output debug information to output (php://output stream) + */ + static function PrintTrace() + { + self::$yyTraceFILE = fopen('php://output', 'w'); + self::$yyTracePrompt = ''; + } + + /** + * @var resource|0 + */ + static public $yyTraceFILE; + /** + * String to prepend to debug output + * @var string|0 + */ + static public $yyTracePrompt; + /** + * @var int + */ + public $yyidx; /* Index of top element in stack */ + /** + * @var int + */ + public $yyerrcnt; /* Shifts left before out of the error */ + /** + * @var array + */ + public $yystack = array(); /* The parser's stack */ + + /** + * For tracing shifts, the names of all terminals and nonterminals + * are required. The following table supplies these names + * @var array + */ + static public $yyTokenName = array( + '$', 'PHPCODE', 'COMMENTSTART', 'COMMENTEND', + 'PI', 'SUBPATTERN', 'CODE', 'PATTERN', + 'QUOTE', 'error', 'start', 'lexfile', + 'declare', 'rules', 'declarations', 'processing_instructions', + 'pattern_declarations', 'subpattern', 'rule', 'reset_rules', + 'rule_subpattern', + ); + + /** + * For tracing reduce actions, the names of all rules are required. + * @var array + */ + static public $yyRuleName = array( + /* 0 */ "start ::= lexfile", + /* 1 */ "lexfile ::= declare rules", + /* 2 */ "lexfile ::= declare PHPCODE rules", + /* 3 */ "lexfile ::= PHPCODE declare rules", + /* 4 */ "lexfile ::= PHPCODE declare PHPCODE rules", + /* 5 */ "declare ::= COMMENTSTART declarations COMMENTEND", + /* 6 */ "declarations ::= processing_instructions pattern_declarations", + /* 7 */ "processing_instructions ::= PI SUBPATTERN", + /* 8 */ "processing_instructions ::= PI CODE", + /* 9 */ "processing_instructions ::= processing_instructions PI SUBPATTERN", + /* 10 */ "processing_instructions ::= processing_instructions PI CODE", + /* 11 */ "pattern_declarations ::= PATTERN subpattern", + /* 12 */ "pattern_declarations ::= pattern_declarations PATTERN subpattern", + /* 13 */ "rules ::= COMMENTSTART rule COMMENTEND", + /* 14 */ "rules ::= COMMENTSTART PI SUBPATTERN rule COMMENTEND", + /* 15 */ "rules ::= COMMENTSTART rule COMMENTEND PHPCODE", + /* 16 */ "rules ::= COMMENTSTART PI SUBPATTERN rule COMMENTEND PHPCODE", + /* 17 */ "rules ::= reset_rules rule COMMENTEND", + /* 18 */ "rules ::= reset_rules PI SUBPATTERN rule COMMENTEND", + /* 19 */ "rules ::= reset_rules rule COMMENTEND PHPCODE", + /* 20 */ "rules ::= reset_rules PI SUBPATTERN rule COMMENTEND PHPCODE", + /* 21 */ "reset_rules ::= rules COMMENTSTART", + /* 22 */ "rule ::= rule_subpattern CODE", + /* 23 */ "rule ::= rule rule_subpattern CODE", + /* 24 */ "rule_subpattern ::= QUOTE", + /* 25 */ "rule_subpattern ::= SUBPATTERN", + /* 26 */ "rule_subpattern ::= rule_subpattern QUOTE", + /* 27 */ "rule_subpattern ::= rule_subpattern SUBPATTERN", + /* 28 */ "subpattern ::= QUOTE", + /* 29 */ "subpattern ::= SUBPATTERN", + /* 30 */ "subpattern ::= subpattern QUOTE", + /* 31 */ "subpattern ::= subpattern SUBPATTERN", + ); + + /** + * This function returns the symbolic name associated with a token + * value. + * @param int + * @return string + */ + function tokenName($tokenType) + { + if ($tokenType === 0) { + return 'End of Input'; + } + if ($tokenType > 0 && $tokenType < count(self::$yyTokenName)) { + return self::$yyTokenName[$tokenType]; + } else { + return "Unknown"; + } + } + + /** + * The following function deletes the value associated with a + * symbol. The symbol can be either a terminal or nonterminal. + * @param int the symbol code + * @param mixed the symbol's value + */ + static function yy_destructor($yymajor, $yypminor) + { + switch ($yymajor) { + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ + default: break; /* If no destructor action specified: do nothing */ + } + } + + /** + * Pop the parser's stack once. + * + * If there is a destructor routine associated with the token which + * is popped from the stack, then call it. + * + * Return the major token number for the symbol popped. + * @param PHP_LexerGenerator_ParseryyParser + * @return int + */ + function yy_pop_parser_stack() + { + if (!count($this->yystack)) { + return; + } + $yytos = array_pop($this->yystack); + if (self::$yyTraceFILE && $this->yyidx >= 0) { + fwrite(self::$yyTraceFILE, + self::$yyTracePrompt . 'Popping ' . self::$yyTokenName[$yytos->major] . + "\n"); + } + $yymajor = $yytos->major; + self::yy_destructor($yymajor, $yytos->minor); + $this->yyidx--; + return $yymajor; + } + + /** + * Deallocate and destroy a parser. Destructors are all called for + * all stack elements before shutting the parser down. + */ + function __destruct() + { + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + if (is_resource(self::$yyTraceFILE)) { + fclose(self::$yyTraceFILE); + } + } + + /** + * Based on the current state and parser stack, get a list of all + * possible lookahead tokens + * @param int + * @return array + */ + function yy_get_expected_tokens($token) + { + $state = $this->yystack[$this->yyidx]->stateno; + $expected = self::$yyExpectedTokens[$state]; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return $expected; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return array_unique($expected); + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate])) { + $expected += self::$yyExpectedTokens[$nextstate]; + if (in_array($token, + self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return array_unique($expected); + } + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new PHP_LexerGenerator_ParseryyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return array_unique($expected); + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return $expected; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + return array_unique($expected); + } + + /** + * Based on the parser state and current parser stack, determine whether + * the lookahead token is possible. + * + * The parser will convert the token value to an error token if not. This + * catches some unusual edge cases where the parser would fail. + * @param int + * @return bool + */ + function yy_is_expected_token($token) + { + if ($token === 0) { + return true; // 0 is not part of this + } + $state = $this->yystack[$this->yyidx]->stateno; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return true; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return true; + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate]) && + in_array($token, self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new PHP_LexerGenerator_ParseryyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + if (!$token) { + // end of input: this is valid + return true; + } + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return false; + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return true; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + + /** + * Find the appropriate action for a parser given the terminal + * look-ahead token iLookAhead. + * + * If the look-ahead token is YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return YY_NO_ACTION. + * @param int The look-ahead token + */ + function yy_find_shift_action($iLookAhead) + { + $stateno = $this->yystack[$this->yyidx]->stateno; + + /* if ($this->yyidx < 0) return self::YY_NO_ACTION; */ + if (!isset(self::$yy_shift_ofst[$stateno])) { + // no shift actions + return self::$yy_default[$stateno]; + } + $i = self::$yy_shift_ofst[$stateno]; + if ($i === self::YY_SHIFT_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback) + && ($iFallback = self::$yyFallback[$iLookAhead]) != 0) { + if (self::$yyTraceFILE) { + fwrite(self::$yyTraceFILE, self::$yyTracePrompt . "FALLBACK " . + self::$yyTokenName[$iLookAhead] . " => " . + self::$yyTokenName[$iFallback] . "\n"); + } + return $this->yy_find_shift_action($iFallback); + } + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Find the appropriate action for a parser given the non-terminal + * look-ahead token $iLookAhead. + * + * If the look-ahead token is self::YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return self::YY_NO_ACTION. + * @param int Current state number + * @param int The look-ahead token + */ + function yy_find_reduce_action($stateno, $iLookAhead) + { + /* $stateno = $this->yystack[$this->yyidx]->stateno; */ + + if (!isset(self::$yy_reduce_ofst[$stateno])) { + return self::$yy_default[$stateno]; + } + $i = self::$yy_reduce_ofst[$stateno]; + if ($i == self::YY_REDUCE_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Perform a shift action. + * @param int The new state to shift in + * @param int The major token to shift in + * @param mixed the minor token to shift in + */ + function yy_shift($yyNewState, $yyMajor, $yypMinor) + { + $this->yyidx++; + if ($this->yyidx >= self::YYSTACKDEPTH) { + $this->yyidx--; + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sStack Overflow!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will execute if the parser + ** stack ever overflows */ + return; + } + $yytos = new PHP_LexerGenerator_ParseryyStackEntry; + $yytos->stateno = $yyNewState; + $yytos->major = $yyMajor; + $yytos->minor = $yypMinor; + array_push($this->yystack, $yytos); + if (self::$yyTraceFILE && $this->yyidx > 0) { + fprintf(self::$yyTraceFILE, "%sShift %d\n", self::$yyTracePrompt, + $yyNewState); + fprintf(self::$yyTraceFILE, "%sStack:", self::$yyTracePrompt); + for($i = 1; $i <= $this->yyidx; $i++) { + fprintf(self::$yyTraceFILE, " %s", + self::$yyTokenName[$this->yystack[$i]->major]); + } + fwrite(self::$yyTraceFILE,"\n"); + } + } + + /** + * The following table contains information about every rule that + * is used during the reduce. + * + *
+     * array(
+     *  array(
+     *   int $lhs;         Symbol on the left-hand side of the rule
+     *   int $nrhs;     Number of right-hand side symbols in the rule
+     *  ),...
+     * );
+     * 
+ */ + static public $yyRuleInfo = array( + array( 'lhs' => 10, 'rhs' => 1 ), + array( 'lhs' => 11, 'rhs' => 2 ), + array( 'lhs' => 11, 'rhs' => 3 ), + array( 'lhs' => 11, 'rhs' => 3 ), + array( 'lhs' => 11, 'rhs' => 4 ), + array( 'lhs' => 12, 'rhs' => 3 ), + array( 'lhs' => 14, 'rhs' => 2 ), + array( 'lhs' => 15, 'rhs' => 2 ), + array( 'lhs' => 15, 'rhs' => 2 ), + array( 'lhs' => 15, 'rhs' => 3 ), + array( 'lhs' => 15, 'rhs' => 3 ), + array( 'lhs' => 16, 'rhs' => 2 ), + array( 'lhs' => 16, 'rhs' => 3 ), + array( 'lhs' => 13, 'rhs' => 3 ), + array( 'lhs' => 13, 'rhs' => 5 ), + array( 'lhs' => 13, 'rhs' => 4 ), + array( 'lhs' => 13, 'rhs' => 6 ), + array( 'lhs' => 13, 'rhs' => 3 ), + array( 'lhs' => 13, 'rhs' => 5 ), + array( 'lhs' => 13, 'rhs' => 4 ), + array( 'lhs' => 13, 'rhs' => 6 ), + array( 'lhs' => 19, 'rhs' => 2 ), + array( 'lhs' => 18, 'rhs' => 2 ), + array( 'lhs' => 18, 'rhs' => 3 ), + array( 'lhs' => 20, 'rhs' => 1 ), + array( 'lhs' => 20, 'rhs' => 1 ), + array( 'lhs' => 20, 'rhs' => 2 ), + array( 'lhs' => 20, 'rhs' => 2 ), + array( 'lhs' => 17, 'rhs' => 1 ), + array( 'lhs' => 17, 'rhs' => 1 ), + array( 'lhs' => 17, 'rhs' => 2 ), + array( 'lhs' => 17, 'rhs' => 2 ), + ); + + /** + * The following table contains a mapping of reduce action to method name + * that handles the reduction. + * + * If a rule is not set, it has no handler. + */ + static public $yyReduceMap = array( + 1 => 1, + 2 => 2, + 3 => 3, + 4 => 4, + 5 => 5, + 6 => 6, + 7 => 7, + 8 => 7, + 9 => 9, + 10 => 9, + 11 => 11, + 12 => 12, + 13 => 13, + 14 => 14, + 15 => 15, + 16 => 16, + 17 => 17, + 18 => 18, + 19 => 19, + 20 => 20, + 21 => 21, + 22 => 22, + 23 => 23, + 24 => 24, + 25 => 25, + 26 => 26, + 27 => 27, + 28 => 28, + 29 => 29, + 30 => 30, + 31 => 31, + ); + /* Beginning here are the reduction cases. A typical example + ** follows: + ** #line + ** function yy_r0($yymsp){ ... } // User supplied code + ** #line + */ +#line 423 "Parser.y" + function yy_r1(){ + fwrite($this->out, ' + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{\'yylex\' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + +'); + foreach ($this->yystack[$this->yyidx + 0]->minor as $rule) { + $this->outputRules($rule['rules'], $rule['statename']); + if ($rule['code']) { + fwrite($this->out, $rule['code']); + } + } + } +#line 1319 "Parser.php" +#line 457 "Parser.y" + function yy_r2(){ + fwrite($this->out, ' + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{\'yylex\' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + +'); + if (strlen($this->yystack[$this->yyidx + -1]->minor)) { + fwrite($this->out, $this->yystack[$this->yyidx + -1]->minor); + } + foreach ($this->yystack[$this->yyidx + 0]->minor as $rule) { + $this->outputRules($rule['rules'], $rule['statename']); + if ($rule['code']) { + fwrite($this->out, $rule['code']); + } + } + } +#line 1358 "Parser.php" +#line 494 "Parser.y" + function yy_r3(){ + if (strlen($this->yystack[$this->yyidx + -2]->minor)) { + fwrite($this->out, $this->yystack[$this->yyidx + -2]->minor); + } + fwrite($this->out, ' + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{\'yylex\' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + +'); + foreach ($this->yystack[$this->yyidx + 0]->minor as $rule) { + $this->outputRules($rule['rules'], $rule['statename']); + if ($rule['code']) { + fwrite($this->out, $rule['code']); + } + } + } +#line 1397 "Parser.php" +#line 531 "Parser.y" + function yy_r4(){ + if (strlen($this->yystack[$this->yyidx + -3]->minor)) { + fwrite($this->out, $this->yystack[$this->yyidx + -3]->minor); + } + fwrite($this->out, ' + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{\'yylex\' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + +'); + if (strlen($this->yystack[$this->yyidx + -1]->minor)) { + fwrite($this->out, $this->yystack[$this->yyidx + -1]->minor); + } + foreach ($this->yystack[$this->yyidx + 0]->minor as $rule) { + $this->outputRules($rule['rules'], $rule['statename']); + if ($rule['code']) { + fwrite($this->out, $rule['code']); + } + } + } +#line 1439 "Parser.php" +#line 572 "Parser.y" + function yy_r5(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; + $this->patterns = $this->yystack[$this->yyidx + -1]->minor['patterns']; + $this->_patternIndex = 1; + } +#line 1446 "Parser.php" +#line 578 "Parser.y" + function yy_r6(){ + $expected = array( + 'counter' => true, + 'input' => true, + 'token' => true, + 'value' => true, + 'line' => true, + ); + foreach ($this->yystack[$this->yyidx + -1]->minor as $pi) { + if (isset($expected[$pi['pi']])) { + unset($expected[$pi['pi']]); + continue; + } + if (count($expected)) { + throw new Exception('Processing Instructions "' . + implode(', ', array_keys($expected)) . '" must be defined'); + } + } + $expected = array( + 'counter' => true, + 'input' => true, + 'token' => true, + 'value' => true, + 'line' => true, + 'matchlongest' => true, + ); + foreach ($this->yystack[$this->yyidx + -1]->minor as $pi) { + if (isset($expected[$pi['pi']])) { + $this->{$pi['pi']} = $pi['definition']; + if ($pi['pi'] == 'matchlongest') { + $this->matchlongest = true; + } + continue; + } + $this->error('Unknown processing instruction %' . $pi['pi'] . + ', should be one of "' . implode(', ', array_keys($expected)) . '"'); + } + $this->_retvalue = array('patterns' => $this->yystack[$this->yyidx + 0]->minor, 'pis' => $this->yystack[$this->yyidx + -1]->minor); + $this->_patternIndex = 1; + } +#line 1488 "Parser.php" +#line 619 "Parser.y" + function yy_r7(){ + $this->_retvalue = array(array('pi' => $this->yystack[$this->yyidx + -1]->minor, 'definition' => $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1493 "Parser.php" +#line 625 "Parser.y" + function yy_r9(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; + $this->_retvalue[] = array('pi' => $this->yystack[$this->yyidx + -1]->minor, 'definition' => $this->yystack[$this->yyidx + 0]->minor); + } +#line 1499 "Parser.php" +#line 634 "Parser.y" + function yy_r11(){ + $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor => $this->yystack[$this->yyidx + 0]->minor); + // reset internal indicator of where we are in a pattern + $this->_patternIndex = 0; + } +#line 1506 "Parser.php" +#line 639 "Parser.y" + function yy_r12(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; + if (isset($this->_retvalue[$this->yystack[$this->yyidx + -1]->minor])) { + throw new Exception('Pattern "' . $this->yystack[$this->yyidx + -1]->minor . '" is already defined as "' . + $this->_retvalue[$this->yystack[$this->yyidx + -1]->minor] . '", cannot redefine as "' . $this->yystack[$this->yyidx + 0]->minor->string . '"'); + } + $this->_retvalue[$this->yystack[$this->yyidx + -1]->minor] = $this->yystack[$this->yyidx + 0]->minor; + // reset internal indicator of where we are in a pattern declaration + $this->_patternIndex = 0; + } +#line 1518 "Parser.php" +#line 650 "Parser.y" + function yy_r13(){ + $this->_retvalue = array(array('rules' => $this->yystack[$this->yyidx + -1]->minor, 'code' => '', 'statename' => '')); + } +#line 1523 "Parser.php" +#line 653 "Parser.y" + function yy_r14(){ + if ($this->yystack[$this->yyidx + -3]->minor != 'statename') { + throw new Exception('Error: only %statename processing instruction ' . + 'is allowed in rule sections'); + } + $this->_retvalue = array(array('rules' => $this->yystack[$this->yyidx + -1]->minor, 'code' => '', 'statename' => $this->yystack[$this->yyidx + -2]->minor)); + } +#line 1532 "Parser.php" +#line 660 "Parser.y" + function yy_r15(){ + $this->_retvalue = array(array('rules' => $this->yystack[$this->yyidx + -2]->minor, 'code' => $this->yystack[$this->yyidx + 0]->minor, 'statename' => '')); + } +#line 1537 "Parser.php" +#line 663 "Parser.y" + function yy_r16(){ + if ($this->yystack[$this->yyidx + -4]->minor != 'statename') { + throw new Exception('Error: only %statename processing instruction ' . + 'is allowed in rule sections'); + } + $this->_retvalue = array(array('rules' => $this->yystack[$this->yyidx + -2]->minor, 'code' => $this->yystack[$this->yyidx + 0]->minor, 'statename' => $this->yystack[$this->yyidx + -3]->minor)); + $this->_patternIndex = 1; + } +#line 1547 "Parser.php" +#line 671 "Parser.y" + function yy_r17(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; + $this->_retvalue[] = array('rules' => $this->yystack[$this->yyidx + -1]->minor, 'code' => '', 'statename' => ''); + $this->_patternIndex = 1; + } +#line 1554 "Parser.php" +#line 676 "Parser.y" + function yy_r18(){ + if ($this->yystack[$this->yyidx + -3]->minor != 'statename') { + throw new Exception('Error: only %statename processing instruction ' . + 'is allowed in rule sections'); + } + $this->_retvalue = $this->yystack[$this->yyidx + -4]->minor; + $this->_retvalue[] = array('rules' => $this->yystack[$this->yyidx + -1]->minor, 'code' => '', 'statename' => $this->yystack[$this->yyidx + -2]->minor); + } +#line 1564 "Parser.php" +#line 684 "Parser.y" + function yy_r19(){ + $this->_retvalue = $this->yystack[$this->yyidx + -3]->minor; + $this->_retvalue[] = array('rules' => $this->yystack[$this->yyidx + -2]->minor, 'code' => $this->yystack[$this->yyidx + 0]->minor, 'statename' => ''); + } +#line 1570 "Parser.php" +#line 688 "Parser.y" + function yy_r20(){ + if ($this->yystack[$this->yyidx + -4]->minor != 'statename') { + throw new Exception('Error: only %statename processing instruction ' . + 'is allowed in rule sections'); + } + $this->_retvalue = $this->yystack[$this->yyidx + -5]->minor; + $this->_retvalue[] = array('rules' => $this->yystack[$this->yyidx + -2]->minor, 'code' => $this->yystack[$this->yyidx + 0]->minor, 'statename' => $this->yystack[$this->yyidx + -3]->minor); + } +#line 1580 "Parser.php" +#line 697 "Parser.y" + function yy_r21(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; + $this->_patternIndex = 1; + } +#line 1586 "Parser.php" +#line 702 "Parser.y" + function yy_r22(){ + $name = $this->yystack[$this->yyidx + -1]->minor[1]; + $this->yystack[$this->yyidx + -1]->minor = $this->yystack[$this->yyidx + -1]->minor[0]; + $this->yystack[$this->yyidx + -1]->minor = $this->_validatePattern($this->yystack[$this->yyidx + -1]->minor); + $this->_patternIndex += $this->yystack[$this->yyidx + -1]->minor['subpatterns'] + 1; + if (@preg_match('/' . str_replace('/', '\\/', $this->yystack[$this->yyidx + -1]->minor['pattern']) . '/', '')) { + $this->error('Rule "' . $name . '" can match the empty string, this will break lexing'); + } + $this->_retvalue = array(array('pattern' => str_replace('/', '\\/', $this->yystack[$this->yyidx + -1]->minor->string), 'code' => $this->yystack[$this->yyidx + 0]->minor, 'subpatterns' => $this->yystack[$this->yyidx + -1]->minor['subpatterns'])); + } +#line 1598 "Parser.php" +#line 712 "Parser.y" + function yy_r23(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; + $name = $this->yystack[$this->yyidx + -1]->minor[1]; + $this->yystack[$this->yyidx + -1]->minor = $this->yystack[$this->yyidx + -1]->minor[0]; + $this->yystack[$this->yyidx + -1]->minor = $this->_validatePattern($this->yystack[$this->yyidx + -1]->minor); + $this->_patternIndex += $this->yystack[$this->yyidx + -1]->minor['subpatterns'] + 1; + if (@preg_match('/' . str_replace('/', '\\/', $this->yystack[$this->yyidx + -1]->minor['pattern']) . '/', '')) { + $this->error('Rule "' . $name . '" can match the empty string, this will break lexing'); + } + $this->_retvalue[] = array('pattern' => str_replace('/', '\\/', $this->yystack[$this->yyidx + -1]->minor->string), 'code' => $this->yystack[$this->yyidx + 0]->minor, 'subpatterns' => $this->yystack[$this->yyidx + -1]->minor['subpatterns']); + } +#line 1611 "Parser.php" +#line 724 "Parser.y" + function yy_r24(){ + $this->_retvalue = array(preg_quote($this->yystack[$this->yyidx + 0]->minor, '/'), $this->yystack[$this->yyidx + 0]->minor); + } +#line 1616 "Parser.php" +#line 727 "Parser.y" + function yy_r25(){ + if (!isset($this->patterns[$this->yystack[$this->yyidx + 0]->minor])) { + $this->error('Undefined pattern "' . $this->yystack[$this->yyidx + 0]->minor . '" used in rules'); + throw new Exception('Undefined pattern "' . $this->yystack[$this->yyidx + 0]->minor . '" used in rules'); + } + $this->_retvalue = array($this->patterns[$this->yystack[$this->yyidx + 0]->minor], $this->yystack[$this->yyidx + 0]->minor); + } +#line 1625 "Parser.php" +#line 734 "Parser.y" + function yy_r26(){ + $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor[0] . preg_quote($this->yystack[$this->yyidx + 0]->minor, '/'), $this->yystack[$this->yyidx + -1]->minor[1] . ' ' . $this->yystack[$this->yyidx + 0]->minor); + } +#line 1630 "Parser.php" +#line 737 "Parser.y" + function yy_r27(){ + if (!isset($this->patterns[$this->yystack[$this->yyidx + 0]->minor])) { + $this->error('Undefined pattern "' . $this->yystack[$this->yyidx + 0]->minor . '" used in rules'); + throw new Exception('Undefined pattern "' . $this->yystack[$this->yyidx + 0]->minor . '" used in rules'); + } + $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor[0] . $this->patterns[$this->yystack[$this->yyidx + 0]->minor], $this->yystack[$this->yyidx + -1]->minor[1] . ' ' . $this->yystack[$this->yyidx + 0]->minor); + } +#line 1639 "Parser.php" +#line 745 "Parser.y" + function yy_r28(){ + $this->_retvalue = preg_quote($this->yystack[$this->yyidx + 0]->minor, '/'); + } +#line 1644 "Parser.php" +#line 748 "Parser.y" + function yy_r29(){ + // increment internal sub-pattern counter + // adjust back-references in pattern based on previous pattern + $test = $this->_validatePattern($this->yystack[$this->yyidx + 0]->minor, true); + $this->_patternIndex += $test['subpatterns']; + $this->_retvalue = $test['pattern']; + } +#line 1653 "Parser.php" +#line 755 "Parser.y" + function yy_r30(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor . preg_quote($this->yystack[$this->yyidx + 0]->minor, '/'); + } +#line 1658 "Parser.php" +#line 758 "Parser.y" + function yy_r31(){ + // increment internal sub-pattern counter + // adjust back-references in pattern based on previous pattern + $test = $this->_validatePattern($this->yystack[$this->yyidx + 0]->minor, true); + $this->_patternIndex += $test['subpatterns']; + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor . $test['pattern']; + } +#line 1667 "Parser.php" + + /** + * placeholder for the left hand side in a reduce operation. + * + * For a parser with a rule like this: + *
+     * rule(A) ::= B. { A = 1; }
+     * 
+ * + * The parser will translate to something like: + * + * + * function yy_r0(){$this->_retvalue = 1;} + * + */ + private $_retvalue; + + /** + * Perform a reduce action and the shift that must immediately + * follow the reduce. + * + * For a rule such as: + * + *
+     * A ::= B blah C. { dosomething(); }
+     * 
+ * + * This function will first call the action, if any, ("dosomething();" in our + * example), and then it will pop three states from the stack, + * one for each entry on the right-hand side of the expression + * (B, blah, and C in our example rule), and then push the result of the action + * back on to the stack with the resulting state reduced to (as described in the .out + * file) + * @param int Number of the rule by which to reduce + */ + function yy_reduce($yyruleno) + { + //int $yygoto; /* The next state */ + //int $yyact; /* The next action */ + //mixed $yygotominor; /* The LHS of the rule reduced */ + //PHP_LexerGenerator_ParseryyStackEntry $yymsp; /* The top of the parser's stack */ + //int $yysize; /* Amount to pop the stack */ + $yymsp = $this->yystack[$this->yyidx]; + if (self::$yyTraceFILE && $yyruleno >= 0 + && $yyruleno < count(self::$yyRuleName)) { + fprintf(self::$yyTraceFILE, "%sReduce (%d) [%s].\n", + self::$yyTracePrompt, $yyruleno, + self::$yyRuleName[$yyruleno]); + } + + $this->_retvalue = $yy_lefthand_side = null; + if (array_key_exists($yyruleno, self::$yyReduceMap)) { + // call the action + $this->_retvalue = null; + $this->{'yy_r' . self::$yyReduceMap[$yyruleno]}(); + $yy_lefthand_side = $this->_retvalue; + } + $yygoto = self::$yyRuleInfo[$yyruleno]['lhs']; + $yysize = self::$yyRuleInfo[$yyruleno]['rhs']; + $this->yyidx -= $yysize; + for($i = $yysize; $i; $i--) { + // pop all of the right-hand side parameters + array_pop($this->yystack); + } + $yyact = $this->yy_find_reduce_action($this->yystack[$this->yyidx]->stateno, $yygoto); + if ($yyact < self::YYNSTATE) { + /* If we are not debugging and the reduce action popped at least + ** one element off the stack, then we can push the new element back + ** onto the stack here, and skip the stack overflow test in yy_shift(). + ** That gives a significant speed improvement. */ + if (!self::$yyTraceFILE && $yysize) { + $this->yyidx++; + $x = new PHP_LexerGenerator_ParseryyStackEntry; + $x->stateno = $yyact; + $x->major = $yygoto; + $x->minor = $yy_lefthand_side; + $this->yystack[$this->yyidx] = $x; + } else { + $this->yy_shift($yyact, $yygoto, $yy_lefthand_side); + } + } elseif ($yyact == self::YYNSTATE + self::YYNRULE + 1) { + $this->yy_accept(); + } + } + + /** + * The following code executes when the parse fails + * + * Code from %parse_fail is inserted here + */ + function yy_parse_failed() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sFail!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser fails */ + } + + /** + * The following code executes when a syntax error first occurs. + * + * %syntax_error code is inserted here + * @param int The major type of the error token + * @param mixed The minor type of the error token + */ + function yy_syntax_error($yymajor, $TOKEN) + { +#line 66 "Parser.y" + + echo "Syntax Error on line " . $this->lex->line . ": token '" . + $this->lex->value . "' while parsing rule:"; + foreach ($this->yystack as $entry) { + echo $this->tokenName($entry->major) . ' '; + } + foreach ($this->yy_get_expected_tokens($yymajor) as $token) { + $expect[] = self::$yyTokenName[$token]; + } + throw new Exception('Unexpected ' . $this->tokenName($yymajor) . '(' . $TOKEN + . '), expected one of: ' . implode(',', $expect)); +#line 1792 "Parser.php" + } + + /** + * The following is executed when the parser accepts + * + * %parse_accept code is inserted here + */ + function yy_accept() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sAccept!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $stack = $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser accepts */ + } + + /** + * The main parser program. + * + * The first argument is the major token number. The second is + * the token value string as scanned from the input. + * + * @param int the token number + * @param mixed the token value + * @param mixed any extra arguments that should be passed to handlers + */ + function doParse($yymajor, $yytokenvalue) + { +// $yyact; /* The parser action. */ +// $yyendofinput; /* True if we are at the end of input */ + $yyerrorhit = 0; /* True if yymajor has invoked an error */ + + /* (re)initialize the parser, if necessary */ + if ($this->yyidx === null || $this->yyidx < 0) { + /* if ($yymajor == 0) return; // not sure why this was here... */ + $this->yyidx = 0; + $this->yyerrcnt = -1; + $x = new PHP_LexerGenerator_ParseryyStackEntry; + $x->stateno = 0; + $x->major = 0; + $this->yystack = array(); + array_push($this->yystack, $x); + } + $yyendofinput = ($yymajor==0); + + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sInput %s\n", + self::$yyTracePrompt, self::$yyTokenName[$yymajor]); + } + + do { + $yyact = $this->yy_find_shift_action($yymajor); + if ($yymajor < self::YYERRORSYMBOL && + !$this->yy_is_expected_token($yymajor)) { + // force a syntax error + $yyact = self::YY_ERROR_ACTION; + } + if ($yyact < self::YYNSTATE) { + $this->yy_shift($yyact, $yymajor, $yytokenvalue); + $this->yyerrcnt--; + if ($yyendofinput && $this->yyidx >= 0) { + $yymajor = 0; + } else { + $yymajor = self::YYNOCODE; + } + } elseif ($yyact < self::YYNSTATE + self::YYNRULE) { + $this->yy_reduce($yyact - self::YYNSTATE); + } elseif ($yyact == self::YY_ERROR_ACTION) { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sSyntax Error!\n", + self::$yyTracePrompt); + } + if (self::YYERRORSYMBOL) { + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if ($this->yyerrcnt < 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $yymx = $this->yystack[$this->yyidx]->major; + if ($yymx == self::YYERRORSYMBOL || $yyerrorhit ){ + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sDiscard input token %s\n", + self::$yyTracePrompt, self::$yyTokenName[$yymajor]); + } + $this->yy_destructor($yymajor, $yytokenvalue); + $yymajor = self::YYNOCODE; + } else { + while ($this->yyidx >= 0 && + $yymx != self::YYERRORSYMBOL && + ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE + ){ + $this->yy_pop_parser_stack(); + } + if ($this->yyidx < 0 || $yymajor==0) { + $this->yy_destructor($yymajor, $yytokenvalue); + $this->yy_parse_failed(); + $yymajor = self::YYNOCODE; + } elseif ($yymx != self::YYERRORSYMBOL) { + $u2 = 0; + $this->yy_shift($yyact, self::YYERRORSYMBOL, $u2); + } + } + $this->yyerrcnt = 3; + $yyerrorhit = 1; + } else { + /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if ($this->yyerrcnt <= 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $this->yyerrcnt = 3; + $this->yy_destructor($yymajor, $yytokenvalue); + if ($yyendofinput) { + $this->yy_parse_failed(); + } + $yymajor = self::YYNOCODE; + } + } else { + $this->yy_accept(); + $yymajor = self::YYNOCODE; + } + } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0); + } +} diff --git a/libs/lexer/LexerGenerator/Parser.y b/libs/lexer/LexerGenerator/Parser.y new file mode 100644 index 00000000..e59b8ff9 --- /dev/null +++ b/libs/lexer/LexerGenerator/Parser.y @@ -0,0 +1,768 @@ +%name PHP_LexerGenerator_Parser +%declare_class {class PHP_LexerGenerator_Parser} +%include { +/* ?> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_LexerGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_LexerGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Parser.y,v 1.8 2007/08/18 23:50:28 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** + * For regular expression validation + */ +require_once 'PHP/LexerGenerator/Regex/Lexer.php'; +require_once 'PHP/LexerGenerator/Regex/Parser.php'; +require_once 'PHP/LexerGenerator/Exception.php'; +/** + * Token parser for plex files. + * + * This parser converts tokens pulled from {@link PHP_LexerGenerator_Lexer} + * into abstract patterns and rules, then creates the output file + * @package PHP_LexerGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version 0.3.4 + * @since Class available since Release 0.1.0 + */ +} +%syntax_error { + echo "Syntax Error on line " . $this->lex->line . ": token '" . + $this->lex->value . "' while parsing rule:"; + foreach ($this->yystack as $entry) { + echo $this->tokenName($entry->major) . ' '; + } + foreach ($this->yy_get_expected_tokens($yymajor) as $token) { + $expect[] = self::$yyTokenName[$token]; + } + throw new Exception('Unexpected ' . $this->tokenName($yymajor) . '(' . $TOKEN + . '), expected one of: ' . implode(',', $expect)); +} +%include_class { + private $patterns; + private $out; + private $lex; + private $input; + private $counter; + private $token; + private $value; + private $line; + private $matchlongest; + private $_regexLexer; + private $_regexParser; + private $_patternIndex = 0; + + public $transTable = array( + 1 => self::PHPCODE, + 2 => self::COMMENTSTART, + 3 => self::COMMENTEND, + 4 => self::QUOTE, + 5 => self::PATTERN, + 6 => self::CODE, + 7 => self::SUBPATTERN, + 8 => self::PI, + ); + + function __construct($outfile, $lex) + { + $this->out = fopen($outfile, 'wb'); + if (!$this->out) { + throw new Exception('unable to open lexer output file "' . $outfile . '"'); + } + $this->lex = $lex; + $this->_regexLexer = new PHP_LexerGenerator_Regex_Lexer(''); + $this->_regexParser = new PHP_LexerGenerator_Regex_Parser($this->_regexLexer); + } + + function doLongestMatch($rules, $statename, $ruleindex) + { + fwrite($this->out, ' + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + do { + $rules = array('); + foreach ($rules as $rule) { + fwrite($this->out, ' + \'/^' . $rule['pattern'] . '/\','); + } + fwrite($this->out, ' + ); + $match = false; + foreach ($rules as $index => $rule) { + if (preg_match($rule, substr(' . $this->input . ', ' . + $this->counter . '), $yymatches)) { + if ($match) { + if (strlen($yymatches[0]) > strlen($match[0][0])) { + $match = array($yymatches, $index); // matches, token + } + } else { + $match = array($yymatches, $index); + } + } + } + if (!$match) { + throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' . + \': \' . ' . $this->input . '[' . $this->counter . ']); + } + ' . $this->token . ' = $match[1]; + ' . $this->value . ' = $match[0][0]; + $yysubmatches = $match[0]; + array_shift($yysubmatches); + if (!$yysubmatches) { + $yysubmatches = array(); + } + $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches); + if ($r === null) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + // skip this token + continue; + } else {'); + fwrite($this->out, ' + $yy_yymore_patterns = array_slice($rules, $this->token, true); + // yymore is needed + do { + if (!isset($yy_yymore_patterns[' . $this->token . '])) { + throw new Exception(\'cannot do yymore for the last token\'); + } + $match = false; + foreach ($yy_yymore_patterns[' . $this->token . '] as $index => $rule) { + if (preg_match(\'/\' . $rule . \'/\', + substr(' . $this->input . ', ' . $this->counter . '), $yymatches)) { + $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns + if ($match) { + if (strlen($yymatches[0]) > strlen($match[0][0])) { + $match = array($yymatches, $index); // matches, token + } + } else { + $match = array($yymatches, $index); + } + } + } + if (!$match) { + throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' . + \': \' . ' . $this->input . '[' . $this->counter . ']); + } + ' . $this->token . ' = $match[1]; + ' . $this->value . ' = $match[0][0]; + $yysubmatches = $match[0]; + array_shift($yysubmatches); + if (!$yysubmatches) { + $yysubmatches = array(); + } + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}(); + } while ($r !== null || !$r); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } else { + // accept + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + return true; + } + } + } while (true); +'); + } + + function doFirstMatch($rules, $statename, $ruleindex) + { + $patterns = array(); + $pattern = '/'; + $ruleMap = array(); + $tokenindex = array(); + $actualindex = 1; + $i = 0; + foreach ($rules as $rule) { + $ruleMap[$i++] = $actualindex; + $tokenindex[$actualindex] = $rule['subpatterns']; + $actualindex += $rule['subpatterns'] + 1; + $patterns[] = '^(' . $rule['pattern'] . ')'; + } + $tokencount = $tokenindex; + $tokenindex = var_export($tokenindex, true); + $tokenindex = explode("\n", $tokenindex); + // indent for prettiness + $tokenindex = implode("\n ", $tokenindex); + $pattern .= implode('|', $patterns); + $pattern .= '/'; + fwrite($this->out, ' + $tokenMap = ' . $tokenindex . '; + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + '); + fwrite($this->out, '$yy_global_pattern = "' . + $pattern . '";' . "\n"); + fwrite($this->out, ' + do { + if (preg_match($yy_global_pattern, substr(' . $this->input . ', ' . + $this->counter . + '), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns + if (!count($yymatches)) { + throw new Exception(\'Error: lexing failed because a rule matched\' . + \'an empty string. Input "\' . substr(' . $this->input . ', + ' . $this->counter . ', 5) . \'... state ' . $statename . '\'); + } + next($yymatches); // skip global match + ' . $this->token . ' = key($yymatches); // token number + if ($tokenMap[' . $this->token . ']) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, ' . $this->token . ' + 1, + $tokenMap[' . $this->token . ']); + } else { + $yysubmatches = array(); + } + ' . $this->value . ' = current($yymatches); // token value + $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches); + if ($r === null) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + // skip this token + continue; + } else {'); + fwrite($this->out, ' $yy_yymore_patterns = array(' . "\n"); + $extra = 0; + for($i = 0; count($patterns); $i++) { + unset($patterns[$i]); + $extra += $tokencount[0]; + array_shift($tokencount); + fwrite($this->out, ' ' . $ruleMap[$i] . ' => array(' . $extra . ', "' . + implode('|', $patterns) . "\"),\n"); + } + fwrite($this->out, ' );' . "\n"); + fwrite($this->out, ' + // yymore is needed + do { + if (!strlen($yy_yymore_patterns[' . $this->token . '][1])) { + throw new Exception(\'cannot do yymore for the last token\'); + } + $yysubmatches = array(); + if (preg_match(\'/\' . $yy_yymore_patterns[' . $this->token . '][1] . \'/\', + substr(' . $this->input . ', ' . $this->counter . '), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns + next($yymatches); // skip global match + ' . $this->token . ' += key($yymatches) + $yy_yymore_patterns[' . $this->token . '][0]; // token number + ' . $this->value . ' = current($yymatches); // token value + ' . $this->line . ' = substr_count(' . $this->value . ', "\n"); + if ($tokenMap[' . $this->token . ']) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, ' . $this->token . ' + 1, + $tokenMap[' . $this->token . ']); + } else { + $yysubmatches = array(); + } + } + $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches); + } while ($r !== null && !is_bool($r)); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + if (' . $this->counter . ' >= strlen(' . $this->input . ')) { + return false; // end of input + } + // skip this token + continue; + } else { + // accept + ' . $this->counter . ' += strlen($this->value); + ' . $this->line . ' += substr_count(' . $this->value . ', "\n"); + return true; + } + } + } else { + throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' . + \': \' . ' . $this->input . '[' . $this->counter . ']); + } + break; + } while (true); +'); + } + + function outputRules($rules, $statename) + { + static $ruleindex = 1; + if (!$statename) { + $statename = $ruleindex; + } + fwrite($this->out, ' + function yylex' . $ruleindex . '() + {'); + if ($this->matchlongest) { + $ruleMap = array(); + foreach ($rules as $i => $rule) { + $ruleMap[$i] = $i; + } + $this->doLongestMatch($rules, $statename, $ruleindex); + } else { + $ruleMap = array(); + $actualindex = 1; + $i = 0; + foreach ($rules as $rule) { + $ruleMap[$i++] = $actualindex; + $actualindex += $rule['subpatterns'] + 1; + } + $this->doFirstMatch($rules, $statename, $ruleindex); + } + fwrite($this->out, ' + } // end function + +'); + if (is_string($statename)) { + fwrite($this->out, ' + const ' . $statename . ' = ' . $ruleindex . '; +'); + } + foreach ($rules as $i => $rule) { + fwrite($this->out, ' function yy_r' . $ruleindex . '_' . $ruleMap[$i] . '($yy_subpatterns) + { +' . $rule['code'] . +' } +'); + } + $ruleindex++; // for next set of rules + } + + function error($msg) + { + echo 'Error on line ' . $this->lex->line . ': ' , $msg; + } + + function _validatePattern($pattern, $update = false) + { + $this->_regexLexer->reset($pattern, $this->lex->line); + $this->_regexParser->reset($this->_patternIndex, $update); + try { + while ($this->_regexLexer->yylex()) { + $this->_regexParser->doParse( + $this->_regexLexer->token, $this->_regexLexer->value); + } + $this->_regexParser->doParse(0, 0); + } catch (PHP_LexerGenerator_Exception $e) { + $this->error($e->getMessage()); + throw new PHP_LexerGenerator_Exception('Invalid pattern "' . $pattern . '"'); + } + return $this->_regexParser->result; + } +} + +start ::= lexfile. + +lexfile ::= declare rules(B). { + fwrite($this->out, ' + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{\'yylex\' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + +'); + foreach (B as $rule) { + $this->outputRules($rule['rules'], $rule['statename']); + if ($rule['code']) { + fwrite($this->out, $rule['code']); + } + } +} +lexfile ::= declare(D) PHPCODE(B) rules(C). { + fwrite($this->out, ' + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{\'yylex\' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + +'); + if (strlen(B)) { + fwrite($this->out, B); + } + foreach (C as $rule) { + $this->outputRules($rule['rules'], $rule['statename']); + if ($rule['code']) { + fwrite($this->out, $rule['code']); + } + } +} +lexfile ::= PHPCODE(B) declare(D) rules(C). { + if (strlen(B)) { + fwrite($this->out, B); + } + fwrite($this->out, ' + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{\'yylex\' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + +'); + foreach (C as $rule) { + $this->outputRules($rule['rules'], $rule['statename']); + if ($rule['code']) { + fwrite($this->out, $rule['code']); + } + } +} +lexfile ::= PHPCODE(A) declare(D) PHPCODE(B) rules(C). { + if (strlen(A)) { + fwrite($this->out, A); + } + fwrite($this->out, ' + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{\'yylex\' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + +'); + if (strlen(B)) { + fwrite($this->out, B); + } + foreach (C as $rule) { + $this->outputRules($rule['rules'], $rule['statename']); + if ($rule['code']) { + fwrite($this->out, $rule['code']); + } + } +} + +declare(A) ::= COMMENTSTART declarations(B) COMMENTEND. { + A = B; + $this->patterns = B['patterns']; + $this->_patternIndex = 1; +} + +declarations(A) ::= processing_instructions(B) pattern_declarations(C). { + $expected = array( + 'counter' => true, + 'input' => true, + 'token' => true, + 'value' => true, + 'line' => true, + ); + foreach (B as $pi) { + if (isset($expected[$pi['pi']])) { + unset($expected[$pi['pi']]); + continue; + } + if (count($expected)) { + throw new Exception('Processing Instructions "' . + implode(', ', array_keys($expected)) . '" must be defined'); + } + } + $expected = array( + 'counter' => true, + 'input' => true, + 'token' => true, + 'value' => true, + 'line' => true, + 'matchlongest' => true, + ); + foreach (B as $pi) { + if (isset($expected[$pi['pi']])) { + $this->{$pi['pi']} = $pi['definition']; + if ($pi['pi'] == 'matchlongest') { + $this->matchlongest = true; + } + continue; + } + $this->error('Unknown processing instruction %' . $pi['pi'] . + ', should be one of "' . implode(', ', array_keys($expected)) . '"'); + } + A = array('patterns' => C, 'pis' => B); + $this->_patternIndex = 1; +} + +processing_instructions(A) ::= PI(B) SUBPATTERN(C). { + A = array(array('pi' => B, 'definition' => C)); +} +processing_instructions(A) ::= PI(B) CODE(C). { + A = array(array('pi' => B, 'definition' => C)); +} +processing_instructions(A) ::= processing_instructions(P) PI(B) SUBPATTERN(C). { + A = P; + A[] = array('pi' => B, 'definition' => C); +} +processing_instructions(A) ::= processing_instructions(P) PI(B) CODE(C). { + A = P; + A[] = array('pi' => B, 'definition' => C); +} + +pattern_declarations(A) ::= PATTERN(B) subpattern(C). { + A = array(B => C); + // reset internal indicator of where we are in a pattern + $this->_patternIndex = 0; +} +pattern_declarations(A) ::= pattern_declarations(B) PATTERN(C) subpattern(D). { + A = B; + if (isset(A[C])) { + throw new Exception('Pattern "' . C . '" is already defined as "' . + A[C] . '", cannot redefine as "' . D->string . '"'); + } + A[C] = D; + // reset internal indicator of where we are in a pattern declaration + $this->_patternIndex = 0; +} + +rules(A) ::= COMMENTSTART rule(B) COMMENTEND. { + A = array(array('rules' => B, 'code' => '', 'statename' => '')); +} +rules(A) ::= COMMENTSTART PI(P) SUBPATTERN(S) rule(B) COMMENTEND. { + if (P != 'statename') { + throw new Exception('Error: only %statename processing instruction ' . + 'is allowed in rule sections'); + } + A = array(array('rules' => B, 'code' => '', 'statename' => S)); +} +rules(A) ::= COMMENTSTART rule(B) COMMENTEND PHPCODE(C). { + A = array(array('rules' => B, 'code' => C, 'statename' => '')); +} +rules(A) ::= COMMENTSTART PI(P) SUBPATTERN(S) rule(B) COMMENTEND PHPCODE(C). { + if (P != 'statename') { + throw new Exception('Error: only %statename processing instruction ' . + 'is allowed in rule sections'); + } + A = array(array('rules' => B, 'code' => C, 'statename' => S)); + $this->_patternIndex = 1; +} +rules(A) ::= reset_rules(R) rule(B) COMMENTEND. { + A = R; + A[] = array('rules' => B, 'code' => '', 'statename' => ''); + $this->_patternIndex = 1; +} +rules(A) ::= reset_rules(R) PI(P) SUBPATTERN(S) rule(B) COMMENTEND. { + if (P != 'statename') { + throw new Exception('Error: only %statename processing instruction ' . + 'is allowed in rule sections'); + } + A = R; + A[] = array('rules' => B, 'code' => '', 'statename' => S); +} +rules(A) ::= reset_rules(R) rule(B) COMMENTEND PHPCODE(C). { + A = R; + A[] = array('rules' => B, 'code' => C, 'statename' => ''); +} +rules(A) ::= reset_rules(R) PI(P) SUBPATTERN(S) rule(B) COMMENTEND PHPCODE(C). { + if (P != 'statename') { + throw new Exception('Error: only %statename processing instruction ' . + 'is allowed in rule sections'); + } + A = R; + A[] = array('rules' => B, 'code' => C, 'statename' => S); +} + +reset_rules(A) ::= rules(R) COMMENTSTART. { + A = R; + $this->_patternIndex = 1; +} + +rule(A) ::= rule_subpattern(B) CODE(C). { + $name = B[1]; + B = B[0]; + B = $this->_validatePattern(B); + $this->_patternIndex += B['subpatterns'] + 1; + if (@preg_match('/' . str_replace('/', '\\/', B['pattern']) . '/', '')) { + $this->error('Rule "' . $name . '" can match the empty string, this will break lexing'); + } + A = array(array('pattern' => str_replace('/', '\\/', B->string), 'code' => C, 'subpatterns' => B['subpatterns'])); +} +rule(A) ::= rule(R) rule_subpattern(B) CODE(C).{ + A = R; + $name = B[1]; + B = B[0]; + B = $this->_validatePattern(B); + $this->_patternIndex += B['subpatterns'] + 1; + if (@preg_match('/' . str_replace('/', '\\/', B['pattern']) . '/', '')) { + $this->error('Rule "' . $name . '" can match the empty string, this will break lexing'); + } + A[] = array('pattern' => str_replace('/', '\\/', B->string), 'code' => C, 'subpatterns' => B['subpatterns']); +} + +rule_subpattern(A) ::= QUOTE(B). { + A = array(preg_quote(B, '/'), B); +} +rule_subpattern(A) ::= SUBPATTERN(B). { + if (!isset($this->patterns[B])) { + $this->error('Undefined pattern "' . B . '" used in rules'); + throw new Exception('Undefined pattern "' . B . '" used in rules'); + } + A = array($this->patterns[B], B); +} +rule_subpattern(A) ::= rule_subpattern(B) QUOTE(C). { + A = array(B[0] . preg_quote(C, '/'), B[1] . ' ' . C); +} +rule_subpattern(A) ::= rule_subpattern(B) SUBPATTERN(C). { + if (!isset($this->patterns[C])) { + $this->error('Undefined pattern "' . C . '" used in rules'); + throw new Exception('Undefined pattern "' . C . '" used in rules'); + } + A = array(B[0] . $this->patterns[C], B[1] . ' ' . C); +} + +subpattern(A) ::= QUOTE(B). { + A = preg_quote(B, '/'); +} +subpattern(A) ::= SUBPATTERN(B). { + // increment internal sub-pattern counter + // adjust back-references in pattern based on previous pattern + $test = $this->_validatePattern(B, true); + $this->_patternIndex += $test['subpatterns']; + A = $test['pattern']; +} +subpattern(A) ::= subpattern(B) QUOTE(C). { + A = B . preg_quote(C, '/'); +} +subpattern(A) ::= subpattern(B) SUBPATTERN(C). { + // increment internal sub-pattern counter + // adjust back-references in pattern based on previous pattern + $test = $this->_validatePattern(C, true); + $this->_patternIndex += $test['subpatterns']; + A = B . $test['pattern']; +} \ No newline at end of file diff --git a/libs/lexer/LexerGenerator/Regex/Lexer.php b/libs/lexer/LexerGenerator/Regex/Lexer.php new file mode 100644 index 00000000..578eec07 --- /dev/null +++ b/libs/lexer/LexerGenerator/Regex/Lexer.php @@ -0,0 +1,938 @@ +input = $data; + $this->N = 0; + } + + function reset($data, $line) + { + $this->input = $data; + $this->N = 0; + // passed in from parent parser + $this->line = $line; + $this->yybegin(self::INITIAL); + } + + + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{'yylex' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + + + + function yylex1() + { + $tokenMap = array ( + 1 => 0, + 2 => 0, + 3 => 0, + 4 => 0, + 5 => 0, + 6 => 0, + 7 => 0, + 8 => 0, + 9 => 0, + 10 => 0, + 11 => 0, + 12 => 0, + 13 => 0, + 14 => 0, + 15 => 0, + 16 => 0, + 17 => 0, + 18 => 0, + 19 => 0, + 20 => 0, + 21 => 0, + 22 => 0, + 23 => 0, + ); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + $yy_global_pattern = "/^(\\\\\\\\)|^([^[\\\\^$.|()?*+{}]+)|^(\\\\[][{}*.^$|?()+])|^(\\[)|^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)/"; + + do { + if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + if (!count($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . + 'an empty string. Input "' . substr($this->input, + $this->N, 5) . '... state INITIAL'); + } + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + if ($tokenMap[$this->token]) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, $this->token + 1, + $tokenMap[$this->token]); + } else { + $yysubmatches = array(); + } + $this->value = current($yymatches); // token value + $r = $this->{'yy_r1_' . $this->token}($yysubmatches); + if ($r === null) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + // skip this token + continue; + } else { $yy_yymore_patterns = array( + 1 => "^([^[\\\\^$.|()?*+{}]+)|^(\\\\[][{}*.^$|?()+])|^(\\[)|^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 2 => "^(\\\\[][{}*.^$|?()+])|^(\\[)|^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 3 => "^(\\[)|^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 4 => "^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 5 => "^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 6 => "^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 7 => "^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 8 => "^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 9 => "^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 10 => "^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 11 => "^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 12 => "^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 13 => "^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 14 => "^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 15 => "^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 16 => "^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 17 => "^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 18 => "^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 19 => "^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 20 => "^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)", + 21 => "^(\\\\p[CLMNPSZ])|^(\\\\)", + 22 => "^(\\\\)", + 23 => "", + ); + + // yymore is needed + do { + if (!strlen($yy_yymore_patterns[$this->token])) { + throw new Exception('cannot do yymore for the last token'); + } + if (preg_match($yy_yymore_patterns[$this->token], + substr($this->input, $this->N), $yymatches)) { + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + $this->value = current($yymatches); // token value + $this->line = substr_count($this->value, "\n"); + } + $r = $this->{'yy_r1_' . $this->token}(); + } while ($r !== null || !$r); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } else { + // accept + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + return true; + } + } + } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->input[$this->N]); + } + break; + } while (true); + + } // end function + + + const INITIAL = 1; + function yy_r1_1($yy_subpatterns) + { + + $this->token = self::ESCAPEDBACKSLASH; + } + function yy_r1_2($yy_subpatterns) + { + + $this->token = self::TEXT; + } + function yy_r1_3($yy_subpatterns) + { + + $this->token = self::CONTROLCHAR; + } + function yy_r1_4($yy_subpatterns) + { + + $this->token = self::OPENCHARCLASS; + $this->yybegin(self::CHARACTERCLASSSTART); + } + function yy_r1_5($yy_subpatterns) + { + + $this->token = self::BAR; + } + function yy_r1_6($yy_subpatterns) + { + + $this->token = self::TEXT; + } + function yy_r1_7($yy_subpatterns) + { + + $this->token = self::COULDBEBACKREF; + } + function yy_r1_8($yy_subpatterns) + { + + $this->token = self::CONTROLCHAR; + } + function yy_r1_9($yy_subpatterns) + { + + $this->token = self::MATCHSTART; + } + function yy_r1_10($yy_subpatterns) + { + + $this->token = self::MATCHSTART; + } + function yy_r1_11($yy_subpatterns) + { + + $this->token = self::CLOSEPAREN; + $this->yybegin(self::INITIAL); + } + function yy_r1_12($yy_subpatterns) + { + + $this->token = self::MATCHEND; + } + function yy_r1_13($yy_subpatterns) + { + + $this->token = self::MULTIPLIER; + } + function yy_r1_14($yy_subpatterns) + { + + $this->token = self::MATCHEND; + } + function yy_r1_15($yy_subpatterns) + { + + $this->token = self::OPENASSERTION; + $this->yybegin(self::ASSERTION); + } + function yy_r1_16($yy_subpatterns) + { + + $this->token = self::OPENPAREN; + } + function yy_r1_17($yy_subpatterns) + { + + $this->token = self::FULLSTOP; + } + function yy_r1_18($yy_subpatterns) + { + + $this->token = self::BACKREFERENCE; + } + function yy_r1_19($yy_subpatterns) + { + + $this->token = self::CONTROLCHAR; + } + function yy_r1_20($yy_subpatterns) + { + + $this->token = self::CONTROLCHAR; + } + function yy_r1_21($yy_subpatterns) + { + + $this->token = self::CONTROLCHAR; + } + function yy_r1_22($yy_subpatterns) + { + + $this->token = self::CONTROLCHAR; + } + function yy_r1_23($yy_subpatterns) + { + + return false; + } + + + function yylex2() + { + $tokenMap = array ( + 1 => 0, + 2 => 0, + 3 => 0, + ); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + $yy_global_pattern = "/^(\\^)|^(\\])|^(.)/"; + + do { + if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + if (!count($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . + 'an empty string. Input "' . substr($this->input, + $this->N, 5) . '... state CHARACTERCLASSSTART'); + } + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + if ($tokenMap[$this->token]) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, $this->token + 1, + $tokenMap[$this->token]); + } else { + $yysubmatches = array(); + } + $this->value = current($yymatches); // token value + $r = $this->{'yy_r2_' . $this->token}($yysubmatches); + if ($r === null) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + // skip this token + continue; + } else { $yy_yymore_patterns = array( + 1 => "^(\\])|^(.)", + 2 => "^(.)", + 3 => "", + ); + + // yymore is needed + do { + if (!strlen($yy_yymore_patterns[$this->token])) { + throw new Exception('cannot do yymore for the last token'); + } + if (preg_match($yy_yymore_patterns[$this->token], + substr($this->input, $this->N), $yymatches)) { + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + $this->value = current($yymatches); // token value + $this->line = substr_count($this->value, "\n"); + } + $r = $this->{'yy_r2_' . $this->token}(); + } while ($r !== null || !$r); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } else { + // accept + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + return true; + } + } + } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->input[$this->N]); + } + break; + } while (true); + + } // end function + + + const CHARACTERCLASSSTART = 2; + function yy_r2_1($yy_subpatterns) + { + + $this->token = self::NEGATE; + } + function yy_r2_2($yy_subpatterns) + { + + $this->yybegin(self::CHARACTERCLASS); + $this->token = self::TEXT; + } + function yy_r2_3($yy_subpatterns) + { + + $this->yybegin(self::CHARACTERCLASS); + return true; + } + + + function yylex3() + { + $tokenMap = array ( + 1 => 0, + 2 => 0, + 3 => 0, + 4 => 0, + 5 => 0, + 6 => 0, + 7 => 0, + 8 => 0, + 9 => 0, + 10 => 0, + 11 => 0, + ); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + $yy_global_pattern = "/^(\\\\\\\\)|^(\\])|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)/"; + + do { + if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + if (!count($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . + 'an empty string. Input "' . substr($this->input, + $this->N, 5) . '... state CHARACTERCLASS'); + } + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + if ($tokenMap[$this->token]) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, $this->token + 1, + $tokenMap[$this->token]); + } else { + $yysubmatches = array(); + } + $this->value = current($yymatches); // token value + $r = $this->{'yy_r3_' . $this->token}($yysubmatches); + if ($r === null) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + // skip this token + continue; + } else { $yy_yymore_patterns = array( + 1 => "^(\\])|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)", + 2 => "^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)", + 3 => "^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)", + 4 => "^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)", + 5 => "^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)", + 6 => "^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)", + 7 => "^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)", + 8 => "^([^\-\\\\])|^(\\\\)|^(.)", + 9 => "^(\\\\)|^(.)", + 10 => "^(.)", + 11 => "", + ); + + // yymore is needed + do { + if (!strlen($yy_yymore_patterns[$this->token])) { + throw new Exception('cannot do yymore for the last token'); + } + if (preg_match($yy_yymore_patterns[$this->token], + substr($this->input, $this->N), $yymatches)) { + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + $this->value = current($yymatches); // token value + $this->line = substr_count($this->value, "\n"); + } + $r = $this->{'yy_r3_' . $this->token}(); + } while ($r !== null || !$r); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } else { + // accept + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + return true; + } + } + } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->input[$this->N]); + } + break; + } while (true); + + } // end function + + + const CHARACTERCLASS = 3; + function yy_r3_1($yy_subpatterns) + { + + $this->token = self::ESCAPEDBACKSLASH; + } + function yy_r3_2($yy_subpatterns) + { + + $this->yybegin(self::INITIAL); + $this->token = self::CLOSECHARCLASS; + } + function yy_r3_3($yy_subpatterns) + { + + $this->token = self::TEXT; + } + function yy_r3_4($yy_subpatterns) + { + + $this->token = self::TEXT; + } + function yy_r3_5($yy_subpatterns) + { + + $this->token = self::COULDBEBACKREF; + } + function yy_r3_6($yy_subpatterns) + { + + $this->token = self::BACKREFERENCE; + } + function yy_r3_7($yy_subpatterns) + { + + $this->token = self::TEXT; + } + function yy_r3_8($yy_subpatterns) + { + + $this->token = self::HYPHEN; + $this->yybegin(self::RANGE); + } + function yy_r3_9($yy_subpatterns) + { + + $this->token = self::TEXT; + } + function yy_r3_10($yy_subpatterns) + { + + return false; // ignore escaping of normal text + } + function yy_r3_11($yy_subpatterns) + { + + $this->token = self::TEXT; + } + + + function yylex4() + { + $tokenMap = array ( + 1 => 0, + 2 => 0, + 3 => 0, + 4 => 0, + 5 => 0, + 6 => 0, + 7 => 0, + ); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + $yy_global_pattern = "/^(\\\\\\\\)|^(\\\\\\])|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)/"; + + do { + if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + if (!count($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . + 'an empty string. Input "' . substr($this->input, + $this->N, 5) . '... state RANGE'); + } + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + if ($tokenMap[$this->token]) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, $this->token + 1, + $tokenMap[$this->token]); + } else { + $yysubmatches = array(); + } + $this->value = current($yymatches); // token value + $r = $this->{'yy_r4_' . $this->token}($yysubmatches); + if ($r === null) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + // skip this token + continue; + } else { $yy_yymore_patterns = array( + 1 => "^(\\\\\\])|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)", + 2 => "^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)", + 3 => "^(\\\\[0-9][0-9])|^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)", + 4 => "^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)", + 5 => "^([^\-\\\\])|^(\\\\)", + 6 => "^(\\\\)", + 7 => "", + ); + + // yymore is needed + do { + if (!strlen($yy_yymore_patterns[$this->token])) { + throw new Exception('cannot do yymore for the last token'); + } + if (preg_match($yy_yymore_patterns[$this->token], + substr($this->input, $this->N), $yymatches)) { + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + $this->value = current($yymatches); // token value + $this->line = substr_count($this->value, "\n"); + } + $r = $this->{'yy_r4_' . $this->token}(); + } while ($r !== null || !$r); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } else { + // accept + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + return true; + } + } + } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->input[$this->N]); + } + break; + } while (true); + + } // end function + + + const RANGE = 4; + function yy_r4_1($yy_subpatterns) + { + + $this->token = self::ESCAPEDBACKSLASH; + } + function yy_r4_2($yy_subpatterns) + { + + $this->token = self::TEXT; + $this->yybegin(self::CHARACTERCLASS); + } + function yy_r4_3($yy_subpatterns) + { + + $this->token = self::TEXT; + $this->yybegin(self::CHARACTERCLASS); + } + function yy_r4_4($yy_subpatterns) + { + + $this->token = self::COULDBEBACKREF; + } + function yy_r4_5($yy_subpatterns) + { + + $this->token = self::BACKREFERENCE; + } + function yy_r4_6($yy_subpatterns) + { + + $this->token = self::TEXT; + $this->yybegin(self::CHARACTERCLASS); + } + function yy_r4_7($yy_subpatterns) + { + + return false; // ignore escaping of normal text + } + + + function yylex5() + { + $tokenMap = array ( + 1 => 0, + 2 => 0, + 3 => 0, + 4 => 0, + 5 => 0, + 6 => 0, + 7 => 0, + 8 => 0, + 9 => 0, + 10 => 0, + 11 => 0, + 12 => 0, + 13 => 0, + ); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + $yy_global_pattern = "/^([imsxUX]+-[imsxUX]+|[imsxUX]+|-[imsxUX]+)|^(:)|^(\\))|^(P<[^>]+>)|^(<=)|^()|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)/"; + + do { + if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + if (!count($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . + 'an empty string. Input "' . substr($this->input, + $this->N, 5) . '... state ASSERTION'); + } + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + if ($tokenMap[$this->token]) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, $this->token + 1, + $tokenMap[$this->token]); + } else { + $yysubmatches = array(); + } + $this->value = current($yymatches); // token value + $r = $this->{'yy_r5_' . $this->token}($yysubmatches); + if ($r === null) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + if ($this->N >= strlen($this->input)) { + return false; // end of input + } + // skip this token + continue; + } else { $yy_yymore_patterns = array( + 1 => "^(:)|^(\\))|^(P<[^>]+>)|^(<=)|^()|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)", + 2 => "^(\\))|^(P<[^>]+>)|^(<=)|^()|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)", + 3 => "^(P<[^>]+>)|^(<=)|^()|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)", + 4 => "^(<=)|^()|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)", + 5 => "^()|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)", + 6 => "^(=)|^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)", + 7 => "^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)", + 8 => "^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)", + 9 => "^(\\(\\?)|^(#[^)]+)|^(R)|^(.)", + 10 => "^(#[^)]+)|^(R)|^(.)", + 11 => "^(R)|^(.)", + 12 => "^(.)", + 13 => "", + ); + + // yymore is needed + do { + if (!strlen($yy_yymore_patterns[$this->token])) { + throw new Exception('cannot do yymore for the last token'); + } + if (preg_match($yy_yymore_patterns[$this->token], + substr($this->input, $this->N), $yymatches)) { + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + $this->value = current($yymatches); // token value + $this->line = substr_count($this->value, "\n"); + } + $r = $this->{'yy_r5_' . $this->token}(); + } while ($r !== null || !$r); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } else { + // accept + $this->N += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + return true; + } + } + } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->input[$this->N]); + } + break; + } while (true); + + } // end function + + + const ASSERTION = 5; + function yy_r5_1($yy_subpatterns) + { + + $this->token = self::INTERNALOPTIONS; + } + function yy_r5_2($yy_subpatterns) + { + + $this->token = self::COLON; + $this->yybegin(self::INITIAL); + } + function yy_r5_3($yy_subpatterns) + { + + $this->token = self::CLOSEPAREN; + $this->yybegin(self::INITIAL); + } + function yy_r5_4($yy_subpatterns) + { + + $this->token = self::PATTERNNAME; + $this->yybegin(self::INITIAL); + } + function yy_r5_5($yy_subpatterns) + { + + $this->token = self::POSITIVELOOKBEHIND; + $this->yybegin(self::INITIAL); + } + function yy_r5_6($yy_subpatterns) + { + + $this->token = self::NEGATIVELOOKBEHIND; + $this->yybegin(self::INITIAL); + } + function yy_r5_7($yy_subpatterns) + { + + $this->token = self::POSITIVELOOKAHEAD; + $this->yybegin(self::INITIAL); + } + function yy_r5_8($yy_subpatterns) + { + + $this->token = self::NEGATIVELOOKAHEAD; + $this->yybegin(self::INITIAL); + } + function yy_r5_9($yy_subpatterns) + { + + $this->token = self::ONCEONLY; + $this->yybegin(self::INITIAL); + } + function yy_r5_10($yy_subpatterns) + { + + $this->token = self::OPENASSERTION; + } + function yy_r5_11($yy_subpatterns) + { + + $this->token = self::COMMENT; + $this->yybegin(self::INITIAL); + } + function yy_r5_12($yy_subpatterns) + { + + $this->token = self::RECUR; + } + function yy_r5_13($yy_subpatterns) + { + + $this->yybegin(self::INITIAL); + return true; + } + +} diff --git a/libs/lexer/LexerGenerator/Regex/Parser.php b/libs/lexer/LexerGenerator/Regex/Parser.php new file mode 100644 index 00000000..20e90ea0 --- /dev/null +++ b/libs/lexer/LexerGenerator/Regex/Parser.php @@ -0,0 +1,1933 @@ +string = $s->string; + $this->metadata = $s->metadata; + } else { + $this->string = (string) $s; + if ($m instanceof PHP_LexerGenerator_Regex_yyToken) { + $this->metadata = $m->metadata; + } elseif (is_array($m)) { + $this->metadata = $m; + } + } + } + + function __toString() + { + return $this->_string; + } + + function offsetExists($offset) + { + return isset($this->metadata[$offset]); + } + + function offsetGet($offset) + { + return $this->metadata[$offset]; + } + + function offsetSet($offset, $value) + { + if ($offset === null) { + if (isset($value[0])) { + $x = ($value instanceof PHP_LexerGenerator_Regex_yyToken) ? + $value->metadata : $value; + $this->metadata = array_merge($this->metadata, $x); + return; + } + $offset = count($this->metadata); + } + if ($value === null) { + return; + } + if ($value instanceof PHP_LexerGenerator_Regex_yyToken) { + if ($value->metadata) { + $this->metadata[$offset] = $value->metadata; + } + } elseif ($value) { + $this->metadata[$offset] = $value; + } + } + + function offsetUnset($offset) + { + unset($this->metadata[$offset]); + } +} + +/** The following structure represents a single element of the + * parser's stack. Information stored includes: + * + * + The state number for the parser at this level of the stack. + * + * + The value of the token stored at this level of the stack. + * (In other words, the "major" token.) + * + * + The semantic value stored at this level of the stack. This is + * the information used by the action routines in the grammar. + * It is sometimes called the "minor" token. + */ +class PHP_LexerGenerator_Regex_yyStackEntry +{ + public $stateno; /* The state-number */ + public $major; /* The major token value. This is the code + ** number for the token at this stack level */ + public $minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; + +// code external to the class is included here +#line 2 "Parser.y" + +require_once './LexerGenerator/Exception.php'; +#line 102 "Parser.php" + +// declare_class is output here +#line 5 "Parser.y" +class PHP_LexerGenerator_Regex_Parser#line 107 "Parser.php" +{ +/* First off, code is included which follows the "include_class" declaration +** in the input file. */ +#line 21 "Parser.y" + + private $_lex; + private $_subpatterns; + private $_updatePattern; + private $_patternIndex; + public $result; + function __construct($lex) + { + $this->result = new PHP_LexerGenerator_ParseryyToken(''); + $this->_lex = $lex; + $this->_subpatterns = 0; + $this->_patternIndex = 1; + } + + function reset($patternIndex, $updatePattern = false) + { + $this->_updatePattern = $updatePattern; + $this->_patternIndex = $patternIndex; + $this->_subpatterns = 0; + $this->result = new PHP_LexerGenerator_ParseryyToken(''); + } +#line 134 "Parser.php" + +/* Next is all token values, as class constants +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ + const OPENPAREN = 1; + const OPENASSERTION = 2; + const BAR = 3; + const MULTIPLIER = 4; + const MATCHSTART = 5; + const MATCHEND = 6; + const OPENCHARCLASS = 7; + const CLOSECHARCLASS = 8; + const NEGATE = 9; + const TEXT = 10; + const ESCAPEDBACKSLASH = 11; + const HYPHEN = 12; + const BACKREFERENCE = 13; + const COULDBEBACKREF = 14; + const CONTROLCHAR = 15; + const FULLSTOP = 16; + const INTERNALOPTIONS = 17; + const CLOSEPAREN = 18; + const COLON = 19; + const POSITIVELOOKAHEAD = 20; + const NEGATIVELOOKAHEAD = 21; + const POSITIVELOOKBEHIND = 22; + const NEGATIVELOOKBEHIND = 23; + const PATTERNNAME = 24; + const ONCEONLY = 25; + const COMMENT = 26; + const RECUR = 27; + const YY_NO_ACTION = 230; + const YY_ACCEPT_ACTION = 229; + const YY_ERROR_ACTION = 228; + +/* Next are that tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N < self::YYNSTATE Shift N. That is, +** push the lookahead +** token onto the stack +** and goto state N. +** +** self::YYNSTATE <= N < self::YYNSTATE+self::YYNRULE Reduce by rule N-YYNSTATE. +** +** N == self::YYNSTATE+self::YYNRULE A syntax error has occurred. +** +** N == self::YYNSTATE+self::YYNRULE+1 The parser accepts its +** input. (and concludes parsing) +** +** N == self::YYNSTATE+self::YYNRULE+2 No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large static array $yy_action. +** Given state S and lookahead X, the action is computed as +** +** self::$yy_action[self::$yy_shift_ofst[S] + X ] +** +** If the index value self::$yy_shift_ofst[S]+X is out of range or if the value +** self::$yy_lookahead[self::$yy_shift_ofst[S]+X] is not equal to X or if +** self::$yy_shift_ofst[S] is equal to self::YY_SHIFT_USE_DFLT, it means that +** the action is not in the table and that self::$yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the static $yy_reduce_ofst array is used in place of +** the static $yy_shift_ofst array and self::YY_REDUCE_USE_DFLT is used in place of +** self::YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** self::$yy_action A single table containing all actions. +** self::$yy_lookahead A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** self::$yy_shift_ofst For each state, the offset into self::$yy_action for +** shifting terminals. +** self::$yy_reduce_ofst For each state, the offset into self::$yy_action for +** shifting non-terminals after a reduce. +** self::$yy_default Default action for each state. +*/ + const YY_SZ_ACTTAB = 354; +static public $yy_action = array( + /* 0 */ 229, 45, 15, 23, 104, 106, 107, 109, 108, 118, + /* 10 */ 119, 129, 128, 130, 36, 15, 23, 104, 106, 107, + /* 20 */ 109, 108, 118, 119, 129, 128, 130, 39, 15, 23, + /* 30 */ 104, 106, 107, 109, 108, 118, 119, 129, 128, 130, + /* 40 */ 25, 15, 23, 104, 106, 107, 109, 108, 118, 119, + /* 50 */ 129, 128, 130, 32, 15, 23, 104, 106, 107, 109, + /* 60 */ 108, 118, 119, 129, 128, 130, 28, 15, 23, 104, + /* 70 */ 106, 107, 109, 108, 118, 119, 129, 128, 130, 35, + /* 80 */ 15, 23, 104, 106, 107, 109, 108, 118, 119, 129, + /* 90 */ 128, 130, 92, 15, 23, 104, 106, 107, 109, 108, + /* 100 */ 118, 119, 129, 128, 130, 38, 15, 23, 104, 106, + /* 110 */ 107, 109, 108, 118, 119, 129, 128, 130, 40, 15, + /* 120 */ 23, 104, 106, 107, 109, 108, 118, 119, 129, 128, + /* 130 */ 130, 33, 15, 23, 104, 106, 107, 109, 108, 118, + /* 140 */ 119, 129, 128, 130, 30, 15, 23, 104, 106, 107, + /* 150 */ 109, 108, 118, 119, 129, 128, 130, 37, 15, 23, + /* 160 */ 104, 106, 107, 109, 108, 118, 119, 129, 128, 130, + /* 170 */ 34, 15, 23, 104, 106, 107, 109, 108, 118, 119, + /* 180 */ 129, 128, 130, 16, 23, 104, 106, 107, 109, 108, + /* 190 */ 118, 119, 129, 128, 130, 54, 24, 22, 72, 76, + /* 200 */ 85, 84, 82, 81, 80, 97, 134, 125, 93, 12, + /* 210 */ 12, 26, 83, 2, 5, 1, 11, 4, 10, 13, + /* 220 */ 49, 50, 9, 17, 46, 98, 14, 12, 18, 113, + /* 230 */ 124, 52, 43, 79, 44, 57, 42, 41, 9, 17, + /* 240 */ 127, 12, 53, 91, 18, 126, 12, 52, 43, 120, + /* 250 */ 44, 57, 42, 41, 9, 17, 47, 12, 31, 117, + /* 260 */ 18, 88, 99, 52, 43, 75, 44, 57, 42, 41, + /* 270 */ 9, 17, 51, 19, 67, 69, 18, 101, 87, 52, + /* 280 */ 43, 12, 44, 57, 42, 41, 132, 64, 63, 103, + /* 290 */ 62, 58, 66, 65, 59, 12, 60, 68, 90, 111, + /* 300 */ 116, 122, 61, 100, 60, 68, 12, 111, 116, 122, + /* 310 */ 71, 5, 1, 11, 4, 67, 69, 12, 101, 87, + /* 320 */ 12, 102, 12, 12, 112, 6, 105, 131, 78, 7, + /* 330 */ 8, 95, 77, 74, 70, 56, 123, 48, 133, 73, + /* 340 */ 27, 114, 86, 55, 115, 89, 110, 121, 3, 94, + /* 350 */ 21, 29, 96, 20, + ); + static public $yy_lookahead = array( + /* 0 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + /* 10 */ 39, 40, 41, 42, 30, 31, 32, 33, 34, 35, + /* 20 */ 36, 37, 38, 39, 40, 41, 42, 30, 31, 32, + /* 30 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + /* 40 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + /* 50 */ 40, 41, 42, 30, 31, 32, 33, 34, 35, 36, + /* 60 */ 37, 38, 39, 40, 41, 42, 30, 31, 32, 33, + /* 70 */ 34, 35, 36, 37, 38, 39, 40, 41, 42, 30, + /* 80 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + /* 90 */ 41, 42, 30, 31, 32, 33, 34, 35, 36, 37, + /* 100 */ 38, 39, 40, 41, 42, 30, 31, 32, 33, 34, + /* 110 */ 35, 36, 37, 38, 39, 40, 41, 42, 30, 31, + /* 120 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + /* 130 */ 42, 30, 31, 32, 33, 34, 35, 36, 37, 38, + /* 140 */ 39, 40, 41, 42, 30, 31, 32, 33, 34, 35, + /* 150 */ 36, 37, 38, 39, 40, 41, 42, 30, 31, 32, + /* 160 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + /* 170 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + /* 180 */ 40, 41, 42, 31, 32, 33, 34, 35, 36, 37, + /* 190 */ 38, 39, 40, 41, 42, 1, 2, 32, 33, 34, + /* 200 */ 35, 36, 37, 38, 39, 40, 41, 42, 18, 3, + /* 210 */ 3, 17, 10, 19, 20, 21, 22, 23, 24, 25, + /* 220 */ 26, 27, 1, 2, 18, 18, 5, 3, 7, 10, + /* 230 */ 11, 10, 11, 4, 13, 14, 15, 16, 1, 2, + /* 240 */ 10, 3, 18, 6, 7, 15, 3, 10, 11, 4, + /* 250 */ 13, 14, 15, 16, 1, 2, 18, 3, 12, 6, + /* 260 */ 7, 18, 4, 10, 11, 4, 13, 14, 15, 16, + /* 270 */ 1, 2, 18, 9, 10, 11, 7, 13, 14, 10, + /* 280 */ 11, 3, 13, 14, 15, 16, 4, 10, 11, 4, + /* 290 */ 13, 14, 15, 16, 8, 3, 10, 11, 18, 13, + /* 300 */ 14, 15, 8, 4, 10, 11, 3, 13, 14, 15, + /* 310 */ 18, 20, 21, 22, 23, 10, 11, 3, 13, 14, + /* 320 */ 3, 18, 3, 3, 18, 19, 10, 11, 4, 36, + /* 330 */ 37, 4, 18, 4, 12, 18, 4, 18, 18, 4, + /* 340 */ 12, 4, 4, 10, 4, 4, 4, 4, 18, 4, + /* 350 */ 43, 12, 4, 43, +); + const YY_SHIFT_USE_DFLT = -1; + const YY_SHIFT_MAX = 70; + static public $yy_shift_ofst = array( + /* 0 */ 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + /* 10 */ 221, 221, 221, 221, 269, 253, 237, 194, 264, 305, + /* 20 */ 286, 294, 277, 277, 291, 320, 306, 316, 317, 219, + /* 30 */ 224, 230, 238, 206, 207, 319, 243, 314, 303, 254, + /* 40 */ 292, 345, 348, 261, 282, 278, 285, 324, 327, 280, + /* 50 */ 190, 229, 245, 343, 333, 330, 342, 337, 329, 332, + /* 60 */ 328, 340, 335, 338, 341, 299, 258, 339, 246, 322, + /* 70 */ 202, +); + const YY_REDUCE_USE_DFLT = -30; + const YY_REDUCE_MAX = 19; + static public $yy_reduce_ofst = array( + /* 0 */ -29, 127, 114, 101, 140, 88, 10, -3, 23, 36, + /* 10 */ 49, 75, 62, -16, 152, 165, 165, 293, 310, 307, +); + static public $yyExpectedTokens = array( + /* 0 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 1 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 2 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 3 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 4 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 5 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 6 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 7 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 8 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 9 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 10 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 11 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 12 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 13 */ array(1, 2, 5, 7, 10, 11, 13, 14, 15, 16, ), + /* 14 */ array(1, 2, 7, 10, 11, 13, 14, 15, 16, ), + /* 15 */ array(1, 2, 6, 7, 10, 11, 13, 14, 15, 16, ), + /* 16 */ array(1, 2, 6, 7, 10, 11, 13, 14, 15, 16, ), + /* 17 */ array(1, 2, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, ), + /* 18 */ array(9, 10, 11, 13, 14, ), + /* 19 */ array(10, 11, 13, 14, ), + /* 20 */ array(8, 10, 11, 13, 14, 15, ), + /* 21 */ array(8, 10, 11, 13, 14, 15, ), + /* 22 */ array(10, 11, 13, 14, 15, 16, ), + /* 23 */ array(10, 11, 13, 14, 15, 16, ), + /* 24 */ array(20, 21, 22, 23, ), + /* 25 */ array(3, 18, ), + /* 26 */ array(18, 19, ), + /* 27 */ array(10, 11, ), + /* 28 */ array(3, 18, ), + /* 29 */ array(10, 11, ), + /* 30 */ array(3, 18, ), + /* 31 */ array(10, 15, ), + /* 32 */ array(3, 18, ), + /* 33 */ array(3, 18, ), + /* 34 */ array(3, 18, ), + /* 35 */ array(3, 18, ), + /* 36 */ array(3, 18, ), + /* 37 */ array(3, 18, ), + /* 38 */ array(3, 18, ), + /* 39 */ array(3, 18, ), + /* 40 */ array(3, 18, ), + /* 41 */ array(4, ), + /* 42 */ array(4, ), + /* 43 */ array(4, ), + /* 44 */ array(4, ), + /* 45 */ array(3, ), + /* 46 */ array(4, ), + /* 47 */ array(4, ), + /* 48 */ array(4, ), + /* 49 */ array(18, ), + /* 50 */ array(18, ), + /* 51 */ array(4, ), + /* 52 */ array(4, ), + /* 53 */ array(4, ), + /* 54 */ array(10, ), + /* 55 */ array(18, ), + /* 56 */ array(4, ), + /* 57 */ array(4, ), + /* 58 */ array(4, ), + /* 59 */ array(4, ), + /* 60 */ array(12, ), + /* 61 */ array(4, ), + /* 62 */ array(4, ), + /* 63 */ array(4, ), + /* 64 */ array(4, ), + /* 65 */ array(4, ), + /* 66 */ array(4, ), + /* 67 */ array(12, ), + /* 68 */ array(12, ), + /* 69 */ array(12, ), + /* 70 */ array(10, ), + /* 71 */ array(), + /* 72 */ array(), + /* 73 */ array(), + /* 74 */ array(), + /* 75 */ array(), + /* 76 */ array(), + /* 77 */ array(), + /* 78 */ array(), + /* 79 */ array(), + /* 80 */ array(), + /* 81 */ array(), + /* 82 */ array(), + /* 83 */ array(), + /* 84 */ array(), + /* 85 */ array(), + /* 86 */ array(), + /* 87 */ array(), + /* 88 */ array(), + /* 89 */ array(), + /* 90 */ array(), + /* 91 */ array(), + /* 92 */ array(), + /* 93 */ array(), + /* 94 */ array(), + /* 95 */ array(), + /* 96 */ array(), + /* 97 */ array(), + /* 98 */ array(), + /* 99 */ array(), + /* 100 */ array(), + /* 101 */ array(), + /* 102 */ array(), + /* 103 */ array(), + /* 104 */ array(), + /* 105 */ array(), + /* 106 */ array(), + /* 107 */ array(), + /* 108 */ array(), + /* 109 */ array(), + /* 110 */ array(), + /* 111 */ array(), + /* 112 */ array(), + /* 113 */ array(), + /* 114 */ array(), + /* 115 */ array(), + /* 116 */ array(), + /* 117 */ array(), + /* 118 */ array(), + /* 119 */ array(), + /* 120 */ array(), + /* 121 */ array(), + /* 122 */ array(), + /* 123 */ array(), + /* 124 */ array(), + /* 125 */ array(), + /* 126 */ array(), + /* 127 */ array(), + /* 128 */ array(), + /* 129 */ array(), + /* 130 */ array(), + /* 131 */ array(), + /* 132 */ array(), + /* 133 */ array(), + /* 134 */ array(), +); + static public $yy_default = array( + /* 0 */ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, + /* 10 */ 228, 228, 228, 228, 228, 139, 137, 228, 228, 228, + /* 20 */ 228, 228, 152, 141, 228, 228, 228, 228, 228, 228, + /* 30 */ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, + /* 40 */ 228, 185, 187, 189, 191, 135, 212, 215, 221, 228, + /* 50 */ 228, 213, 183, 209, 228, 228, 223, 193, 205, 163, + /* 60 */ 176, 164, 203, 201, 195, 197, 199, 167, 175, 168, + /* 70 */ 228, 217, 153, 204, 206, 190, 154, 218, 216, 214, + /* 80 */ 159, 158, 157, 169, 156, 155, 202, 173, 225, 196, + /* 90 */ 226, 136, 140, 227, 186, 222, 188, 160, 220, 200, + /* 100 */ 198, 172, 219, 211, 142, 180, 143, 144, 146, 145, + /* 110 */ 224, 181, 207, 170, 194, 166, 182, 138, 147, 148, + /* 120 */ 184, 210, 174, 165, 171, 162, 177, 178, 150, 149, + /* 130 */ 151, 179, 192, 208, 161, +); +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** self::YYNOCODE is a number which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** self::YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** self::YYSTACKDEPTH is the maximum depth of the parser's stack. +** self::YYNSTATE the combined number of states. +** self::YYNRULE the number of rules in the grammar +** self::YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ + const YYNOCODE = 45; + const YYSTACKDEPTH = 100; + const YYNSTATE = 135; + const YYNRULE = 93; + const YYERRORSYMBOL = 28; + const YYERRSYMDT = 'yy0'; + const YYFALLBACK = 0; + /** The next table maps tokens into fallback tokens. If a construct + * like the following: + * + * %fallback ID X Y Z. + * + * appears in the grammer, then ID becomes a fallback token for X, Y, + * and Z. Whenever one of the tokens X, Y, or Z is input to the parser + * but it does not parse, the type of the token is changed to ID and + * the parse is retried before an error is thrown. + */ + static public $yyFallback = array( + ); + /** + * Turn parser tracing on by giving a stream to which to write the trace + * and a prompt to preface each trace message. Tracing is turned off + * by making either argument NULL + * + * Inputs: + * + * - A stream resource to which trace output should be written. + * If NULL, then tracing is turned off. + * - A prefix string written at the beginning of every + * line of trace output. If NULL, then tracing is + * turned off. + * + * Outputs: + * + * - None. + * @param resource + * @param string + */ + static function Trace($TraceFILE, $zTracePrompt) + { + if (!$TraceFILE) { + $zTracePrompt = 0; + } elseif (!$zTracePrompt) { + $TraceFILE = 0; + } + self::$yyTraceFILE = $TraceFILE; + self::$yyTracePrompt = $zTracePrompt; + } + + /** + * Output debug information to output (php://output stream) + */ + static function PrintTrace() + { + self::$yyTraceFILE = fopen('php://output', 'w'); + self::$yyTracePrompt = ''; + } + + /** + * @var resource|0 + */ + static public $yyTraceFILE; + /** + * String to prepend to debug output + * @var string|0 + */ + static public $yyTracePrompt; + /** + * @var int + */ + public $yyidx; /* Index of top element in stack */ + /** + * @var int + */ + public $yyerrcnt; /* Shifts left before out of the error */ + /** + * @var array + */ + public $yystack = array(); /* The parser's stack */ + + /** + * For tracing shifts, the names of all terminals and nonterminals + * are required. The following table supplies these names + * @var array + */ + static public $yyTokenName = array( + '$', 'OPENPAREN', 'OPENASSERTION', 'BAR', + 'MULTIPLIER', 'MATCHSTART', 'MATCHEND', 'OPENCHARCLASS', + 'CLOSECHARCLASS', 'NEGATE', 'TEXT', 'ESCAPEDBACKSLASH', + 'HYPHEN', 'BACKREFERENCE', 'COULDBEBACKREF', 'CONTROLCHAR', + 'FULLSTOP', 'INTERNALOPTIONS', 'CLOSEPAREN', 'COLON', + 'POSITIVELOOKAHEAD', 'NEGATIVELOOKAHEAD', 'POSITIVELOOKBEHIND', 'NEGATIVELOOKBEHIND', + 'PATTERNNAME', 'ONCEONLY', 'COMMENT', 'RECUR', + 'error', 'start', 'pattern', 'basic_pattern', + 'basic_text', 'character_class', 'assertion', 'grouping', + 'lookahead', 'lookbehind', 'subpattern', 'onceonly', + 'comment', 'recur', 'conditional', 'character_class_contents', + ); + + /** + * For tracing reduce actions, the names of all rules are required. + * @var array + */ + static public $yyRuleName = array( + /* 0 */ "start ::= pattern", + /* 1 */ "pattern ::= MATCHSTART basic_pattern MATCHEND", + /* 2 */ "pattern ::= MATCHSTART basic_pattern", + /* 3 */ "pattern ::= basic_pattern MATCHEND", + /* 4 */ "pattern ::= basic_pattern", + /* 5 */ "pattern ::= pattern BAR pattern", + /* 6 */ "basic_pattern ::= basic_text", + /* 7 */ "basic_pattern ::= character_class", + /* 8 */ "basic_pattern ::= assertion", + /* 9 */ "basic_pattern ::= grouping", + /* 10 */ "basic_pattern ::= lookahead", + /* 11 */ "basic_pattern ::= lookbehind", + /* 12 */ "basic_pattern ::= subpattern", + /* 13 */ "basic_pattern ::= onceonly", + /* 14 */ "basic_pattern ::= comment", + /* 15 */ "basic_pattern ::= recur", + /* 16 */ "basic_pattern ::= conditional", + /* 17 */ "basic_pattern ::= basic_pattern basic_text", + /* 18 */ "basic_pattern ::= basic_pattern character_class", + /* 19 */ "basic_pattern ::= basic_pattern assertion", + /* 20 */ "basic_pattern ::= basic_pattern grouping", + /* 21 */ "basic_pattern ::= basic_pattern lookahead", + /* 22 */ "basic_pattern ::= basic_pattern lookbehind", + /* 23 */ "basic_pattern ::= basic_pattern subpattern", + /* 24 */ "basic_pattern ::= basic_pattern onceonly", + /* 25 */ "basic_pattern ::= basic_pattern comment", + /* 26 */ "basic_pattern ::= basic_pattern recur", + /* 27 */ "basic_pattern ::= basic_pattern conditional", + /* 28 */ "character_class ::= OPENCHARCLASS character_class_contents CLOSECHARCLASS", + /* 29 */ "character_class ::= OPENCHARCLASS NEGATE character_class_contents CLOSECHARCLASS", + /* 30 */ "character_class ::= OPENCHARCLASS character_class_contents CLOSECHARCLASS MULTIPLIER", + /* 31 */ "character_class ::= OPENCHARCLASS NEGATE character_class_contents CLOSECHARCLASS MULTIPLIER", + /* 32 */ "character_class_contents ::= TEXT", + /* 33 */ "character_class_contents ::= ESCAPEDBACKSLASH", + /* 34 */ "character_class_contents ::= ESCAPEDBACKSLASH HYPHEN TEXT", + /* 35 */ "character_class_contents ::= TEXT HYPHEN TEXT", + /* 36 */ "character_class_contents ::= TEXT HYPHEN ESCAPEDBACKSLASH", + /* 37 */ "character_class_contents ::= BACKREFERENCE", + /* 38 */ "character_class_contents ::= COULDBEBACKREF", + /* 39 */ "character_class_contents ::= character_class_contents CONTROLCHAR", + /* 40 */ "character_class_contents ::= character_class_contents ESCAPEDBACKSLASH", + /* 41 */ "character_class_contents ::= character_class_contents TEXT", + /* 42 */ "character_class_contents ::= character_class_contents ESCAPEDBACKSLASH HYPHEN CONTROLCHAR", + /* 43 */ "character_class_contents ::= character_class_contents ESCAPEDBACKSLASH HYPHEN TEXT", + /* 44 */ "character_class_contents ::= character_class_contents TEXT HYPHEN ESCAPEDBACKSLASH", + /* 45 */ "character_class_contents ::= character_class_contents TEXT HYPHEN TEXT", + /* 46 */ "character_class_contents ::= character_class_contents BACKREFERENCE", + /* 47 */ "character_class_contents ::= character_class_contents COULDBEBACKREF", + /* 48 */ "basic_text ::= TEXT", + /* 49 */ "basic_text ::= TEXT MULTIPLIER", + /* 50 */ "basic_text ::= FULLSTOP", + /* 51 */ "basic_text ::= FULLSTOP MULTIPLIER", + /* 52 */ "basic_text ::= CONTROLCHAR", + /* 53 */ "basic_text ::= CONTROLCHAR MULTIPLIER", + /* 54 */ "basic_text ::= ESCAPEDBACKSLASH", + /* 55 */ "basic_text ::= ESCAPEDBACKSLASH MULTIPLIER", + /* 56 */ "basic_text ::= BACKREFERENCE", + /* 57 */ "basic_text ::= BACKREFERENCE MULTIPLIER", + /* 58 */ "basic_text ::= COULDBEBACKREF", + /* 59 */ "basic_text ::= COULDBEBACKREF MULTIPLIER", + /* 60 */ "basic_text ::= basic_text TEXT", + /* 61 */ "basic_text ::= basic_text TEXT MULTIPLIER", + /* 62 */ "basic_text ::= basic_text FULLSTOP", + /* 63 */ "basic_text ::= basic_text FULLSTOP MULTIPLIER", + /* 64 */ "basic_text ::= basic_text CONTROLCHAR", + /* 65 */ "basic_text ::= basic_text CONTROLCHAR MULTIPLIER", + /* 66 */ "basic_text ::= basic_text ESCAPEDBACKSLASH", + /* 67 */ "basic_text ::= basic_text ESCAPEDBACKSLASH MULTIPLIER", + /* 68 */ "basic_text ::= basic_text BACKREFERENCE", + /* 69 */ "basic_text ::= basic_text BACKREFERENCE MULTIPLIER", + /* 70 */ "basic_text ::= basic_text COULDBEBACKREF", + /* 71 */ "basic_text ::= basic_text COULDBEBACKREF MULTIPLIER", + /* 72 */ "assertion ::= OPENASSERTION INTERNALOPTIONS CLOSEPAREN", + /* 73 */ "assertion ::= OPENASSERTION INTERNALOPTIONS COLON pattern CLOSEPAREN", + /* 74 */ "grouping ::= OPENASSERTION COLON pattern CLOSEPAREN", + /* 75 */ "grouping ::= OPENASSERTION COLON pattern CLOSEPAREN MULTIPLIER", + /* 76 */ "conditional ::= OPENASSERTION OPENPAREN TEXT CLOSEPAREN pattern CLOSEPAREN MULTIPLIER", + /* 77 */ "conditional ::= OPENASSERTION OPENPAREN TEXT CLOSEPAREN pattern CLOSEPAREN", + /* 78 */ "conditional ::= OPENASSERTION lookahead pattern CLOSEPAREN", + /* 79 */ "conditional ::= OPENASSERTION lookahead pattern CLOSEPAREN MULTIPLIER", + /* 80 */ "conditional ::= OPENASSERTION lookbehind pattern CLOSEPAREN", + /* 81 */ "conditional ::= OPENASSERTION lookbehind pattern CLOSEPAREN MULTIPLIER", + /* 82 */ "lookahead ::= OPENASSERTION POSITIVELOOKAHEAD pattern CLOSEPAREN", + /* 83 */ "lookahead ::= OPENASSERTION NEGATIVELOOKAHEAD pattern CLOSEPAREN", + /* 84 */ "lookbehind ::= OPENASSERTION POSITIVELOOKBEHIND pattern CLOSEPAREN", + /* 85 */ "lookbehind ::= OPENASSERTION NEGATIVELOOKBEHIND pattern CLOSEPAREN", + /* 86 */ "subpattern ::= OPENASSERTION PATTERNNAME pattern CLOSEPAREN", + /* 87 */ "subpattern ::= OPENASSERTION PATTERNNAME pattern CLOSEPAREN MULTIPLIER", + /* 88 */ "subpattern ::= OPENPAREN pattern CLOSEPAREN", + /* 89 */ "subpattern ::= OPENPAREN pattern CLOSEPAREN MULTIPLIER", + /* 90 */ "onceonly ::= OPENASSERTION ONCEONLY pattern CLOSEPAREN", + /* 91 */ "comment ::= OPENASSERTION COMMENT CLOSEPAREN", + /* 92 */ "recur ::= OPENASSERTION RECUR CLOSEPAREN", + ); + + /** + * This function returns the symbolic name associated with a token + * value. + * @param int + * @return string + */ + function tokenName($tokenType) + { + if ($tokenType === 0) { + return 'End of Input'; + } + if ($tokenType > 0 && $tokenType < count(self::$yyTokenName)) { + return self::$yyTokenName[$tokenType]; + } else { + return "Unknown"; + } + } + + /** + * The following function deletes the value associated with a + * symbol. The symbol can be either a terminal or nonterminal. + * @param int the symbol code + * @param mixed the symbol's value + */ + static function yy_destructor($yymajor, $yypminor) + { + switch ($yymajor) { + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ + default: break; /* If no destructor action specified: do nothing */ + } + } + + /** + * Pop the parser's stack once. + * + * If there is a destructor routine associated with the token which + * is popped from the stack, then call it. + * + * Return the major token number for the symbol popped. + * @param PHP_LexerGenerator_Regex_yyParser + * @return int + */ + function yy_pop_parser_stack() + { + if (!count($this->yystack)) { + return; + } + $yytos = array_pop($this->yystack); + if (self::$yyTraceFILE && $this->yyidx >= 0) { + fwrite(self::$yyTraceFILE, + self::$yyTracePrompt . 'Popping ' . self::$yyTokenName[$yytos->major] . + "\n"); + } + $yymajor = $yytos->major; + self::yy_destructor($yymajor, $yytos->minor); + $this->yyidx--; + return $yymajor; + } + + /** + * Deallocate and destroy a parser. Destructors are all called for + * all stack elements before shutting the parser down. + */ + function __destruct() + { + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + if (is_resource(self::$yyTraceFILE)) { + fclose(self::$yyTraceFILE); + } + } + + /** + * Based on the current state and parser stack, get a list of all + * possible lookahead tokens + * @param int + * @return array + */ + function yy_get_expected_tokens($token) + { + $state = $this->yystack[$this->yyidx]->stateno; + $expected = self::$yyExpectedTokens[$state]; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return $expected; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return array_unique($expected); + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate])) { + $expected += self::$yyExpectedTokens[$nextstate]; + if (in_array($token, + self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return array_unique($expected); + } + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new PHP_LexerGenerator_Regex_yyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return array_unique($expected); + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return $expected; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + return array_unique($expected); + } + + /** + * Based on the parser state and current parser stack, determine whether + * the lookahead token is possible. + * + * The parser will convert the token value to an error token if not. This + * catches some unusual edge cases where the parser would fail. + * @param int + * @return bool + */ + function yy_is_expected_token($token) + { + if ($token === 0) { + return true; // 0 is not part of this + } + $state = $this->yystack[$this->yyidx]->stateno; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return true; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return true; + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate]) && + in_array($token, self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new PHP_LexerGenerator_Regex_yyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + if (!$token) { + // end of input: this is valid + return true; + } + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return false; + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return true; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + + /** + * Find the appropriate action for a parser given the terminal + * look-ahead token iLookAhead. + * + * If the look-ahead token is YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return YY_NO_ACTION. + * @param int The look-ahead token + */ + function yy_find_shift_action($iLookAhead) + { + $stateno = $this->yystack[$this->yyidx]->stateno; + + /* if ($this->yyidx < 0) return self::YY_NO_ACTION; */ + if (!isset(self::$yy_shift_ofst[$stateno])) { + // no shift actions + return self::$yy_default[$stateno]; + } + $i = self::$yy_shift_ofst[$stateno]; + if ($i === self::YY_SHIFT_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback) + && ($iFallback = self::$yyFallback[$iLookAhead]) != 0) { + if (self::$yyTraceFILE) { + fwrite(self::$yyTraceFILE, self::$yyTracePrompt . "FALLBACK " . + self::$yyTokenName[$iLookAhead] . " => " . + self::$yyTokenName[$iFallback] . "\n"); + } + return $this->yy_find_shift_action($iFallback); + } + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Find the appropriate action for a parser given the non-terminal + * look-ahead token $iLookAhead. + * + * If the look-ahead token is self::YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return self::YY_NO_ACTION. + * @param int Current state number + * @param int The look-ahead token + */ + function yy_find_reduce_action($stateno, $iLookAhead) + { + /* $stateno = $this->yystack[$this->yyidx]->stateno; */ + + if (!isset(self::$yy_reduce_ofst[$stateno])) { + return self::$yy_default[$stateno]; + } + $i = self::$yy_reduce_ofst[$stateno]; + if ($i == self::YY_REDUCE_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Perform a shift action. + * @param int The new state to shift in + * @param int The major token to shift in + * @param mixed the minor token to shift in + */ + function yy_shift($yyNewState, $yyMajor, $yypMinor) + { + $this->yyidx++; + if ($this->yyidx >= self::YYSTACKDEPTH) { + $this->yyidx--; + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sStack Overflow!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will execute if the parser + ** stack ever overflows */ + return; + } + $yytos = new PHP_LexerGenerator_Regex_yyStackEntry; + $yytos->stateno = $yyNewState; + $yytos->major = $yyMajor; + $yytos->minor = $yypMinor; + array_push($this->yystack, $yytos); + if (self::$yyTraceFILE && $this->yyidx > 0) { + fprintf(self::$yyTraceFILE, "%sShift %d\n", self::$yyTracePrompt, + $yyNewState); + fprintf(self::$yyTraceFILE, "%sStack:", self::$yyTracePrompt); + for($i = 1; $i <= $this->yyidx; $i++) { + fprintf(self::$yyTraceFILE, " %s", + self::$yyTokenName[$this->yystack[$i]->major]); + } + fwrite(self::$yyTraceFILE,"\n"); + } + } + + /** + * The following table contains information about every rule that + * is used during the reduce. + * + *
+     * array(
+     *  array(
+     *   int $lhs;         Symbol on the left-hand side of the rule
+     *   int $nrhs;     Number of right-hand side symbols in the rule
+     *  ),...
+     * );
+     * 
+ */ + static public $yyRuleInfo = array( + array( 'lhs' => 29, 'rhs' => 1 ), + array( 'lhs' => 30, 'rhs' => 3 ), + array( 'lhs' => 30, 'rhs' => 2 ), + array( 'lhs' => 30, 'rhs' => 2 ), + array( 'lhs' => 30, 'rhs' => 1 ), + array( 'lhs' => 30, 'rhs' => 3 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 1 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 31, 'rhs' => 2 ), + array( 'lhs' => 33, 'rhs' => 3 ), + array( 'lhs' => 33, 'rhs' => 4 ), + array( 'lhs' => 33, 'rhs' => 4 ), + array( 'lhs' => 33, 'rhs' => 5 ), + array( 'lhs' => 43, 'rhs' => 1 ), + array( 'lhs' => 43, 'rhs' => 1 ), + array( 'lhs' => 43, 'rhs' => 3 ), + array( 'lhs' => 43, 'rhs' => 3 ), + array( 'lhs' => 43, 'rhs' => 3 ), + array( 'lhs' => 43, 'rhs' => 1 ), + array( 'lhs' => 43, 'rhs' => 1 ), + array( 'lhs' => 43, 'rhs' => 2 ), + array( 'lhs' => 43, 'rhs' => 2 ), + array( 'lhs' => 43, 'rhs' => 2 ), + array( 'lhs' => 43, 'rhs' => 4 ), + array( 'lhs' => 43, 'rhs' => 4 ), + array( 'lhs' => 43, 'rhs' => 4 ), + array( 'lhs' => 43, 'rhs' => 4 ), + array( 'lhs' => 43, 'rhs' => 2 ), + array( 'lhs' => 43, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 1 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 1 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 1 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 1 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 1 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 1 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 3 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 3 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 3 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 3 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 3 ), + array( 'lhs' => 32, 'rhs' => 2 ), + array( 'lhs' => 32, 'rhs' => 3 ), + array( 'lhs' => 34, 'rhs' => 3 ), + array( 'lhs' => 34, 'rhs' => 5 ), + array( 'lhs' => 35, 'rhs' => 4 ), + array( 'lhs' => 35, 'rhs' => 5 ), + array( 'lhs' => 42, 'rhs' => 7 ), + array( 'lhs' => 42, 'rhs' => 6 ), + array( 'lhs' => 42, 'rhs' => 4 ), + array( 'lhs' => 42, 'rhs' => 5 ), + array( 'lhs' => 42, 'rhs' => 4 ), + array( 'lhs' => 42, 'rhs' => 5 ), + array( 'lhs' => 36, 'rhs' => 4 ), + array( 'lhs' => 36, 'rhs' => 4 ), + array( 'lhs' => 37, 'rhs' => 4 ), + array( 'lhs' => 37, 'rhs' => 4 ), + array( 'lhs' => 38, 'rhs' => 4 ), + array( 'lhs' => 38, 'rhs' => 5 ), + array( 'lhs' => 38, 'rhs' => 3 ), + array( 'lhs' => 38, 'rhs' => 4 ), + array( 'lhs' => 39, 'rhs' => 4 ), + array( 'lhs' => 40, 'rhs' => 3 ), + array( 'lhs' => 41, 'rhs' => 3 ), + ); + + /** + * The following table contains a mapping of reduce action to method name + * that handles the reduction. + * + * If a rule is not set, it has no handler. + */ + static public $yyReduceMap = array( + 0 => 0, + 1 => 1, + 2 => 2, + 3 => 3, + 4 => 4, + 6 => 4, + 7 => 4, + 9 => 4, + 10 => 4, + 12 => 4, + 13 => 4, + 14 => 4, + 15 => 4, + 16 => 4, + 5 => 5, + 17 => 17, + 18 => 17, + 20 => 17, + 21 => 17, + 23 => 17, + 24 => 17, + 25 => 17, + 26 => 17, + 27 => 17, + 28 => 28, + 29 => 29, + 30 => 30, + 31 => 31, + 32 => 32, + 48 => 32, + 50 => 32, + 33 => 33, + 54 => 33, + 34 => 34, + 35 => 35, + 36 => 36, + 37 => 37, + 56 => 37, + 38 => 38, + 58 => 38, + 39 => 39, + 64 => 39, + 40 => 40, + 66 => 40, + 41 => 41, + 60 => 41, + 62 => 41, + 42 => 42, + 43 => 43, + 44 => 44, + 45 => 45, + 46 => 46, + 68 => 46, + 47 => 47, + 70 => 47, + 49 => 49, + 51 => 49, + 52 => 52, + 53 => 53, + 55 => 55, + 57 => 57, + 59 => 59, + 61 => 61, + 63 => 61, + 65 => 65, + 67 => 67, + 69 => 69, + 71 => 71, + 72 => 72, + 73 => 73, + 74 => 74, + 75 => 75, + 76 => 76, + 77 => 77, + 78 => 78, + 79 => 79, + 80 => 80, + 84 => 80, + 81 => 81, + 82 => 82, + 83 => 83, + 85 => 85, + 86 => 86, + 87 => 87, + 88 => 88, + 89 => 89, + 90 => 90, + 91 => 91, + 92 => 92, + ); + /* Beginning here are the reduction cases. A typical example + ** follows: + ** #line + ** function yy_r0($yymsp){ ... } // User supplied code + ** #line + */ +#line 47 "Parser.y" + function yy_r0(){ + $this->yystack[$this->yyidx + 0]->minor->string = str_replace('"', '\\"', $this->yystack[$this->yyidx + 0]->minor->string); + $x = $this->yystack[$this->yyidx + 0]->minor->metadata; + $x['subpatterns'] = $this->_subpatterns; + $this->yystack[$this->yyidx + 0]->minor->metadata = $x; + $this->_subpatterns = 0; + $this->result = $this->yystack[$this->yyidx + 0]->minor; + } +#line 1259 "Parser.php" +#line 56 "Parser.y" + function yy_r1(){ + throw new PHP_LexerGenerator_Exception('Cannot include start match "' . + $this->yystack[$this->yyidx + -2]->minor . '" or end match "' . $this->yystack[$this->yyidx + 0]->minor . '"'); + } +#line 1265 "Parser.php" +#line 60 "Parser.y" + function yy_r2(){ + throw new PHP_LexerGenerator_Exception('Cannot include start match "' . + B . '"'); + } +#line 1271 "Parser.php" +#line 64 "Parser.y" + function yy_r3(){ + throw new PHP_LexerGenerator_Exception('Cannot include end match "' . $this->yystack[$this->yyidx + 0]->minor . '"'); + } +#line 1276 "Parser.php" +#line 67 "Parser.y" + function yy_r4(){$this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 1279 "Parser.php" +#line 68 "Parser.y" + function yy_r5(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -2]->minor->string . '|' . $this->yystack[$this->yyidx + 0]->minor->string, array( + 'pattern' => $this->yystack[$this->yyidx + -2]->minor['pattern'] . '|' . $this->yystack[$this->yyidx + 0]->minor['pattern'])); + } +#line 1285 "Parser.php" +#line 84 "Parser.y" + function yy_r17(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -1]->minor->string . $this->yystack[$this->yyidx + 0]->minor->string, array( + 'pattern' => $this->yystack[$this->yyidx + -1]->minor['pattern'] . $this->yystack[$this->yyidx + 0]->minor['pattern'])); + } +#line 1291 "Parser.php" +#line 123 "Parser.y" + function yy_r28(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('[' . $this->yystack[$this->yyidx + -1]->minor->string . ']', array( + 'pattern' => '[' . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ']')); + } +#line 1297 "Parser.php" +#line 127 "Parser.y" + function yy_r29(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('[^' . $this->yystack[$this->yyidx + -1]->minor->string . ']', array( + 'pattern' => '[^' . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ']')); + } +#line 1303 "Parser.php" +#line 131 "Parser.y" + function yy_r30(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('[' . $this->yystack[$this->yyidx + -2]->minor->string . ']' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => '[' . $this->yystack[$this->yyidx + -2]->minor['pattern'] . ']' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1309 "Parser.php" +#line 135 "Parser.y" + function yy_r31(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('[^' . $this->yystack[$this->yyidx + -2]->minor->string . ']' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => '[^' . $this->yystack[$this->yyidx + -2]->minor['pattern'] . ']' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1315 "Parser.php" +#line 140 "Parser.y" + function yy_r32(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1321 "Parser.php" +#line 144 "Parser.y" + function yy_r33(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('\\\\' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1327 "Parser.php" +#line 148 "Parser.y" + function yy_r34(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('\\\\' . $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1333 "Parser.php" +#line 152 "Parser.y" + function yy_r35(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1339 "Parser.php" +#line 156 "Parser.y" + function yy_r36(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -2]->minor . '-\\\\' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1345 "Parser.php" +#line 160 "Parser.y" + function yy_r37(){ + if (((int) substr($this->yystack[$this->yyidx + 0]->minor, 1)) > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception('Back-reference refers to non-existent ' . + 'sub-pattern ' . substr($this->yystack[$this->yyidx + 0]->minor, 1)); + } + $this->yystack[$this->yyidx + 0]->minor = substr($this->yystack[$this->yyidx + 0]->minor, 1); + // adjust back-reference for containing () + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('\\\\' . ($this->yystack[$this->yyidx + 0]->minor + $this->_patternIndex), array( + 'pattern' => '\\' . ($this->_updatePattern ? ($this->yystack[$this->yyidx + 0]->minor + $this->_patternIndex) : $this->yystack[$this->yyidx + 0]->minor))); + } +#line 1357 "Parser.php" +#line 170 "Parser.y" + function yy_r38(){ + if (((int) substr($this->yystack[$this->yyidx + 0]->minor, 1)) > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception($this->yystack[$this->yyidx + 0]->minor . ' will be interpreted as an invalid' . + ' back-reference, use "\\0' . substr($this->yystack[$this->yyidx + 0]->minor, 1) . ' for octal'); + } + $this->yystack[$this->yyidx + 0]->minor = substr($this->yystack[$this->yyidx + 0]->minor, 1); + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('\\\\' . ($this->yystack[$this->yyidx + 0]->minor + $this->_patternIndex), array( + 'pattern' => '\\' . ($this->_updatePattern ? ($this->yystack[$this->yyidx + 0]->minor + $this->_patternIndex) : $this->yystack[$this->yyidx + 0]->minor))); + } +#line 1368 "Parser.php" +#line 179 "Parser.y" + function yy_r39(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -1]->minor->string . '\\' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -1]->minor['pattern'] . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1374 "Parser.php" +#line 183 "Parser.y" + function yy_r40(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -1]->minor->string . '\\\\' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -1]->minor['pattern'] . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1380 "Parser.php" +#line 187 "Parser.y" + function yy_r41(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -1]->minor->string . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -1]->minor['pattern'] . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1386 "Parser.php" +#line 191 "Parser.y" + function yy_r42(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -3]->minor->string . '\\\\' . $this->yystack[$this->yyidx + -2]->minor . '-\\' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -3]->minor['pattern'] . $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1392 "Parser.php" +#line 195 "Parser.y" + function yy_r43(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -3]->minor->string . '\\\\' . $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -3]->minor['pattern'] . $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1398 "Parser.php" +#line 199 "Parser.y" + function yy_r44(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -3]->minor->string . $this->yystack[$this->yyidx + -2]->minor . '-\\\\' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -3]->minor['pattern'] . $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1404 "Parser.php" +#line 203 "Parser.y" + function yy_r45(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -3]->minor->string . $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -3]->minor['pattern'] . $this->yystack[$this->yyidx + -2]->minor . '-' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1410 "Parser.php" +#line 207 "Parser.y" + function yy_r46(){ + if (((int) substr($this->yystack[$this->yyidx + 0]->minor, 1)) > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception('Back-reference refers to non-existent ' . + 'sub-pattern ' . substr($this->yystack[$this->yyidx + 0]->minor, 1)); + } + $this->yystack[$this->yyidx + 0]->minor = substr($this->yystack[$this->yyidx + 0]->minor, 1); + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -1]->minor->string . '\\\\' . ($this->yystack[$this->yyidx + 0]->minor + $this->_patternIndex), array( + 'pattern' => $this->yystack[$this->yyidx + -1]->minor['pattern'] . '\\' . ($this->_updatePattern ? ($this->yystack[$this->yyidx + 0]->minor + $this->_patternIndex) : $this->yystack[$this->yyidx + 0]->minor))); + } +#line 1421 "Parser.php" +#line 216 "Parser.y" + function yy_r47(){ + if (((int) substr($this->yystack[$this->yyidx + 0]->minor, 1)) > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception($this->yystack[$this->yyidx + 0]->minor . ' will be interpreted as an invalid' . + ' back-reference, use "\\0' . substr($this->yystack[$this->yyidx + 0]->minor, 1) . ' for octal'); + } + $this->yystack[$this->yyidx + 0]->minor = substr($this->yystack[$this->yyidx + 0]->minor, 1); + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -1]->minor->string . '\\\\' . ($this->yystack[$this->yyidx + 0]->minor + $this->_patternIndex), array( + 'pattern' => $this->yystack[$this->yyidx + -1]->minor['pattern'] . '\\' . ($this->_updatePattern ? ($this->yystack[$this->yyidx + 0]->minor + $this->_patternIndex) : $this->yystack[$this->yyidx + 0]->minor))); + } +#line 1432 "Parser.php" +#line 230 "Parser.y" + function yy_r49(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1438 "Parser.php" +#line 242 "Parser.y" + function yy_r52(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('\\' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1444 "Parser.php" +#line 246 "Parser.y" + function yy_r53(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('\\' . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1450 "Parser.php" +#line 254 "Parser.y" + function yy_r55(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('\\\\' . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1456 "Parser.php" +#line 268 "Parser.y" + function yy_r57(){ + if (((int) substr($this->yystack[$this->yyidx + -1]->minor, 1)) > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception('Back-reference refers to non-existent ' . + 'sub-pattern ' . substr($this->yystack[$this->yyidx + -1]->minor, 1)); + } + $this->yystack[$this->yyidx + -1]->minor = substr($this->yystack[$this->yyidx + -1]->minor, 1); + // adjust back-reference for containing () + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('\\\\' . ($this->yystack[$this->yyidx + -1]->minor + $this->_patternIndex) . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => '\\' . ($this->_updatePattern ? ($this->yystack[$this->yyidx + -1]->minor + $this->_patternIndex) : $this->yystack[$this->yyidx + -1]->minor) . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1468 "Parser.php" +#line 287 "Parser.y" + function yy_r59(){ + if (((int) substr($this->yystack[$this->yyidx + -1]->minor, 1)) > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception($this->yystack[$this->yyidx + -1]->minor . ' will be interpreted as an invalid' . + ' back-reference, use "\\0' . substr($this->yystack[$this->yyidx + -1]->minor, 1) . ' for octal'); + } + $this->yystack[$this->yyidx + -1]->minor = substr($this->yystack[$this->yyidx + -1]->minor, 1); + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('\\\\' . ($this->yystack[$this->yyidx + -1]->minor + $this->_patternIndex) . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => '\\' . ($this->_updatePattern ? ($this->yystack[$this->yyidx + -1]->minor + $this->_patternIndex) : $this->yystack[$this->yyidx + -1]->minor) . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1479 "Parser.php" +#line 300 "Parser.y" + function yy_r61(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -2]->minor->string . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -2]->minor['pattern'] . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1485 "Parser.php" +#line 316 "Parser.y" + function yy_r65(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -2]->minor->string . '\\' . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -2]->minor['pattern'] . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1491 "Parser.php" +#line 324 "Parser.y" + function yy_r67(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -2]->minor->string . '\\\\' . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -2]->minor['pattern'] . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1497 "Parser.php" +#line 337 "Parser.y" + function yy_r69(){ + if (((int) substr($this->yystack[$this->yyidx + -1]->minor, 1)) > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception('Back-reference refers to non-existent ' . + 'sub-pattern ' . substr($this->yystack[$this->yyidx + -1]->minor, 1)); + } + $this->yystack[$this->yyidx + -1]->minor = substr($this->yystack[$this->yyidx + -1]->minor, 1); + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -2]->minor->string . '\\\\' . ($this->yystack[$this->yyidx + -1]->minor + $this->_patternIndex) . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -2]->minor['pattern'] . '\\' . ($this->_updatePattern ? ($this->yystack[$this->yyidx + -1]->minor + $this->_patternIndex) : $this->yystack[$this->yyidx + -1]->minor) . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1508 "Parser.php" +#line 355 "Parser.y" + function yy_r71(){ + if (((int) substr($this->yystack[$this->yyidx + -1]->minor, 1)) > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception($this->yystack[$this->yyidx + -1]->minor . ' will be interpreted as an invalid' . + ' back-reference, use "\\0' . substr($this->yystack[$this->yyidx + -1]->minor, 1) . ' for octal'); + } + $this->yystack[$this->yyidx + -1]->minor = substr($this->yystack[$this->yyidx + -1]->minor, 1); + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken($this->yystack[$this->yyidx + -2]->minor->string . '\\\\' . ($this->yystack[$this->yyidx + -1]->minor + $this->_patternIndex) . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => $this->yystack[$this->yyidx + -2]->minor['pattern'] . '\\' . ($this->_updatePattern ? ($this->yystack[$this->yyidx + -1]->minor + $this->_patternIndex) : $this->yystack[$this->yyidx + -1]->minor) . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1519 "Parser.php" +#line 365 "Parser.y" + function yy_r72(){ + throw new PHP_LexerGenerator_Exception('Error: cannot set preg options directly with "' . + $this->yystack[$this->yyidx + -2]->minor . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor . '"'); + } +#line 1525 "Parser.php" +#line 369 "Parser.y" + function yy_r73(){ + throw new PHP_LexerGenerator_Exception('Error: cannot set preg options directly with "' . + $this->yystack[$this->yyidx + -4]->minor . $this->yystack[$this->yyidx + -3]->minor . $this->yystack[$this->yyidx + -2]->minor . $this->yystack[$this->yyidx + -1]->minor['pattern'] . $this->yystack[$this->yyidx + 0]->minor . '"'); + } +#line 1531 "Parser.php" +#line 374 "Parser.y" + function yy_r74(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(?:' . $this->yystack[$this->yyidx + -1]->minor->string . ')', array( + 'pattern' => '(?:' . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ')')); + } +#line 1537 "Parser.php" +#line 378 "Parser.y" + function yy_r75(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(?:' . $this->yystack[$this->yyidx + -2]->minor->string . ')' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => '(?:' . $this->yystack[$this->yyidx + -2]->minor['pattern'] . ')' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1543 "Parser.php" +#line 383 "Parser.y" + function yy_r76(){ + if ($this->yystack[$this->yyidx + -4]->minor != 'R') { + if (!preg_match('/[1-9][0-9]*/', $this->yystack[$this->yyidx + -4]->minor)) { + throw new PHP_LexerGenerator_Exception('Invalid sub-pattern conditional: "(?(' . $this->yystack[$this->yyidx + -4]->minor . ')"'); + } + if ($this->yystack[$this->yyidx + -4]->minor > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception('sub-pattern conditional . "' . $this->yystack[$this->yyidx + -4]->minor . '" refers to non-existent sub-pattern'); + } + } else { + throw new PHP_LexerGenerator_Exception('Recursive conditional (?(' . $this->yystack[$this->yyidx + -4]->minor . ')" cannot work in this lexer'); + } + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(?(' . $this->yystack[$this->yyidx + -4]->minor . ')' . $this->yystack[$this->yyidx + -2]->minor->string . ')' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => '(?(' . $this->yystack[$this->yyidx + -4]->minor . ')' . $this->yystack[$this->yyidx + -2]->minor['pattern'] . ')' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1559 "Parser.php" +#line 397 "Parser.y" + function yy_r77(){ + if ($this->yystack[$this->yyidx + -3]->minor != 'R') { + if (!preg_match('/[1-9][0-9]*/', $this->yystack[$this->yyidx + -3]->minor)) { + throw new PHP_LexerGenerator_Exception('Invalid sub-pattern conditional: "(?(' . $this->yystack[$this->yyidx + -3]->minor . ')"'); + } + if ($this->yystack[$this->yyidx + -3]->minor > $this->_subpatterns) { + throw new PHP_LexerGenerator_Exception('sub-pattern conditional . "' . $this->yystack[$this->yyidx + -3]->minor . '" refers to non-existent sub-pattern'); + } + } else { + throw new PHP_LexerGenerator_Exception('Recursive conditional (?(' . $this->yystack[$this->yyidx + -3]->minor . ')" cannot work in this lexer'); + } + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(?(' . $this->yystack[$this->yyidx + -3]->minor . ')' . $this->yystack[$this->yyidx + -1]->minor->string . ')', array( + 'pattern' => '(?(' . $this->yystack[$this->yyidx + -3]->minor . ')' . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ')')); + } +#line 1575 "Parser.php" +#line 411 "Parser.y" + function yy_r78(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(?' . $this->yystack[$this->yyidx + -2]->minor->string . $this->yystack[$this->yyidx + -1]->minor->string . ')', array( + 'pattern' => '(?' . $this->yystack[$this->yyidx + -2]->minor['pattern'] . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ')')); + } +#line 1581 "Parser.php" +#line 415 "Parser.y" + function yy_r79(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(?' . $this->yystack[$this->yyidx + -3]->minor->string . $this->yystack[$this->yyidx + -2]->minor->string . ')' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => '(?' . $this->yystack[$this->yyidx + -3]->minor['pattern'] . $this->yystack[$this->yyidx + -2]->minor['pattern'] . ')' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1587 "Parser.php" +#line 419 "Parser.y" + function yy_r80(){ + throw new PHP_LexerGenerator_Exception('Look-behind assertions cannot be used: "(?<=' . + $this->yystack[$this->yyidx + -1]->minor['pattern'] . ')'); + } +#line 1593 "Parser.php" +#line 423 "Parser.y" + function yy_r81(){ + throw new PHP_LexerGenerator_Exception('Look-behind assertions cannot be used: "(?<=' . + $this->yystack[$this->yyidx + -2]->minor['pattern'] . ')'); + } +#line 1599 "Parser.php" +#line 428 "Parser.y" + function yy_r82(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(?=' . $this->yystack[$this->yyidx + -1]->minor->string . ')', array( + 'pattern '=> '(?=' . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ')')); + } +#line 1605 "Parser.php" +#line 432 "Parser.y" + function yy_r83(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(?!' . $this->yystack[$this->yyidx + -1]->minor->string . ')', array( + 'pattern' => '(?!' . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ')')); + } +#line 1611 "Parser.php" +#line 441 "Parser.y" + function yy_r85(){ + throw new PHP_LexerGenerator_Exception('Look-behind assertions cannot be used: "(?yystack[$this->yyidx + -1]->minor['pattern'] . ')'); + } +#line 1617 "Parser.php" +#line 446 "Parser.y" + function yy_r86(){ + throw new PHP_LexerGenerator_Exception('Cannot use named sub-patterns: "(' . + $this->yystack[$this->yyidx + -2]->minor['pattern'] . ')'); + } +#line 1623 "Parser.php" +#line 450 "Parser.y" + function yy_r87(){ + throw new PHP_LexerGenerator_Exception('Cannot use named sub-patterns: "(' . + $this->yystack[$this->yyidx + -3]->minor['pattern'] . ')'); + } +#line 1629 "Parser.php" +#line 454 "Parser.y" + function yy_r88(){ + $this->_subpatterns++; + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(' . $this->yystack[$this->yyidx + -1]->minor->string . ')', array( + 'pattern' => '(' . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ')')); + } +#line 1636 "Parser.php" +#line 459 "Parser.y" + function yy_r89(){ + $this->_subpatterns++; + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(' . $this->yystack[$this->yyidx + -2]->minor->string . ')' . $this->yystack[$this->yyidx + 0]->minor, array( + 'pattern' => '(' . $this->yystack[$this->yyidx + -2]->minor['pattern'] . ')' . $this->yystack[$this->yyidx + 0]->minor)); + } +#line 1643 "Parser.php" +#line 465 "Parser.y" + function yy_r90(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(?>' . $this->yystack[$this->yyidx + -1]->minor->string . ')', array( + 'pattern' => '(?>' . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ')')); + } +#line 1649 "Parser.php" +#line 470 "Parser.y" + function yy_r91(){ + $this->_retvalue = new PHP_LexerGenerator_ParseryyToken('(' . $this->yystack[$this->yyidx + -1]->minor->string . ')', array( + 'pattern' => '(' . $this->yystack[$this->yyidx + -1]->minor['pattern'] . ')')); + } +#line 1655 "Parser.php" +#line 475 "Parser.y" + function yy_r92(){ + throw new Exception('(?R) cannot work in this lexer'); + } +#line 1660 "Parser.php" + + /** + * placeholder for the left hand side in a reduce operation. + * + * For a parser with a rule like this: + *
+     * rule(A) ::= B. { A = 1; }
+     * 
+ * + * The parser will translate to something like: + * + * + * function yy_r0(){$this->_retvalue = 1;} + * + */ + private $_retvalue; + + /** + * Perform a reduce action and the shift that must immediately + * follow the reduce. + * + * For a rule such as: + * + *
+     * A ::= B blah C. { dosomething(); }
+     * 
+ * + * This function will first call the action, if any, ("dosomething();" in our + * example), and then it will pop three states from the stack, + * one for each entry on the right-hand side of the expression + * (B, blah, and C in our example rule), and then push the result of the action + * back on to the stack with the resulting state reduced to (as described in the .out + * file) + * @param int Number of the rule by which to reduce + */ + function yy_reduce($yyruleno) + { + //int $yygoto; /* The next state */ + //int $yyact; /* The next action */ + //mixed $yygotominor; /* The LHS of the rule reduced */ + //PHP_LexerGenerator_Regex_yyStackEntry $yymsp; /* The top of the parser's stack */ + //int $yysize; /* Amount to pop the stack */ + $yymsp = $this->yystack[$this->yyidx]; + if (self::$yyTraceFILE && $yyruleno >= 0 + && $yyruleno < count(self::$yyRuleName)) { + fprintf(self::$yyTraceFILE, "%sReduce (%d) [%s].\n", + self::$yyTracePrompt, $yyruleno, + self::$yyRuleName[$yyruleno]); + } + + $this->_retvalue = $yy_lefthand_side = null; + if (array_key_exists($yyruleno, self::$yyReduceMap)) { + // call the action + $this->_retvalue = null; + $this->{'yy_r' . self::$yyReduceMap[$yyruleno]}(); + $yy_lefthand_side = $this->_retvalue; + } + $yygoto = self::$yyRuleInfo[$yyruleno]['lhs']; + $yysize = self::$yyRuleInfo[$yyruleno]['rhs']; + $this->yyidx -= $yysize; + for($i = $yysize; $i; $i--) { + // pop all of the right-hand side parameters + array_pop($this->yystack); + } + $yyact = $this->yy_find_reduce_action($this->yystack[$this->yyidx]->stateno, $yygoto); + if ($yyact < self::YYNSTATE) { + /* If we are not debugging and the reduce action popped at least + ** one element off the stack, then we can push the new element back + ** onto the stack here, and skip the stack overflow test in yy_shift(). + ** That gives a significant speed improvement. */ + if (!self::$yyTraceFILE && $yysize) { + $this->yyidx++; + $x = new PHP_LexerGenerator_Regex_yyStackEntry; + $x->stateno = $yyact; + $x->major = $yygoto; + $x->minor = $yy_lefthand_side; + $this->yystack[$this->yyidx] = $x; + } else { + $this->yy_shift($yyact, $yygoto, $yy_lefthand_side); + } + } elseif ($yyact == self::YYNSTATE + self::YYNRULE + 1) { + $this->yy_accept(); + } + } + + /** + * The following code executes when the parse fails + * + * Code from %parse_fail is inserted here + */ + function yy_parse_failed() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sFail!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser fails */ + } + + /** + * The following code executes when a syntax error first occurs. + * + * %syntax_error code is inserted here + * @param int The major type of the error token + * @param mixed The minor type of the error token + */ + function yy_syntax_error($yymajor, $TOKEN) + { +#line 6 "Parser.y" + +/* ?>_lex->line . ": token '" . + $this->_lex->value . "' while parsing rule:"; + foreach ($this->yystack as $entry) { + echo $this->tokenName($entry->major) . ' '; + } + foreach ($this->yy_get_expected_tokens($yymajor) as $token) { + $expect[] = self::$yyTokenName[$token]; + } + throw new Exception('Unexpected ' . $this->tokenName($yymajor) . '(' . $TOKEN + . '), expected one of: ' . implode(',', $expect)); +#line 1788 "Parser.php" + } + + /** + * The following is executed when the parser accepts + * + * %parse_accept code is inserted here + */ + function yy_accept() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sAccept!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $stack = $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser accepts */ + } + + /** + * The main parser program. + * + * The first argument is the major token number. The second is + * the token value string as scanned from the input. + * + * @param int the token number + * @param mixed the token value + * @param mixed any extra arguments that should be passed to handlers + */ + function doParse($yymajor, $yytokenvalue) + { +// $yyact; /* The parser action. */ +// $yyendofinput; /* True if we are at the end of input */ + $yyerrorhit = 0; /* True if yymajor has invoked an error */ + + /* (re)initialize the parser, if necessary */ + if ($this->yyidx === null || $this->yyidx < 0) { + /* if ($yymajor == 0) return; // not sure why this was here... */ + $this->yyidx = 0; + $this->yyerrcnt = -1; + $x = new PHP_LexerGenerator_Regex_yyStackEntry; + $x->stateno = 0; + $x->major = 0; + $this->yystack = array(); + array_push($this->yystack, $x); + } + $yyendofinput = ($yymajor==0); + + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sInput %s\n", + self::$yyTracePrompt, self::$yyTokenName[$yymajor]); + } + + do { + $yyact = $this->yy_find_shift_action($yymajor); + if ($yymajor < self::YYERRORSYMBOL && + !$this->yy_is_expected_token($yymajor)) { + // force a syntax error + $yyact = self::YY_ERROR_ACTION; + } + if ($yyact < self::YYNSTATE) { + $this->yy_shift($yyact, $yymajor, $yytokenvalue); + $this->yyerrcnt--; + if ($yyendofinput && $this->yyidx >= 0) { + $yymajor = 0; + } else { + $yymajor = self::YYNOCODE; + } + } elseif ($yyact < self::YYNSTATE + self::YYNRULE) { + $this->yy_reduce($yyact - self::YYNSTATE); + } elseif ($yyact == self::YY_ERROR_ACTION) { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sSyntax Error!\n", + self::$yyTracePrompt); + } + if (self::YYERRORSYMBOL) { + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if ($this->yyerrcnt < 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $yymx = $this->yystack[$this->yyidx]->major; + if ($yymx == self::YYERRORSYMBOL || $yyerrorhit ){ + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sDiscard input token %s\n", + self::$yyTracePrompt, self::$yyTokenName[$yymajor]); + } + $this->yy_destructor($yymajor, $yytokenvalue); + $yymajor = self::YYNOCODE; + } else { + while ($this->yyidx >= 0 && + $yymx != self::YYERRORSYMBOL && + ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE + ){ + $this->yy_pop_parser_stack(); + } + if ($this->yyidx < 0 || $yymajor==0) { + $this->yy_destructor($yymajor, $yytokenvalue); + $this->yy_parse_failed(); + $yymajor = self::YYNOCODE; + } elseif ($yymx != self::YYERRORSYMBOL) { + $u2 = 0; + $this->yy_shift($yyact, self::YYERRORSYMBOL, $u2); + } + } + $this->yyerrcnt = 3; + $yyerrorhit = 1; + } else { + /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if ($this->yyerrcnt <= 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $this->yyerrcnt = 3; + $this->yy_destructor($yymajor, $yytokenvalue); + if ($yyendofinput) { + $this->yy_parse_failed(); + } + $yymajor = self::YYNOCODE; + } + } else { + $this->yy_accept(); + $yymajor = self::YYNOCODE; + } + } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0); + } +} diff --git a/libs/lexer/LexerGenerator/cli.php b/libs/lexer/LexerGenerator/cli.php new file mode 100644 index 00000000..9db328e2 --- /dev/null +++ b/libs/lexer/LexerGenerator/cli.php @@ -0,0 +1,4 @@ + diff --git a/libs/lexer/ParserGenerator.php b/libs/lexer/ParserGenerator.php new file mode 100644 index 00000000..fe390340 --- /dev/null +++ b/libs/lexer/ParserGenerator.php @@ -0,0 +1,760 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_ParserGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: ParserGenerator.php,v 1.2 2006/12/16 04:01:58 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/**#@+ + * Basic components of the parser generator + */ +require_once './ParserGenerator/Action.php'; +require_once './ParserGenerator/ActionTable.php'; +require_once './ParserGenerator/Config.php'; +require_once './ParserGenerator/Data.php'; +require_once './ParserGenerator/Symbol.php'; +require_once './ParserGenerator/Rule.php'; +require_once './ParserGenerator/Parser.php'; +require_once './ParserGenerator/PropagationLink.php'; +require_once './ParserGenerator/State.php'; +/**#@-*/ +/** + * The basic home class for the parser generator + * + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version 0.1.5 + * @since Class available since Release 0.1.0 + * @example Lempar.php + * @example examples/Parser.y Sample parser file format (PHP_LexerGenerator's parser) + * @example examples/Parser.php Sample parser file format PHP code (PHP_LexerGenerator's parser) + */ +class PHP_ParserGenerator +{ + /** + * Set this to 1 to turn on debugging of Lemon's parsing of + * grammar files. + */ + const DEBUG = 0; + const MAXRHS = 1000; + const OPT_FLAG = 1, OPT_INT = 2, OPT_DBL = 3, OPT_STR = 4, + OPT_FFLAG = 5, OPT_FINT = 6, OPT_FDBL = 7, OPT_FSTR = 8; + public $azDefine = array(); + private static $options = array( + 'b' => array( + 'type' => self::OPT_FLAG, + 'arg' => 'basisflag', + 'message' => 'Print only the basis in report.' + ), + 'c' => array( + 'type' => self::OPT_FLAG, + 'arg' => 'compress', + 'message' => 'Don\'t compress the action table.' + ), + 'D' => array( + 'type' => self::OPT_FSTR, + 'arg' => 'handle_D_option', + 'message' => 'Define an %ifdef macro.' + ), + 'g' => array( + 'type' => self::OPT_FLAG, + 'arg' => 'rpflag', + 'message' => 'Print grammar without actions.' + ), + 'm' => array( + 'type' => self::OPT_FLAG, + 'arg' => 'mhflag', + 'message' => 'Output a makeheaders compatible file' + ), + 'q' => array( + 'type' => self::OPT_FLAG, + 'arg' => 'quiet', + 'message' => '(Quiet) Don\'t print the report file.' + ), + 's' => array( + 'type' => self::OPT_FLAG, + 'arg' => 'statistics', + 'message' => 'Print parser stats to standard output.' + ), + 'x' => array( + 'type' => self::OPT_FLAG, + 'arg' => 'version', + 'message' => 'Print the version number.' + ) + ); + + private $basisflag = 0; + private $compress = 0; + private $rpflag = 0; + private $mhflag = 0; + private $quiet = 0; + private $statistics = 0; + private $version = 0; + private $size; + /** + * Process a flag command line argument. + * @param int + * @param array + * @return int + */ + function handleflags($i, $argv) + { + if (!isset($argv[1]) || !isset(self::$options[$argv[$i][1]])) { + throw new Exception('Command line syntax error: undefined option "' . $argv[$i] . '"'); + } + $v = self::$options[$argv[$i][1]] == '-'; + if (self::$options[$argv[$i][1]]['type'] == self::OPT_FLAG) { + $this->{self::$options[$argv[$i][1]]['arg']} = 1; + } elseif (self::$options[$argv[$i][1]]['type'] == self::OPT_FFLAG) { + $this->{self::$options[$argv[$i][1]]['arg']}($v); + } elseif (self::$options[$argv[$i][1]]['type'] == self::OPT_FSTR) { + $this->{self::$options[$argv[$i][1]]['arg']}(substr($v, 2)); + } else { + throw new Exception('Command line syntax error: missing argument on switch: "' . $argv[$i] . '"'); + } + return 0; + } + + /** + * Process a command line switch which has an argument. + * @param int + * @param array + * @param array + * @return int + */ + function handleswitch($i, $argv) + { + $lv = 0; + $dv = 0.0; + $sv = $end = $cp = ''; + $j; // int + $errcnt = 0; + $cp = strstr($argv[$i],'='); + if (!$cp) { + throw new Exception('INTERNAL ERROR: handleswitch passed bad argument, no "=" in arg'); + } + $argv[$i] = substr($argv[$i], 0, strlen($argv[$i]) - strlen($cp)); + if (!isset(self::$options[$argv[$i]])) { + throw new Exception('Command line syntax error: undefined option "' . $argv[$i] . + $cp . '"'); + } + $cp = substr($cp, 1); + switch (self::$options[$argv[$i]]['type']) { + case self::OPT_FLAG: + case self::OPT_FFLAG: + throw new Exception('Command line syntax error: option requires an argument "' . + $argv[$i] . '=' . $cp . '"'); + case self::OPT_DBL: + case self::OPT_FDBL: + $dv = (double) $cp; + break; + case self::OPT_INT: + case self::OPT_FINT: + $lv = (int) $cp; + break; + case self::OPT_STR: + case self::OPT_FSTR: + $sv = $cp; + break; + } + switch(self::$options[$argv[$i]]['type']) { + case self::OPT_FLAG: + case self::OPT_FFLAG: + break; + case self::OPT_DBL: + $this->{self::$options[$argv[$i]]['arg']} = $dv; + break; + case self::OPT_FDBL: + $this->{self::$options[$argv[$i]]['arg']}($dv); + break; + case self::OPT_INT: + $this->{self::$options[$argv[$i]]['arg']} = $lv; + break; + case self::OPT_FINT: + $this->{self::$options[$argv[$i]]['arg']}($lv); + break; + case self::OPT_STR: + $this->{self::$options[$argv[$i]]['arg']} = $sv; + break; + case self::OPT_FSTR: + $this->{self::$options[$argv[$i]]['arg']}($sv); + break; + } + return 0; + } + + /** + * @param array arguments + * @param array valid options + * @return int + */ + function OptInit($a) + { + $errcnt = 0; + $argv = $a; + try { + if (is_array($argv) && count($argv) && self::$options) { + for($i = 1; $i < count($argv); $i++) { + if ($argv[$i][0] == '+' || $argv[$i][0] == '-') { + $errcnt += $this->handleflags($i, $argv); + } elseif (strstr($argv[$i],'=')) { + $errcnt += $this->handleswitch($i, $argv); + } + } + } + } catch (Exception $e) { + OptPrint(); + echo $e->getMessage(); + exit(1); + } + return 0; + } + + /** + * Return the index of the N-th non-switch argument. Return -1 + * if N is out of range. + * @param int + * @return int + */ + private function argindex($n, $a) + { + $dashdash = 0; + if (!is_array($a) || !count($a)) { + return -1; + } + for ($i=1; $i < count($a); $i++) { + if ($dashdash || !($a[$i][0] == '-' || $a[$i][0] == '+' || + strchr($a[$i], '='))) { + if ($n == 0) { + return $i; + } + $n--; + } + if ($_SERVER['argv'][$i] == '--') { + $dashdash = 1; + } + } + return -1; + } + + /** + * Return the value of the non-option argument as indexed by $i + * + * @param int + * @param array the value of $argv + * @return 0|string + */ + private function OptArg($i, $a) + { + if (-1 == ($ind = $this->argindex($i, $a))) { + return 0; + } + return $a[$ind]; + } + + /** + * @return int number of arguments + */ + function OptNArgs($a) + { + $cnt = $dashdash = 0; + if (is_array($a) && count($a)) { + for($i = 1; $i < count($a); $i++) { + if ($dashdash || !($a[$i][0] == '-' || $a[$i][0] == '+' || + strchr($a[$i], '='))) { + $cnt++; + } + if ($a[$i] == "--") { + $dashdash = 1; + } + } + } + return $cnt; + } + + /** + * Print out command-line options + */ + function OptPrint() + { + $max = 0; + foreach (self::$options as $label => $info) { + $len = strlen($label) + 1; + switch ($info['type']) { + case self::OPT_FLAG: + case self::OPT_FFLAG: + break; + case self::OPT_INT: + case self::OPT_FINT: + $len += 9; /* length of "" */ + break; + case self::OPT_DBL: + case self::OPT_FDBL: + $len += 6; /* length of "" */ + break; + case self::OPT_STR: + case self::OPT_FSTR: + $len += 8; /* length of "" */ + break; + } + if ($len > $max) { + $max = $len; + } + } + foreach (self::$options as $label => $info) { + switch ($info['type']) { + case self::OPT_FLAG: + case self::OPT_FFLAG: + echo " -$label"; + echo str_repeat(' ', $max - strlen($label)); + echo " $info[message]\n"; + break; + case self::OPT_INT: + case self::OPT_FINT: + echo " $label=" . str_repeat(' ', $max - strlen($label) - 9); + echo " $info[message]\n"; + break; + case self::OPT_DBL: + case self::OPT_FDBL: + echo " $label=" . str_repeat(' ', $max - strlen($label) - 6); + echo " $info[message]\n"; + break; + case self::OPT_STR: + case self::OPT_FSTR: + echo " $label=" . str_repeat(' ', $max - strlen($label) - 8); + echo " $info[message]\n"; + break; + } + } + } + + /** + * This routine is called with the argument to each -D command-line option. + * Add the macro defined to the azDefine array. + * @param string + */ + private function handle_D_option($z) + { + if ($a = strstr($z, '=')) { + $z = substr($a, 1); // strip first = + } + $this->azDefine[] = $z; + } + + /**************** From the file "main.c" ************************************/ +/* +** Main program file for the LEMON parser generator. +*/ + + + /* The main program. Parse the command line and do it... */ + function main() + { + $lem = new PHP_ParserGenerator_Data; + + $this->OptInit($_SERVER['argv']); + if ($this->version) { + echo "Lemon version 1.0/PHP_ParserGenerator port version 0.1.5\n"; + exit(0); + } + if ($this->OptNArgs($_SERVER['argv']) != 1) { + echo "Exactly one filename argument is required.\n"; + exit(1); + } + $lem->errorcnt = 0; + + /* Initialize the machine */ + $lem->argv0 = $_SERVER['argv'][0]; + $lem->filename = $this->OptArg(0, $_SERVER['argv']); + $a = pathinfo($lem->filename); + if (isset($a['extension'])) { + $ext = '.' . $a['extension']; + $lem->filenosuffix = substr($lem->filename, 0, strlen($lem->filename) - strlen($ext)); + } else { + $lem->filenosuffix = $lem->filename; + } + $lem->basisflag = $this->basisflag; + $lem->has_fallback = 0; + $lem->nconflict = 0; + $lem->name = $lem->include_code = $lem->include_classcode = $lem->arg = + $lem->tokentype = $lem->start = 0; + $lem->vartype = 0; + $lem->stacksize = 0; + $lem->error = $lem->overflow = $lem->failure = $lem->accept = $lem->tokendest = + $lem->tokenprefix = $lem->outname = $lem->extracode = 0; + $lem->vardest = 0; + $lem->tablesize = 0; + PHP_ParserGenerator_Symbol::Symbol_new("$"); + $lem->errsym = PHP_ParserGenerator_Symbol::Symbol_new("error"); + + /* Parse the input file */ + $parser = new PHP_ParserGenerator_Parser($this); + $parser->Parse($lem); + if ($lem->errorcnt) { + exit($lem->errorcnt); + } + if ($lem->rule === 0) { + printf("Empty grammar.\n"); + exit(1); + } + + /* Count and index the symbols of the grammar */ + $lem->nsymbol = PHP_ParserGenerator_Symbol::Symbol_count(); + PHP_ParserGenerator_Symbol::Symbol_new("{default}"); + $lem->symbols = PHP_ParserGenerator_Symbol::Symbol_arrayof(); + for ($i = 0; $i <= $lem->nsymbol; $i++) { + $lem->symbols[$i]->index = $i; + } + usort($lem->symbols, array('PHP_ParserGenerator_Symbol', 'sortSymbols')); + for ($i = 0; $i <= $lem->nsymbol; $i++) { + $lem->symbols[$i]->index = $i; + } + // find the first lower-case symbol + for($i = 1; ord($lem->symbols[$i]->name[0]) < ord ('Z'); $i++); + $lem->nterminal = $i; + + /* Generate a reprint of the grammar, if requested on the command line */ + if ($this->rpflag) { + $this->Reprint(); + } else { + /* Initialize the size for all follow and first sets */ + $this->SetSize($lem->nterminal); + + /* Find the precedence for every production rule (that has one) */ + $lem->FindRulePrecedences(); + + /* Compute the lambda-nonterminals and the first-sets for every + ** nonterminal */ + $lem->FindFirstSets(); + + /* Compute all LR(0) states. Also record follow-set propagation + ** links so that the follow-set can be computed later */ + $lem->nstate = 0; + $lem->FindStates(); + $lem->sorted = PHP_ParserGenerator_State::State_arrayof(); + + /* Tie up loose ends on the propagation links */ + $lem->FindLinks(); + + /* Compute the follow set of every reducible configuration */ + $lem->FindFollowSets(); + + /* Compute the action tables */ + $lem->FindActions(); + + /* Compress the action tables */ + if ($this->compress===0) { + $lem->CompressTables(); + } + + /* Reorder and renumber the states so that states with fewer choices + ** occur at the end. */ + $lem->ResortStates(); + + /* Generate a report of the parser generated. (the "y.output" file) */ + if (!$this->quiet) { + $lem->ReportOutput(); + } + + /* Generate the source code for the parser */ + $lem->ReportTable($this->mhflag); + + /* Produce a header file for use by the scanner. (This step is + ** omitted if the "-m" option is used because makeheaders will + ** generate the file for us.) */ +// if (!$this->mhflag) { +// $this->ReportHeader(); +// } + } + if ($this->statistics) { + printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", + $lem->nterminal, $lem->nsymbol - $lem->nterminal, $lem->nrule); + printf(" %d states, %d parser table entries, %d conflicts\n", + $lem->nstate, $lem->tablesize, $lem->nconflict); + } + if ($lem->nconflict) { + printf("%d parsing conflicts.\n", $lem->nconflict); + } + exit($lem->errorcnt + $lem->nconflict); + return ($lem->errorcnt + $lem->nconflict); + } + + function SetSize($n) + { + $this->size = $n + 1; + } + + /** + * Merge in a merge sort for a linked list + * Inputs: + * - a: A sorted, null-terminated linked list. (May be null). + * - b: A sorted, null-terminated linked list. (May be null). + * - cmp: A pointer to the comparison function. + * - offset: Offset in the structure to the "next" field. + * + * Return Value: + * A pointer to the head of a sorted list containing the elements + * of both a and b. + * + * Side effects: + * The "next" pointers for elements in the lists a and b are + * changed. + */ + static function merge($a, $b, $cmp, $offset) + { + if($a === 0) { + $head = $b; + } elseif ($b === 0) { + $head = $a; + } else { + if (call_user_func($cmp, $a, $b) < 0) { + $ptr = $a; + $a = $a->$offset; + } else { + $ptr = $b; + $b = $b->$offset; + } + $head = $ptr; + while ($a && $b) { + if (call_user_func($cmp, $a, $b) < 0) { + $ptr->$offset = $a; + $ptr = $a; + $a = $a->$offset; + } else { + $ptr->$offset = $b; + $ptr = $b; + $b = $b->$offset; + } + } + if ($a !== 0) { + $ptr->$offset = $a; + } else { + $ptr->$offset = $b; + } + } + return $head; + } + + /* + ** Inputs: + ** list: Pointer to a singly-linked list of structures. + ** next: Pointer to pointer to the second element of the list. + ** cmp: A comparison function. + ** + ** Return Value: + ** A pointer to the head of a sorted list containing the elements + ** orginally in list. + ** + ** Side effects: + ** The "next" pointers for elements in list are changed. + */ + #define LISTSIZE 30 + static function msort($list, $next, $cmp) + { + if ($list === 0) { + return $list; + } + if ($list->$next === 0) { + return $list; + } + $set = array_fill(0, 30, 0); + while ($list) { + $ep = $list; + $list = $list->$next; + $ep->$next = 0; + for ($i = 0; $i < 29 && $set[$i] !== 0; $i++) { + $ep = self::merge($ep, $set[$i], $cmp, $next); + $set[$i] = 0; + } + $set[$i] = $ep; + } + $ep = 0; + for ($i = 0; $i < 30; $i++) { + if ($set[$i] !== 0) { + $ep = self::merge($ep, $set[$i], $cmp, $next); + } + } + return $ep; + } + + /* Find a good place to break "msg" so that its length is at least "min" + ** but no more than "max". Make the point as close to max as possible. + */ + static function findbreak($msg, $min, $max) + { + if ($min >= strlen($msg)) { + return strlen($msg); + } + for ($i = $spot = $min; $i <= $max && $i < strlen($msg); $i++) { + $c = $msg[$i]; + if ($c == '-' && $i < $max - 1) { + $spot = $i + 1; + } + if ($c == ' ') { + $spot = $i; + } + } + return $spot; + } + + static function ErrorMsg($filename, $lineno, $format) + { + /* Prepare a prefix to be prepended to every output line */ + if ($lineno > 0) { + $prefix = sprintf("%20s:%d: ", $filename, $lineno); + } else { + $prefix = sprintf("%20s: ", $filename); + } + $prefixsize = strlen($prefix); + $availablewidth = 79 - $prefixsize; + + /* Generate the error message */ + $ap = func_get_args(); + array_shift($ap); // $filename + array_shift($ap); // $lineno + array_shift($ap); // $format + $errmsg = vsprintf($format, $ap); + $linewidth = strlen($errmsg); + /* Remove trailing "\n"s from the error message. */ + while ($linewidth > 0 && in_array($errmsg[$linewidth-1], array("\n", "\r"), true)) { + --$linewidth; + $errmsg = substr($errmsg, 0, strlen($errmsg) - 1); + } + + /* Print the error message */ + $base = 0; + $errmsg = str_replace(array("\r", "\n", "\t"), array(' ', ' ', ' '), $errmsg); + while (strlen($errmsg)) { + $end = $restart = self::findbreak($errmsg, 0, $availablewidth); + if (strlen($errmsg) <= 79 && $end < strlen($errmsg) && $end <= 79) { + $end = $restart = strlen($errmsg); + } + while (isset($errmsg[$restart]) && $errmsg[$restart] == ' ') { + $restart++; + } + printf("%s%.${end}s\n", $prefix, $errmsg); + $errmsg = substr($errmsg, $restart); + } + } + + /** + * Duplicate the input file without comments and without actions + * on rules + */ + function Reprint() + { + printf("// Reprint of input file \"%s\".\n// Symbols:\n", $this->filename); + $maxlen = 10; + for ($i = 0; $i < $this->nsymbol; $i++) { + $sp = $this->symbols[$i]; + $len = strlen($sp->name); + if ($len > $maxlen ) { + $maxlen = $len; + } + } + $ncolumns = 76 / ($maxlen + 5); + if ($ncolumns < 1) { + $ncolumns = 1; + } + $skip = ($this->nsymbol + $ncolumns - 1) / $ncolumns; + for ($i = 0; $i < $skip; $i++) { + print "//"; + for ($j = $i; $j < $this->nsymbol; $j += $skip) { + $sp = $this->symbols[$j]; + //assert( sp->index==j ); + printf(" %3d %-${maxlen}.${maxlen}s", $j, $sp->name); + } + print "\n"; + } + for ($rp = $this->rule; $rp; $rp = $rp->next) { + printf("%s", $rp->lhs->name); +/* if ($rp->lhsalias) { + printf("(%s)", $rp->lhsalias); + }*/ + print " ::="; + for ($i = 0; $i < $rp->nrhs; $i++) { + $sp = $rp->rhs[$i]; + printf(" %s", $sp->name); + if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + for ($j = 1; $j < $sp->nsubsym; $j++) { + printf("|%s", $sp->subsym[$j]->name); + } + } +/* if ($rp->rhsalias[$i]) { + printf("(%s)", $rp->rhsalias[$i]); + }*/ + } + print "."; + if ($rp->precsym) { + printf(" [%s]", $rp->precsym->name); + } +/* if ($rp->code) { + print "\n " . $rp->code); + }*/ + print "\n"; + } + } +} +//$a = new PHP_ParserGenerator; +//$_SERVER['argv'] = array('lemon', '-s', '/development/lemon/PHP_Parser.y'); +//$_SERVER['argv'] = array('lemon', '-s', '/development/File_ChessPGN/ChessPGN/Parser.y'); +//$a->main(); diff --git a/libs/lexer/ParserGenerator/Action.php b/libs/lexer/ParserGenerator/Action.php new file mode 100644 index 00000000..bc588d0e --- /dev/null +++ b/libs/lexer/ParserGenerator/Action.php @@ -0,0 +1,240 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_ParserGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Action.php,v 1.2 2007/03/04 17:52:05 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** + * Every shift or reduce operation is stored as one of the following objects. + * + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version 0.1.5 + * @since Class available since Release 0.1.0 + */ +class PHP_ParserGenerator_Action { + const SHIFT = 1, + ACCEPT = 2, + REDUCE = 3, + ERROR = 4, + /** + * Was a reduce, but part of a conflict + */ + CONFLICT = 5, + /** + * Was a shift. Precedence resolved conflict + */ + SH_RESOLVED = 6, + /** + * Was a reduce. Precedence resolved conflict + */ + RD_RESOLVED = 7, + /** + * Deleted by compression + * @see PHP_ParserGenerator::CompressTables() + */ + NOT_USED = 8; + /** + * The look-ahead symbol that triggers this action + * @var PHP_ParserGenerator_Symbol + */ + public $sp; /* The look-ahead symbol */ + /** + * This defines the kind of action, and must be one + * of the class constants. + * + * - {@link PHP_ParserGenerator_Action::SHIFT} + * - {@link PHP_ParserGenerator_Action::ACCEPT} + * - {@link PHP_ParserGenerator_Action::REDUCE} + * - {@link PHP_ParserGenerator_Action::ERROR} + * - {@link PHP_ParserGenerator_Action::CONFLICT} + * - {@link PHP_ParserGenerator_Action::SH_RESOLVED} + * - {@link PHP_ParserGenerator_Action:: RD_RESOLVED} + * - {@link PHP_ParserGenerator_Action::NOT_USED} + */ + public $type; + /** + * The new state, if this is a shift, + * the parser rule index, if this is a reduce. + * + * @var PHP_ParserGenerator_State|PHP_ParserGenerator_Rule + */ + public $x; + /** + * The next action for this state. + * @var PHP_ParserGenerator_Action + */ + public $next; + + /** + * Compare two actions + * + * This is used by {@link Action_sort()} to compare actions + */ + static function actioncmp(PHP_ParserGenerator_Action $ap1, + PHP_ParserGenerator_Action $ap2) + { + $rc = $ap1->sp->index - $ap2->sp->index; + if ($rc === 0) { + $rc = $ap1->type - $ap2->type; + } + if ($rc === 0) { + if ($ap1->type == self::SHIFT) { + if ($ap1->x->statenum != $ap2->x->statenum) { + throw new Exception('Shift conflict: ' . $ap1->sp->name . + ' shifts both to state ' . $ap1->x->statenum . ' (rule ' . + $ap1->x->cfp->rp->lhs->name . ' on line ' . + $ap1->x->cfp->rp->ruleline . ') and to state ' . + $ap2->x->statenum . ' (rule ' . + $ap2->x->cfp->rp->lhs->name . ' on line ' . + $ap2->x->cfp->rp->ruleline . ')'); + } + } + if ($ap1->type != self::REDUCE && + $ap1->type != self::RD_RESOLVED && + $ap1->type != self::CONFLICT) { + throw new Exception('action has not been processed: ' . + $ap1->sp->name . ' on line ' . $ap1->x->cfp->rp->ruleline . + ', rule ' . $ap1->x->cfp->rp->lhs->name); + } + if ($ap2->type != self::REDUCE && + $ap2->type != self::RD_RESOLVED && + $ap2->type != self::CONFLICT) { + throw new Exception('action has not been processed: ' . + $ap2->sp->name . ' on line ' . $ap2->x->cfp->rp->ruleline . + ', rule ' . $ap2->x->cfp->rp->lhs->name); + } + $rc = $ap1->x->index - $ap2->x->index; + } + return $rc; + } + + function display($processed = false) + { + $map = array( + self::ACCEPT => 'ACCEPT', + self::CONFLICT => 'CONFLICT', + self::REDUCE => 'REDUCE', + self::SHIFT => 'SHIFT' + ); + echo $map[$this->type] . ' for ' . $this->sp->name; + if ($this->type == self::REDUCE) { + echo ' - rule ' . $this->x->lhs->name . "
"; + } elseif ($this->type == self::SHIFT) { + echo ' - state ' . $this->x->statenum . ', basis ' . $this->x->cfp->rp->lhs->name . "
"; + } else { + echo "
"; + } + } + + /** + * create linked list of PHP_ParserGenerator_Actions + * + * @param PHP_ParserGenerator_Action|null + * @param int one of the class constants from PHP_ParserGenerator_Action + * @param PHP_ParserGenerator_Symbol + * @param PHP_ParserGenerator_State|PHP_ParserGenerator_Rule + */ + static function Action_add(&$app, $type, PHP_ParserGenerator_Symbol $sp, $arg) + { + $new = new PHP_ParserGenerator_Action; + $new->next = $app; + $app = $new; + $new->type = $type; + $new->sp = $sp; + $new->x = $arg; + echo ' Adding '; + $new->display(); + } + + /** + * Sort parser actions + * @see PHP_ParserGenerator_Data::FindActions() + */ + static function Action_sort(PHP_ParserGenerator_Action $ap) + { + $ap = PHP_ParserGenerator::msort($ap, 'next', array('PHP_ParserGenerator_Action', 'actioncmp')); + return $ap; + } + + /** + * Print an action to the given file descriptor. Return FALSE if + * nothing was actually printed. + * @see PHP_ParserGenerator_Data::ReportOutput() + */ + function PrintAction($fp, $indent) + { + if (!$fp) { + $fp = STDOUT; + } + $result = 1; + switch ($this->type) + { + case self::SHIFT: + fprintf($fp, "%${indent}s shift %d", $this->sp->name, $this->x->statenum); + break; + case self::REDUCE: + fprintf($fp, "%${indent}s reduce %d", $this->sp->name, $this->x->index); + break; + case self::ACCEPT: + fprintf($fp, "%${indent}s accept", $this->sp->name); + break; + case self::ERROR: + fprintf($fp, "%${indent}s error", $this->sp->name); + break; + case self::CONFLICT: + fprintf($fp, "%${indent}s reduce %-3d ** Parsing conflict **", $this->sp->name, $this->x->index); + break; + case self::SH_RESOLVED: + case self::RD_RESOLVED: + case self::NOT_USED: + $result = 0; + break; + } + return $result; + } +} +?> diff --git a/libs/lexer/ParserGenerator/ActionTable.php b/libs/lexer/ParserGenerator/ActionTable.php new file mode 100644 index 00000000..1412001a --- /dev/null +++ b/libs/lexer/ParserGenerator/ActionTable.php @@ -0,0 +1,293 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_ParserGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: ActionTable.php,v 1.1 2006/07/18 00:53:10 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** + * The state of the yy_action table under construction is an instance of + * the following structure + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version 0.1.5 + * @since Class available since Release 0.1.0 + */ +class PHP_ParserGenerator_ActionTable +{ + /** + * Number of used slots in {@link $aAction} + * @var int + */ + public $nAction = 0; + /** + * The $yy_action table under construction. + * + * Each entry is of format: + * + * array( + * 'lookahead' => -1, // Value of the lookahead token (symbol index) + * 'action' => -1 // Action to take on the given lookahead (action index) + * ); + * + * @see PHP_ParserGenerator_Data::compute_action() + * @var array + */ + public $aAction = + array(array( + 'lookahead' => -1, + 'action' => -1 + )); + /** + * A single new transaction set. + * + * @see $aAction format of the internal array is described here + * @var array + */ + public $aLookahead = + array(array( + 'lookahead' => 0, + 'action' => 0 + )); + /** + * The smallest (minimum) value of any lookahead token in {@link $aLookahead} + * + * The lowest non-terminal is always introduced earlier in the parser file, + * and is therefore a more significant token. + * @var int + */ + public $mnLookahead = 0; + /** + * The action associated with the smallest lookahead token. + * @see $mnLookahead + * @var int + */ + public $mnAction = 0; + /** + * The largest (maximum) value of any lookahead token in {@link $aLookahead} + * @var int + */ + public $mxLookahead = 0; + /** + * The number of slots used in {@link $aLookahead}. + * + * This is the same as count($aLookahead), but there was no pressing reason + * to change this when porting from C. + * @see $mnLookahead + * @var int + */ + public $nLookahead = 0; + + /** + * Add a new action to the current transaction set + * @param int + * @param int + */ + function acttab_action($lookahead, $action) + { + if ($this->nLookahead === 0) { + $this->aLookahead = array(); + $this->mxLookahead = $lookahead; + $this->mnLookahead = $lookahead; + $this->mnAction = $action; + } else { + if ($this->mxLookahead < $lookahead) { + $this->mxLookahead = $lookahead; + } + if ($this->mnLookahead > $lookahead) { + $this->mnLookahead = $lookahead; + $this->mnAction = $action; + } + } + $this->aLookahead[$this->nLookahead] = array( + 'lookahead' => $lookahead, + 'action' => $action); + $this->nLookahead++; + } + + /** + * Add the transaction set built up with prior calls to acttab_action() + * into the current action table. Then reset the transaction set back + * to an empty set in preparation for a new round of acttab_action() calls. + * + * Return the offset into the action table of the new transaction. + * @return int Return the offset that should be added to the lookahead in + * order to get the index into $yy_action of the action. This will be used + * in generation of $yy_ofst tables (reduce and shift) + * @throws Exception + */ + function acttab_insert() + { + if ($this->nLookahead <= 0) { + throw new Exception('nLookahead is not set up?'); + } + + /* Scan the existing action table looking for an offset where we can + ** insert the current transaction set. Fall out of the loop when that + ** offset is found. In the worst case, we fall out of the loop when + ** i reaches $this->nAction, which means we append the new transaction set. + ** + ** i is the index in $this->aAction[] where $this->mnLookahead is inserted. + */ + for ($i = 0; $i < $this->nAction + $this->mnLookahead; $i++) { + if (!isset($this->aAction[$i])) { + $this->aAction[$i] = array( + 'lookahead' => -1, + 'action' => -1, + ); + } + if ($this->aAction[$i]['lookahead'] < 0) { + for ($j = 0; $j < $this->nLookahead; $j++) { + if (!isset($this->aLookahead[$j])) { + $this->aLookahead[$j] = array( + 'lookahead' => 0, + 'action' => 0, + ); + } + $k = $this->aLookahead[$j]['lookahead'] - + $this->mnLookahead + $i; + if ($k < 0) { + break; + } + if (!isset($this->aAction[$k])) { + $this->aAction[$k] = array( + 'lookahead' => -1, + 'action' => -1, + ); + } + if ($this->aAction[$k]['lookahead'] >= 0) { + break; + } + } + if ($j < $this->nLookahead ) { + continue; + } + for ($j = 0; $j < $this->nAction; $j++) { + if (!isset($this->aAction[$j])) { + $this->aAction[$j] = array( + 'lookahead' => -1, + 'action' => -1, + ); + } + if ($this->aAction[$j]['lookahead'] == $j + + $this->mnLookahead - $i) { + break; + } + } + if ($j == $this->nAction) { + break; /* Fits in empty slots */ + } + } elseif ($this->aAction[$i]['lookahead'] == $this->mnLookahead) { + if ($this->aAction[$i]['action'] != $this->mnAction) { + continue; + } + for ($j = 0; $j < $this->nLookahead; $j++) { + $k = $this->aLookahead[$j]['lookahead'] - + $this->mnLookahead + $i; + if ($k < 0 || $k >= $this->nAction) { + break; + } + if (!isset($this->aAction[$k])) { + $this->aAction[$k] = array( + 'lookahead' => -1, + 'action' => -1, + ); + } + if ($this->aLookahead[$j]['lookahead'] != + $this->aAction[$k]['lookahead']) { + break; + } + if ($this->aLookahead[$j]['action'] != + $this->aAction[$k]['action']) { + break; + } + } + if ($j < $this->nLookahead) { + continue; + } + $n = 0; + for ($j = 0; $j < $this->nAction; $j++) { + if (!isset($this->aAction[$j])) { + $this->aAction[$j] = array( + 'lookahead' => -1, + 'action' => -1, + ); + } + if ($this->aAction[$j]['lookahead'] < 0) { + continue; + } + if ($this->aAction[$j]['lookahead'] == $j + + $this->mnLookahead - $i) { + $n++; + } + } + if ($n == $this->nLookahead) { + break; /* Same as a prior transaction set */ + } + } + } + /* Insert transaction set at index i. */ + for ($j = 0; $j < $this->nLookahead; $j++) { + if (!isset($this->aLookahead[$j])) { + $this->aLookahead[$j] = array( + 'lookahead' => 0, + 'action' => 0, + ); + } + $k = $this->aLookahead[$j]['lookahead'] - $this->mnLookahead + $i; + $this->aAction[$k] = $this->aLookahead[$j]; + if ($k >= $this->nAction) { + $this->nAction = $k + 1; + } + } + $this->nLookahead = 0; + $this->aLookahead = array(); + + /* Return the offset that is added to the lookahead in order to get the + ** index into yy_action of the action */ + return $i - $this->mnLookahead; + } +} +?> \ No newline at end of file diff --git a/libs/lexer/ParserGenerator/Config.php b/libs/lexer/ParserGenerator/Config.php new file mode 100644 index 00000000..242ed9e4 --- /dev/null +++ b/libs/lexer/ParserGenerator/Config.php @@ -0,0 +1,570 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_ParserGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Config.php,v 1.1 2006/07/18 00:53:10 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** +/** A configuration is a production rule of the grammar together with + * a mark (dot) showing how much of that rule has been processed so far. + * + * Configurations also contain a follow-set which is a list of terminal + * symbols which are allowed to immediately follow the end of the rule. + * Every configuration is recorded as an instance of the following class. + * + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version 0.1.5 + * @since Class available since Release 0.1.0 + */ +class PHP_ParserGenerator_Config { + const COMPLETE = 1; + const INCOMPLETE = 2; + /** + * The parser rule upon with the configuration is based. + * + * A parser rule is something like: + *
+     * blah ::= FOO bar.
+     * 
+ * @var PHP_ParserGenerator_Rule + */ + public $rp; + /** + * The parse point. + * + * This is the index into the right-hand side of a rule that is + * represented by this configuration. In other words, possible + * dots for this rule: + * + *
+     * blah ::= FOO bar.
+     * 
+ * + * are (represented by "[here]"): + * + *
+     * blah ::= [here] FOO bar.
+     * blah ::= FOO [here] bar.
+     * blah ::= FOO bar [here].
+     * 
+ * @var int + */ + public $dot; + /** + * Follow-set for this configuration only + * + * This is the list of terminals and non-terminals that + * can follow this configuration. + * @var array + */ + public $fws; + /** + * Follow-set forward propagation links. + * @var PHP_ParserGenerator_PropagationLink + */ + public $fplp; + /** + * Follow-set backwards propagation links + * @var PHP_ParserGenerator_PropagationLink + */ + public $bplp; + /** + * State that contains this configuration + * @var PHP_ParserGenerator_State + */ + public $stp; + /* enum { + COMPLETE, /* The status is used during followset and + INCOMPLETE /* shift computations + } */ + /** + * Status during followset and shift computations. + * + * One of PHP_ParserGenerator_Config::COMPLETE or + * PHP_ParserGenerator_Config::INCOMPLETE. + * @var int + */ + public $status; + /** + * Next configuration in the state. + * + * Index of next PHP_ParserGenerator_Config object. + * @var int + */ + public $next; + /** + * Index of the next basis configuration PHP_ParserGenerator_Config object + * @var int + */ + public $bp; + + /** + * Top of the list of configurations for the current state. + * @var PHP_ParserGenerator_Config + */ + static public $current; + /** + * Last on the list of configurations for the current state. + * @var PHP_ParserGenerator_Config + */ + static public $currentend; + + /** + * Top of the list of basis configurations for the current state. + * @var PHP_ParserGenerator_Config + */ + static public $basis; + /** + * Last on the list of basis configurations for the current state. + * @var PHP_ParserGenerator_Config + */ + static public $basisend; + + /** + * Associative array representation of the linked list of configurations + * found in {@link $current} + * + * @var array + */ + static public $x4a = array(); + + /** + * Return a pointer to a new configuration + * @return PHP_ParserGenerator_Config + */ + private static function newconfig() + { + return new PHP_ParserGenerator_Config; + } + + /** + * Display the current configuration for the .out file + * + * @param PHP_ParserGenerator_Config $cfp + * @see PHP_ParserGenerator_Data::ReportOutput() + */ + static function Configshow(PHP_ParserGenerator_Config $cfp) + { + $fp = fopen('php://output', 'w'); + while ($cfp) { + if ($cfp->dot == $cfp->rp->nrhs) { + $buf = sprintf('(%d)', $cfp->rp->index); + fprintf($fp, ' %5s ', $buf); + } else { + fwrite($fp,' '); + } + $cfp->ConfigPrint($fp); + fwrite($fp, "\n"); + if (0) { + //SetPrint(fp,cfp->fws,$this); + //PlinkPrint(fp,cfp->fplp,"To "); + //PlinkPrint(fp,cfp->bplp,"From"); + } + $cfp = $cfp->next; + } + fwrite($fp, "\n"); + fclose($fp); + } + + /** + * Initialize the configuration list builder for a new state. + */ + static function Configlist_init() + { + self::$current = 0; + self::$currentend = &self::$current; + self::$basis = 0; + self::$basisend = &self::$basis; + self::$x4a = array(); + } + + /** + * Remove all data from the table. + * + * Pass each data to the function $f as it is removed if + * $f is a valid callback. + * @param callback|null + * @see Configtable_clear() + */ + static function Configtable_reset($f) + { + self::$current = 0; + self::$currentend = &self::$current; + self::$basis = 0; + self::$basisend = &self::$basis; + self::Configtable_clear(0); + } + + /** + * Remove all data from the associative array representation + * of configurations. + * + * Pass each data to the function $f as it is removed if + * $f is a valid callback. + * @param callback|null + */ + static function Configtable_clear($f) + { + if (!count(self::$x4a)) { + return; + } + if ($f) { + for ($i = 0; $i < count(self::$x4a); $i++) { + call_user_func($f, self::$x4a[$i]->data); + } + } + self::$x4a = array(); + } + + /** + * Reset the configuration list builder for a new state. + * @see Configtable_clear() + */ + static function Configlist_reset() + { + self::Configtable_clear(0); + } + + /** + * Add another configuration to the configuration list for this parser state. + * @param PHP_ParserGenerator_Rule the rule + * @param int Index into the right-hand side of the rule where the dot goes + * @return PHP_ParserGenerator_Config + */ + static function Configlist_add($rp, $dot) + { + $model = new PHP_ParserGenerator_Config; + $model->rp = $rp; + $model->dot = $dot; + $cfp = self::Configtable_find($model); + if ($cfp === 0) { + $cfp = self::newconfig(); + $cfp->rp = $rp; + $cfp->dot = $dot; + $cfp->fws = array(); + $cfp->stp = 0; + $cfp->fplp = $cfp->bplp = 0; + $cfp->next = 0; + $cfp->bp = 0; + self::$currentend = $cfp; + self::$currentend = &$cfp->next; + self::Configtable_insert($cfp); + } + return $cfp; + } + + /** + * Add a basis configuration to the configuration list for this parser state. + * + * Basis configurations are the root for a configuration. This method also + * inserts the configuration into the regular list of configurations for this + * reason. + * @param PHP_ParserGenerator_Rule the rule + * @param int Index into the right-hand side of the rule where the dot goes + * @return PHP_ParserGenerator_Config + */ + static function Configlist_addbasis($rp, $dot) + { + $model = new PHP_ParserGenerator_Config; + $model->rp = $rp; + $model->dot = $dot; + $cfp = self::Configtable_find($model); + if ($cfp === 0) { + $cfp = self::newconfig(); + $cfp->rp = $rp; + $cfp->dot = $dot; + $cfp->fws = array(); + $cfp->stp = 0; + $cfp->fplp = $cfp->bplp = 0; + $cfp->next = 0; + $cfp->bp = 0; + self::$currentend = $cfp; + self::$currentend = &$cfp->next; + self::$basisend = $cfp; + self::$basisend = &$cfp->bp; + self::Configtable_insert($cfp); + } + return $cfp; + } + + /** + * Compute the closure of the configuration list. + * + * This calculates all of the possible continuations of + * each configuration, ensuring that each state accounts + * for every configuration that could arrive at that state. + */ + static function Configlist_closure(PHP_ParserGenerator_Data $lemp) + { + for ($cfp = self::$current; $cfp; $cfp = $cfp->next) { + $rp = $cfp->rp; + $dot = $cfp->dot; + if ($dot >= $rp->nrhs) { + continue; + } + $sp = $rp->rhs[$dot]; + if ($sp->type == PHP_ParserGenerator_Symbol::NONTERMINAL) { + if ($sp->rule === 0 && $sp !== $lemp->errsym) { + PHP_ParserGenerator::ErrorMsg($lemp->filename, $rp->line, + "Nonterminal \"%s\" has no rules.", $sp->name); + $lemp->errorcnt++; + } + for ($newrp = $sp->rule; $newrp; $newrp = $newrp->nextlhs) { + $newcfp = self::Configlist_add($newrp, 0); + for ($i = $dot + 1; $i < $rp->nrhs; $i++) { + $xsp = $rp->rhs[$i]; + if ($xsp->type == PHP_ParserGenerator_Symbol::TERMINAL) { + $newcfp->fws[$xsp->index] = 1; + break; + } elseif ($xsp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + for ($k = 0; $k < $xsp->nsubsym; $k++) { + $newcfp->fws[$xsp->subsym[$k]->index] = 1; + } + break; + } else { + $a = array_diff_key($xsp->firstset, $newcfp->fws); + $newcfp->fws += $a; + if ($xsp->lambda === false) { + break; + } + } + } + if ($i == $rp->nrhs) { + PHP_ParserGenerator_PropagationLink::Plink_add($cfp->fplp, $newcfp); + } + } + } + } + } + + /** + * Sort the configuration list + * @uses Configcmp() + */ + static function Configlist_sort() + { + $a = 0; + //self::Configshow(self::$current); + self::$current = PHP_ParserGenerator::msort(self::$current,'next', array('PHP_ParserGenerator_Config', 'Configcmp')); + //self::Configshow(self::$current); + self::$currentend = &$a; + self::$currentend = 0; + } + + /** + * Sort the configuration list + * @uses Configcmp + */ + static function Configlist_sortbasis() + { + $a = 0; + self::$basis = PHP_ParserGenerator::msort(self::$current,'bp', array('PHP_ParserGenerator_Config', 'Configcmp')); + self::$basisend = &$a; + self::$basisend = 0; + } + + /** + * Return a pointer to the head of the configuration list and + * reset the list + * @see $current + * @return PHP_ParserGenerator_Config + */ + static function Configlist_return() + { + $old = self::$current; + self::$current = 0; + self::$currentend = &self::$current; + return $old; + } + + /** + * Return a pointer to the head of the basis list and + * reset the list + * @see $basis + * @return PHP_ParserGenerator_Config + */ + static function Configlist_basis() + { + $old = self::$basis; + self::$basis = 0; + self::$basisend = &self::$basis; + return $old; + } + + /** + * Free all elements of the given configuration list + * @param PHP_ParserGenerator_Config + */ + static function Configlist_eat($cfp) + { + for(; $cfp; $cfp = $nextcfp){ + $nextcfp = $cfp->next; + if ($cfp->fplp !=0) { + throw new Exception('fplp of configuration non-zero?'); + } + if ($cfp->bplp !=0) { + throw new Exception('bplp of configuration non-zero?'); + } + if ($cfp->fws) { + $cfp->fws = array(); + } + } + } + + /** + * Compare two configurations for sorting purposes. + * + * Configurations based on higher precedence rules + * (those earlier in the file) are chosen first. Two + * configurations that are the same rule are sorted by + * dot (see {@link $dot}), and those configurations + * with a dot closer to the left-hand side are chosen first. + * @param unknown_type $a + * @param unknown_type $b + * @return unknown + */ + static function Configcmp($a, $b) + { + $x = $a->rp->index - $b->rp->index; + if (!$x) { + $x = $a->dot - $b->dot; + } + return $x; + } + + /** + * Print out information on this configuration. + * + * @param resource $fp + * @see PHP_ParserGenerator_Data::ReportOutput() + */ + function ConfigPrint($fp) + { + $rp = $this->rp; + fprintf($fp, "%s ::=", $rp->lhs->name); + for ($i = 0; $i <= $rp->nrhs; $i++) { + if ($i === $this->dot) { + fwrite($fp,' *'); + } + if ($i === $rp->nrhs) { + break; + } + $sp = $rp->rhs[$i]; + fprintf($fp,' %s', $sp->name); + if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + for ($j = 1; $j < $sp->nsubsym; $j++) { + fprintf($fp, '|%s', $sp->subsym[$j]->name); + } + } + } + } + + /** + * Hash a configuration for the associative array {@link $x4a} + */ + private static function confighash(PHP_ParserGenerator_Config $a) + { + $h = 0; + $h = $h * 571 + $a->rp->index * 37 + $a->dot; + return $h; + } + + /** + * Insert a new record into the array. Return TRUE if successful. + * Prior data with the same key is NOT overwritten + */ + static function Configtable_insert(PHP_ParserGenerator_Config $data) + { + $h = self::confighash($data); + if (isset(self::$x4a[$h])) { + $np = self::$x4a[$h]; + } else { + $np = 0; + } + while ($np) { + if (self::Configcmp($np->data, $data) == 0) { + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + $np = $np->next; + } + /* Insert the new data */ + $np = array('data' => $data, 'next' => 0, 'from' => 0); + $np = new PHP_ParserGenerator_StateNode; + $np->data = $data; + if (isset(self::$x4a[$h])) { + self::$x4a[$h]->from = $np->next; + $np->next = self::$x4a[$h]; + } + $np->from = $np; + self::$x4a[$h] = $np; + return 1; + } + + /** + * Return a pointer to data assigned to the given key. Return NULL + * if no such key. + * @return PHP_ParserGenerator_Config|0 + */ + static function Configtable_find(PHP_ParserGenerator_Config $key) + { + $h = self::confighash($key); + if (!isset(self::$x4a[$h])) { + return 0; + } + $np = self::$x4a[$h]; + while ($np) { + if (self::Configcmp($np->data, $key) == 0) { + break; + } + $np = $np->next; + } + return $np ? $np->data : 0; + } +} +?> \ No newline at end of file diff --git a/libs/lexer/ParserGenerator/Data.php b/libs/lexer/ParserGenerator/Data.php new file mode 100644 index 00000000..8715cf77 --- /dev/null +++ b/libs/lexer/ParserGenerator/Data.php @@ -0,0 +1,1854 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_ParserGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Data.php,v 1.2 2007/03/04 17:52:05 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** +/** + * The state vector for the entire parser generator is recorded in + * this class. + * + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version 0.1.5 + * @since Class available since Release 0.1.0 + */ + +class PHP_ParserGenerator_Data +{ + /** + * Used for terminal and non-terminal offsets into the action table + * when their default should be used instead + */ + const NO_OFFSET = -2147483647; + /** + * Table of states sorted by state number + * @var array array of {@link PHP_ParserGenerator_State} objects + */ + public $sorted; + /** + * List of all rules + * @var PHP_ParserGenerator_Rule + */ + public $rule; + /** + * Number of states + * @var int + */ + public $nstate; + /** + * Number of rules + * @var int + */ + public $nrule; + /** + * Number of terminal and nonterminal symbols + * @var int + */ + public $nsymbol; + /** + * Number of terminal symbols (tokens) + * @var int + */ + public $nterminal; + /** + * Sorted array of pointers to symbols + * @var array array of {@link PHP_ParserGenerator_Symbol} objects + */ + public $symbols = array(); + /** + * Number of errors + * @var int + */ + public $errorcnt; + /** + * The error symbol + * @var PHP_ParserGenerator_Symbol + */ + public $errsym; + /** + * Name of the generated parser + * @var string + */ + public $name; + /** + * Unused relic from the C version + * + * Type of terminal symbols in the parser stack + * @var string + */ + public $tokentype; + /** + * Unused relic from the C version + * + * The default type of non-terminal symbols + * @var string + */ + public $vartype; + /** + * Name of the start symbol for the grammar + * @var string + */ + public $start; + /** + * Size of the parser stack + * + * This is 100 by default, but is set with the %stack_size directive + * @var int + */ + public $stacksize; + /** + * Code to put at the start of the parser file + * + * This is set by the %include directive + * @var string + */ + public $include_code; + /** + * Line number for start of include code + * @var int + */ + public $includeln; + /** + * Code to put in the parser class + * + * This is set by the %include_class directive + * @var string + */ + public $include_classcode; + /** + * Line number for start of include code + * @var int + */ + public $include_classln; + /** + * any extends/implements code + * + * This is set by the %declare_class directive + * @var string + */ + /** + * Line number for class declaration code + * @var int + */ + public $declare_classcode; + /** + * Line number for start of class declaration code + * @var int + */ + public $declare_classln; + /** + * Code to execute when a syntax error is seen + * + * This is set by the %syntax_error directive + * @var string + */ + public $error; + /** + * Line number for start of error code + * @var int + */ + public $errorln; + /** + * Code to execute on a stack overflow + * + * This is set by the %stack_overflow directive + */ + public $overflow; + /** + * Line number for start of overflow code + * @var int + */ + public $overflowln; + /** + * Code to execute on parser failure + * + * This is set by the %parse_failure directive + * @var string + */ + public $failure; + /** + * Line number for start of failure code + * @var int + */ + public $failureln; + /** + * Code to execute when the parser acccepts (completes parsing) + * + * This is set by the %parse_accept directive + * @var string + */ + public $accept; + /** + * Line number for the start of accept code + * @var int + */ + public $acceptln; + /** + * Code appended to the generated file + * + * This is set by the %code directive + * @var string + */ + public $extracode; + /** + * Line number for the start of the extra code + * @var int + */ + public $extracodeln; + /** + * Code to execute to destroy token data + * + * This is set by the %token_destructor directive + * @var string + */ + public $tokendest; + /** + * Line number for token destroyer code + * @var int + */ + public $tokendestln; + /** + * Code for the default non-terminal destructor + * + * This is set by the %default_destructor directive + * @var string + */ + public $vardest; + /** + * Line number for default non-terminal destructor code + * @var int + */ + public $vardestln; + /** + * Name of the input file + * @var string + */ + public $filename; + /** + * Name of the input file without its extension + * @var string + */ + public $filenosuffix; + /** + * Name of the current output file + * @var string + */ + public $outname; + /** + * A prefix added to token names + * @var string + */ + public $tokenprefix; + /** + * Number of parsing conflicts + * @var int + */ + public $nconflict; + /** + * Size of the parse tables + * @var int + */ + public $tablesize; + /** + * Public only basis configurations + */ + public $basisflag; + /** + * True if any %fallback is seen in the grammer + * @var boolean + */ + public $has_fallback; + /** + * Name of the program + * @var string + */ + public $argv0; + + /* Find a precedence symbol of every rule in the grammar. + * + * Those rules which have a precedence symbol coded in the input + * grammar using the "[symbol]" construct will already have the + * $rp->precsym field filled. Other rules take as their precedence + * symbol the first RHS symbol with a defined precedence. If there + * are not RHS symbols with a defined precedence, the precedence + * symbol field is left blank. + */ + function FindRulePrecedences() + { + for ($rp = $this->rule; $rp; $rp = $rp->next) { + if ($rp->precsym === 0) { + for ($i = 0; $i < $rp->nrhs && $rp->precsym === 0; $i++) { + $sp = $rp->rhs[$i]; + if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + for ($j = 0; $j < $sp->nsubsym; $j++) { + if ($sp->subsym[$j]->prec >= 0) { + $rp->precsym = $sp->subsym[$j]; + break; + } + } + } elseif ($sp->prec >= 0) { + $rp->precsym = $rp->rhs[$i]; + } + } + } + } + } + + /** + * Find all nonterminals which will generate the empty string. + * Then go back and compute the first sets of every nonterminal. + * The first set is the set of all terminal symbols which can begin + * a string generated by that nonterminal. + */ + function FindFirstSets() + { + for ($i = 0; $i < $this->nsymbol; $i++) { + $this->symbols[$i]->lambda = false; + } + for($i = $this->nterminal; $i < $this->nsymbol; $i++) { + $this->symbols[$i]->firstset = array(); + } + + /* First compute all lambdas */ + do{ + $progress = 0; + for ($rp = $this->rule; $rp; $rp = $rp->next) { + if ($rp->lhs->lambda) { + continue; + } + for ($i = 0; $i < $rp->nrhs; $i++) { + $sp = $rp->rhs[$i]; + if ($sp->type != PHP_ParserGenerator_Symbol::TERMINAL || $sp->lambda === false) { + break; + } + } + if ($i === $rp->nrhs) { + $rp->lhs->lambda = true; + $progress = 1; + } + } + } while ($progress); + + /* Now compute all first sets */ + do { + $progress = 0; + for ($rp = $this->rule; $rp; $rp = $rp->next) { + $s1 = $rp->lhs; + for ($i = 0; $i < $rp->nrhs; $i++) { + $s2 = $rp->rhs[$i]; + if ($s2->type == PHP_ParserGenerator_Symbol::TERMINAL) { + //progress += SetAdd(s1->firstset,s2->index); + $progress += isset($s1->firstset[$s2->index]) ? 0 : 1; + $s1->firstset[$s2->index] = 1; + break; + } elseif ($s2->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + for ($j = 0; $j < $s2->nsubsym; $j++) { + //progress += SetAdd(s1->firstset,s2->subsym[j]->index); + $progress += isset($s1->firstset[$s2->subsym[$j]->index]) ? 0 : 1; + $s1->firstset[$s2->subsym[$j]->index] = 1; + } + break; + } elseif ($s1 === $s2) { + if ($s1->lambda === false) { + break; + } + } else { + //progress += SetUnion(s1->firstset,s2->firstset); + $test = array_diff_key($s2->firstset, $s1->firstset); + if (count($test)) { + $progress++; + $s1->firstset += $test; + } + if ($s2->lambda === false) { + break; + } + } + } + } + } while ($progress); + } + + /** + * Compute all LR(0) states for the grammar. Links + * are added to between some states so that the LR(1) follow sets + * can be computed later. + */ + function FindStates() + { + PHP_ParserGenerator_Config::Configlist_init(); + + /* Find the start symbol */ + if ($this->start) { + $sp = PHP_ParserGenerator_Symbol::Symbol_find($this->start); + if ($sp == 0) { + PHP_ParserGenerator::ErrorMsg($this->filename, 0, + "The specified start symbol \"%s\" is not " . + "in a nonterminal of the grammar. \"%s\" will be used as the start " . + "symbol instead.", $this->start, $this->rule->lhs->name); + $this->errorcnt++; + $sp = $this->rule->lhs; + } + } else { + $sp = $this->rule->lhs; + } + + /* Make sure the start symbol doesn't occur on the right-hand side of + ** any rule. Report an error if it does. (YACC would generate a new + ** start symbol in this case.) */ + for ($rp = $this->rule; $rp; $rp = $rp->next) { + for ($i = 0; $i < $rp->nrhs; $i++) { + if ($rp->rhs[$i]->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + foreach ($rp->rhs[$i]->subsym as $subsp) { + if ($subsp === $sp) { + PHP_ParserGenerator::ErrorMsg($this->filename, 0, + "The start symbol \"%s\" occurs on the " . + "right-hand side of a rule. This will result in a parser which " . + "does not work properly.", $sp->name); + $this->errorcnt++; + } + } + } elseif ($rp->rhs[$i] === $sp) { + PHP_ParserGenerator::ErrorMsg($this->filename, 0, + "The start symbol \"%s\" occurs on the " . + "right-hand side of a rule. This will result in a parser which " . + "does not work properly.", $sp->name); + $this->errorcnt++; + } + } + } + + /* The basis configuration set for the first state + ** is all rules which have the start symbol as their + ** left-hand side */ + for ($rp = $sp->rule; $rp; $rp = $rp->nextlhs) { + $newcfp = PHP_ParserGenerator_Config::Configlist_addbasis($rp, 0); + $newcfp->fws[0] = 1; + } + + /* Compute the first state. All other states will be + ** computed automatically during the computation of the first one. + ** The returned pointer to the first state is not used. */ + $newstp = array(); + $newstp = $this->getstate(); + if (is_array($newstp)) { + $this->buildshifts($newstp[0]); /* Recursively compute successor states */ + } + } + + /** + * @return PHP_ParserGenerator_State + */ + private function getstate() + { + /* Extract the sorted basis of the new state. The basis was constructed + ** by prior calls to "Configlist_addbasis()". */ + PHP_ParserGenerator_Config::Configlist_sortbasis(); + $bp = PHP_ParserGenerator_Config::Configlist_basis(); + + /* Get a state with the same basis */ + $stp = PHP_ParserGenerator_State::State_find($bp); + if ($stp) { + /* A state with the same basis already exists! Copy all the follow-set + ** propagation links from the state under construction into the + ** preexisting state, then return a pointer to the preexisting state */ + for($x = $bp, $y = $stp->bp; $x && $y; $x = $x->bp, $y = $y->bp) { + PHP_ParserGenerator_PropagationLink::Plink_copy($y->bplp, $x->bplp); + PHP_ParserGenerator_PropagationLink::Plink_delete($x->fplp); + $x->fplp = $x->bplp = 0; + } + $cfp = PHP_ParserGenerator_Config::Configlist_return(); + PHP_ParserGenerator_Config::Configlist_eat($cfp); + } else { + /* This really is a new state. Construct all the details */ + PHP_ParserGenerator_Config::Configlist_closure($this); /* Compute the configuration closure */ + PHP_ParserGenerator_Config::Configlist_sort(); /* Sort the configuration closure */ + $cfp = PHP_ParserGenerator_Config::Configlist_return(); /* Get a pointer to the config list */ + $stp = new PHP_ParserGenerator_State; /* A new state structure */ + $stp->bp = $bp; /* Remember the configuration basis */ + $stp->cfp = $cfp; /* Remember the configuration closure */ + $stp->statenum = $this->nstate++; /* Every state gets a sequence number */ + $stp->ap = 0; /* No actions, yet. */ + PHP_ParserGenerator_State::State_insert($stp, $stp->bp); /* Add to the state table */ + // this can't work, recursion is too deep, move it into FindStates() + //$this->buildshifts($stp); /* Recursively compute successor states */ + return array($stp); + } + return $stp; + } + + /** + * Construct all successor states to the given state. A "successor" + * state is any state which can be reached by a shift action. + * @param PHP_ParserGenerator_Data + * @param PHP_ParserGenerator_State The state from which successors are computed + */ + private function buildshifts(PHP_ParserGenerator_State $stp) + { +// struct config *cfp; /* For looping thru the config closure of "stp" */ +// struct config *bcfp; /* For the inner loop on config closure of "stp" */ +// struct config *new; /* */ +// struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ +// struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ +// struct state *newstp; /* A pointer to a successor state */ + + /* Each configuration becomes complete after it contibutes to a successor + ** state. Initially, all configurations are incomplete */ + $cfp = $stp->cfp; + for ($cfp = $stp->cfp; $cfp; $cfp = $cfp->next) { + $cfp->status = PHP_ParserGenerator_Config::INCOMPLETE; + } + + /* Loop through all configurations of the state "stp" */ + for ($cfp = $stp->cfp; $cfp; $cfp = $cfp->next) { + if ($cfp->status == PHP_ParserGenerator_Config::COMPLETE) { + continue; /* Already used by inner loop */ + } + if ($cfp->dot >= $cfp->rp->nrhs) { + continue; /* Can't shift this config */ + } + PHP_ParserGenerator_Config::Configlist_reset(); /* Reset the new config set */ + $sp = $cfp->rp->rhs[$cfp->dot]; /* Symbol after the dot */ + + /* For every configuration in the state "stp" which has the symbol "sp" + ** following its dot, add the same configuration to the basis set under + ** construction but with the dot shifted one symbol to the right. */ + $bcfp = $cfp; + for ($bcfp = $cfp; $bcfp; $bcfp = $bcfp->next) { + if ($bcfp->status == PHP_ParserGenerator_Config::COMPLETE) { + continue; /* Already used */ + } + if ($bcfp->dot >= $bcfp->rp->nrhs) { + continue; /* Can't shift this one */ + } + $bsp = $bcfp->rp->rhs[$bcfp->dot]; /* Get symbol after dot */ + if (!PHP_ParserGenerator_Symbol::same_symbol($bsp, $sp)) { + continue; /* Must be same as for "cfp" */ + } + $bcfp->status = PHP_ParserGenerator_Config::COMPLETE; /* Mark this config as used */ + $new = PHP_ParserGenerator_Config::Configlist_addbasis($bcfp->rp, $bcfp->dot + 1); + PHP_ParserGenerator_PropagationLink::Plink_add($new->bplp, $bcfp); + } + + /* Get a pointer to the state described by the basis configuration set + ** constructed in the preceding loop */ + $newstp = $this->getstate(); + if (is_array($newstp)) { + $this->buildshifts($newstp[0]); /* Recursively compute successor states */ + $newstp = $newstp[0]; + } + + /* The state "newstp" is reached from the state "stp" by a shift action + ** on the symbol "sp" */ + if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + for($i = 0; $i < $sp->nsubsym; $i++) { + PHP_ParserGenerator_Action::Action_add($stp->ap, PHP_ParserGenerator_Action::SHIFT, $sp->subsym[$i], + $newstp); + } + } else { + PHP_ParserGenerator_Action::Action_add($stp->ap, PHP_ParserGenerator_Action::SHIFT, $sp, $newstp); + } + } + } + + /** + * Construct the propagation links + */ + function FindLinks() + { + /* Housekeeping detail: + ** Add to every propagate link a pointer back to the state to + ** which the link is attached. */ + foreach ($this->sorted as $info) { + $info->key->stp = $info->data; + } + + /* Convert all backlinks into forward links. Only the forward + ** links are used in the follow-set computation. */ + for ($i = 0; $i < $this->nstate; $i++) { + $stp = $this->sorted[$i]; + for ($cfp = $stp->data->cfp; $cfp; $cfp = $cfp->next) { + for ($plp = $cfp->bplp; $plp; $plp = $plp->next) { + $other = $plp->cfp; + PHP_ParserGenerator_PropagationLink::Plink_add($other->fplp, $cfp); + } + } + } + } + + /** + * Compute the reduce actions, and resolve conflicts. + */ + function FindActions() + { + /* Add all of the reduce actions + ** A reduce action is added for each element of the followset of + ** a configuration which has its dot at the extreme right. + */ + for ($i = 0; $i < $this->nstate; $i++) { /* Loop over all states */ + $stp = $this->sorted[$i]->data; + for ($cfp = $stp->cfp; $cfp; $cfp = $cfp->next) { + /* Loop over all configurations */ + if ($cfp->rp->nrhs == $cfp->dot) { /* Is dot at extreme right? */ + for ($j = 0; $j < $this->nterminal; $j++) { + if (isset($cfp->fws[$j])) { + /* Add a reduce action to the state "stp" which will reduce by the + ** rule "cfp->rp" if the lookahead symbol is "$this->symbols[j]" */ + PHP_ParserGenerator_Action::Action_add($stp->ap, PHP_ParserGenerator_Action::REDUCE, + $this->symbols[$j], $cfp->rp); + } + } + } + } + } + + /* Add the accepting token */ + if ($this->start instanceof PHP_ParserGenerator_Symbol) { + $sp = PHP_ParserGenerator_Symbol::Symbol_find($this->start); + if ($sp === 0) { + $sp = $this->rule->lhs; + } + } else { + $sp = $this->rule->lhs; + } + /* Add to the first state (which is always the starting state of the + ** finite state machine) an action to ACCEPT if the lookahead is the + ** start nonterminal. */ + PHP_ParserGenerator_Action::Action_add($this->sorted[0]->data->ap, PHP_ParserGenerator_Action::ACCEPT, $sp, 0); + + /* Resolve conflicts */ + for ($i = 0; $i < $this->nstate; $i++) { + // struct action *ap, *nap; + // struct state *stp; + $stp = $this->sorted[$i]->data; + if (!$stp->ap) { + throw new Exception('state has no actions associated'); + } + echo 'processing state ' . $stp->statenum . " actions:\n"; + for ($ap = $stp->ap; $ap !== 0 && $ap->next !== 0; $ap = $ap->next) { + echo ' Action '; + $ap->display(true); + } + $stp->ap = PHP_ParserGenerator_Action::Action_sort($stp->ap); + for ($ap = $stp->ap; $ap !== 0 && $ap->next !== 0; $ap = $ap->next) { + for ($nap = $ap->next; $nap !== 0 && $nap->sp === $ap->sp ; $nap = $nap->next) { + /* The two actions "ap" and "nap" have the same lookahead. + ** Figure out which one should be used */ + $this->nconflict += $this->resolve_conflict($ap, $nap, $this->errsym); + } + } + } + + /* Report an error for each rule that can never be reduced. */ + for ($rp = $this->rule; $rp; $rp = $rp->next) { + $rp->canReduce = false; + } + for ($i = 0; $i < $this->nstate; $i++) { + for ($ap = $this->sorted[$i]->data->ap; $ap !== 0; $ap = $ap->next) { + if ($ap->type == PHP_ParserGenerator_Action::REDUCE) { + $ap->x->canReduce = true; + } + } + } + for ($rp = $this->rule; $rp !== 0; $rp = $rp->next) { + if ($rp->canReduce) { + continue; + } + PHP_ParserGenerator::ErrorMsg($this->filename, $rp->ruleline, "This rule can not be reduced (is not connected to the start symbol).\n"); + $this->errorcnt++; + } + } + + /** Resolve a conflict between the two given actions. If the + * conflict can't be resolve, return non-zero. + * + * NO LONGER TRUE: + * To resolve a conflict, first look to see if either action + * is on an error rule. In that case, take the action which + * is not associated with the error rule. If neither or both + * actions are associated with an error rule, then try to + * use precedence to resolve the conflict. + * + * If either action is a SHIFT, then it must be apx. This + * function won't work if apx->type==REDUCE and apy->type==SHIFT. + * @param PHP_ParserGenerator_Action + * @param PHP_ParserGenerator_Action + * @param PHP_ParserGenerator_Symbol|null The error symbol (if defined. NULL otherwise) + */ + function resolve_conflict($apx, $apy, $errsym) + { + $errcnt = 0; + if ($apx->sp !== $apy->sp) { + throw new Exception('no conflict but resolve_conflict called'); + } + if ($apx->type == PHP_ParserGenerator_Action::SHIFT && $apy->type == PHP_ParserGenerator_Action::REDUCE) { + $spx = $apx->sp; + $spy = $apy->x->precsym; + if ($spy === 0 || $spx->prec < 0 || $spy->prec < 0) { + /* Not enough precedence information. */ + $apy->type = PHP_ParserGenerator_Action::CONFLICT; + $errcnt++; + } elseif ($spx->prec > $spy->prec) { /* Lower precedence wins */ + $apy->type = PHP_ParserGenerator_Action::RD_RESOLVED; + } elseif ($spx->prec < $spy->prec) { + $apx->type = PHP_ParserGenerator_Action::SH_RESOLVED; + } elseif ($spx->prec === $spy->prec && $spx->assoc == PHP_ParserGenerator_Symbol::RIGHT) { + /* Use operator */ + $apy->type = PHP_ParserGenerator_Action::RD_RESOLVED; /* associativity */ + } elseif ($spx->prec === $spy->prec && $spx->assoc == PHP_ParserGenerator_Symbol::LEFT) { + /* to break tie */ + $apx->type = PHP_ParserGenerator_Action::SH_RESOLVED; + } else { + if ($spx->prec !== $spy->prec || $spx->assoc !== PHP_ParserGenerator_Symbol::NONE) { + throw new Exception('$spx->prec !== $spy->prec || $spx->assoc !== PHP_ParserGenerator_Symbol::NONE'); + } + $apy->type = PHP_ParserGenerator_Action::CONFLICT; + $errcnt++; + } + } elseif ($apx->type == PHP_ParserGenerator_Action::REDUCE && $apy->type == PHP_ParserGenerator_Action::REDUCE) { + $spx = $apx->x->precsym; + $spy = $apy->x->precsym; + if ($spx === 0 || $spy === 0 || $spx->prec < 0 || + $spy->prec < 0 || $spx->prec === $spy->prec) { + $apy->type = PHP_ParserGenerator_Action::CONFLICT; + $errcnt++; + } elseif ($spx->prec > $spy->prec) { + $apy->type = PHP_ParserGenerator_Action::RD_RESOLVED; + } elseif ($spx->prec < $spy->prec) { + $apx->type = PHP_ParserGenerator_Action::RD_RESOLVED; + } + } else { + if ($apx->type!== PHP_ParserGenerator_Action::SH_RESOLVED && + $apx->type!== PHP_ParserGenerator_Action::RD_RESOLVED && + $apx->type!== PHP_ParserGenerator_Action::CONFLICT && + $apy->type!== PHP_ParserGenerator_Action::SH_RESOLVED && + $apy->type!== PHP_ParserGenerator_Action::RD_RESOLVED && + $apy->type!== PHP_ParserGenerator_Action::CONFLICT) { + throw new Exception('$apx->type!== PHP_ParserGenerator_Action::SH_RESOLVED && + $apx->type!== PHP_ParserGenerator_Action::RD_RESOLVED && + $apx->type!== PHP_ParserGenerator_Action::CONFLICT && + $apy->type!== PHP_ParserGenerator_Action::SH_RESOLVED && + $apy->type!== PHP_ParserGenerator_Action::RD_RESOLVED && + $apy->type!== PHP_ParserGenerator_Action::CONFLICT'); + } + /* The REDUCE/SHIFT case cannot happen because SHIFTs come before + ** REDUCEs on the list. If we reach this point it must be because + ** the parser conflict had already been resolved. */ + } + return $errcnt; + } + + /** + * Reduce the size of the action tables, if possible, by making use + * of defaults. + * + * In this version, we take the most frequent REDUCE action and make + * it the default. + */ + function CompressTables() + { + for ($i = 0; $i < $this->nstate; $i++) { + $stp = $this->sorted[$i]->data; + $nbest = 0; + $rbest = 0; + + for ($ap = $stp->ap; $ap; $ap = $ap->next) { + if ($ap->type != PHP_ParserGenerator_Action::REDUCE) { + continue; + } + $rp = $ap->x; + if ($rp === $rbest) { + continue; + } + $n = 1; + for ($ap2 = $ap->next; $ap2; $ap2 = $ap2->next) { + if ($ap2->type != PHP_ParserGenerator_Action::REDUCE) { + continue; + } + $rp2 = $ap2->x; + if ($rp2 === $rbest) { + continue; + } + if ($rp2 === $rp) { + $n++; + } + } + if ($n > $nbest) { + $nbest = $n; + $rbest = $rp; + } + } + + /* Do not make a default if the number of rules to default + ** is not at least 1 */ + if ($nbest < 1) { + continue; + } + + + /* Combine matching REDUCE actions into a single default */ + for ($ap = $stp->ap; $ap; $ap = $ap->next) { + if ($ap->type == PHP_ParserGenerator_Action::REDUCE && $ap->x === $rbest) { + break; + } + } + if ($ap === 0) { + throw new Exception('$ap is not an object'); + } + $ap->sp = PHP_ParserGenerator_Symbol::Symbol_new("{default}"); + for ($ap = $ap->next; $ap; $ap = $ap->next) { + if ($ap->type == PHP_ParserGenerator_Action::REDUCE && $ap->x === $rbest) { + $ap->type = PHP_ParserGenerator_Action::NOT_USED; + } + } + $stp->ap = PHP_ParserGenerator_Action::Action_sort($stp->ap); + } + } + + /** + * Renumber and resort states so that states with fewer choices + * occur at the end. Except, keep state 0 as the first state. + */ + function ResortStates() + { + for ($i = 0; $i < $this->nstate; $i++) { + $stp = $this->sorted[$i]->data; + $stp->nTknAct = $stp->nNtAct = 0; + $stp->iDflt = $this->nstate + $this->nrule; + $stp->iTknOfst = PHP_ParserGenerator_Data::NO_OFFSET; + $stp->iNtOfst = PHP_ParserGenerator_Data::NO_OFFSET; + for ($ap = $stp->ap; $ap; $ap = $ap->next) { + if ($this->compute_action($ap) >= 0) { + if ($ap->sp->index < $this->nterminal) { + $stp->nTknAct++; + } elseif ($ap->sp->index < $this->nsymbol) { + $stp->nNtAct++; + } else { + $stp->iDflt = $this->compute_action($ap); + } + } + } + $this->sorted[$i] = $stp; + } + $save = $this->sorted[0]; + unset($this->sorted[0]); + usort($this->sorted, array('PHP_ParserGenerator_State', 'stateResortCompare')); + array_unshift($this->sorted, $save); + for($i = 0; $i < $this->nstate; $i++) { + $this->sorted[$i]->statenum = $i; + } + } + + /** + * Given an action, compute the integer value for that action + * which is to be put in the action table of the generated machine. + * Return negative if no action should be generated. + * @param PHP_ParserGenerator_Action + */ + function compute_action($ap) + { + switch ($ap->type) { + case PHP_ParserGenerator_Action::SHIFT: + $act = $ap->x->statenum; + break; + case PHP_ParserGenerator_Action::REDUCE: + $act = $ap->x->index + $this->nstate; + break; + case PHP_ParserGenerator_Action::ERROR: + $act = $this->nstate + $this->nrule; + break; + case PHP_ParserGenerator_Action::ACCEPT: + $act = $this->nstate + $this->nrule + 1; + break; + default: + $act = -1; + break; + } + return $act; + } + + /** + * Generate the "Parse.out" log file + */ + function ReportOutput() + { + $fp = fopen($this->filenosuffix . ".out", "wb"); + if (!$fp) { + return; + } + for ($i = 0; $i < $this->nstate; $i++) { + $stp = $this->sorted[$i]; + fprintf($fp, "State %d:\n", $stp->statenum); + if ($this->basisflag) { + $cfp = $stp->bp; + } else { + $cfp = $stp->cfp; + } + while ($cfp) { + if ($cfp->dot == $cfp->rp->nrhs) { + $buf = sprintf('(%d)', $cfp->rp->index); + fprintf($fp, ' %5s ', $buf); + } else { + fwrite($fp,' '); + } + $cfp->ConfigPrint($fp); + fwrite($fp, "\n"); + if (0) { + //SetPrint(fp,cfp->fws,$this); + //PlinkPrint(fp,cfp->fplp,"To "); + //PlinkPrint(fp,cfp->bplp,"From"); + } + if ($this->basisflag) { + $cfp = $cfp->bp; + } else { + $cfp = $cfp->next; + } + } + fwrite($fp, "\n"); + for ($ap = $stp->ap; $ap; $ap = $ap->next) { + if ($ap->PrintAction($fp, 30)) { + fprintf($fp,"\n"); + } + } + fwrite($fp,"\n"); + } + fclose($fp); + } + + /** + * The next function finds the template file and opens it, returning + * a pointer to the opened file. + * @return resource + */ + private function tplt_open() + { + $templatename = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . "Lempar.php"; + $buf = $this->filenosuffix . '.lt'; + if (file_exists($buf) && is_readable($buf)) { + $tpltname = $buf; + } elseif (file_exists($templatename) && is_readable($templatename)) { + $tpltname = $templatename; + } elseif ($fp = @fopen($templatename, 'rb', true)) { + return $fp; + } + if (!isset($tpltname)) { + echo "Can't find the parser driver template file \"%s\".\n", + $templatename; + $this->errorcnt++; + return 0; + } + $in = @fopen($tpltname,"rb"); + if (!$in) { + printf("Can't open the template file \"%s\".\n", $tpltname); + $this->errorcnt++; + return 0; + } + return $in; + } + +#define LINESIZE 1000 + /**#@+ + * The next cluster of routines are for reading the template file + * and writing the results to the generated parser + */ + /** + * The first function transfers data from "in" to "out" until + * a line is seen which begins with "%%". The line number is + * tracked. + * + * if name!=0, then any word that begin with "Parse" is changed to + * begin with *name instead. + */ + private function tplt_xfer($name, $in, $out, &$lineno) + { + while (($line = fgets($in, 1024)) && ($line[0] != '%' || $line[1] != '%')) { + $lineno++; + $iStart = 0; + if ($name) { + for ($i = 0; $i < strlen($line); $i++) { + if ($line[$i] == 'P' && substr($line, $i, 5) == "Parse" + && ($i === 0 || preg_match('/[^a-zA-Z]/', $line[$i - 1]))) { + if ($i > $iStart) { + fwrite($out, substr($line, $iStart, $i - $iStart)); + } + fwrite($out, $name); + $i += 4; + $iStart = $i + 1; + } + } + } + fwrite($out, substr($line, $iStart)); + } + } + + /** + * Print a #line directive line to the output file. + */ + private function tplt_linedir($out, $lineno, $filename) + { + fwrite($out, '#line ' . $lineno . ' "' . $filename . "\"\n"); + } + + /** + * Print a string to the file and keep the linenumber up to date + */ + private function tplt_print($out, $str, $strln, &$lineno) + { + if ($str == '') { + return; + } + $this->tplt_linedir($out, $strln, $this->filename); + $lineno++; + fwrite($out, $str); + $lineno += count(explode("\n", $str)) - 1; + $this->tplt_linedir($out, $lineno + 2, $this->outname); + $lineno += 2; + } + /**#@-*/ + + /** + * Compute all followsets. + * + * A followset is the set of all symbols which can come immediately + * after a configuration. + */ + function FindFollowSets() + { + for ($i = 0; $i < $this->nstate; $i++) { + for ($cfp = $this->sorted[$i]->data->cfp; $cfp; $cfp = $cfp->next) { + $cfp->status = PHP_ParserGenerator_Config::INCOMPLETE; + } + } + + do { + $progress = 0; + for ($i = 0; $i < $this->nstate; $i++) { + for ($cfp = $this->sorted[$i]->data->cfp; $cfp; $cfp = $cfp->next) { + if ($cfp->status == PHP_ParserGenerator_Config::COMPLETE) { + continue; + } + for ($plp = $cfp->fplp; $plp; $plp = $plp->next) { + $a = array_diff_key($cfp->fws, $plp->cfp->fws); + if (count($a)) { + $plp->cfp->fws += $a; + $plp->cfp->status = PHP_ParserGenerator_Config::INCOMPLETE; + $progress = 1; + } + } + $cfp->status = PHP_ParserGenerator_Config::COMPLETE; + } + } + } while ($progress); + } + + /** + * Generate C source code for the parser + * @param int Output in makeheaders format if true + */ + function ReportTable($mhflag) + { +// FILE *out, *in; +// char line[LINESIZE]; +// int lineno; +// struct state *stp; +// struct action *ap; +// struct rule *rp; +// struct acttab *pActtab; +// int i, j, n; +// char *name; +// int mnTknOfst, mxTknOfst; +// int mnNtOfst, mxNtOfst; +// struct axset *ax; + + $in = $this->tplt_open(); + if (!$in) { + return; + } + $out = fopen($this->filenosuffix . ".php", "wb"); + if (!$out) { + fclose($in); + return; + } + $this->outname = $this->filenosuffix . ".php"; + $lineno = 1; + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate the include code, if any */ + $this->tplt_print($out, $this->include_code, $this->includeln, $lineno); + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate the class declaration code */ + $this->tplt_print($out, $this->declare_classcode, $this->declare_classln, + $lineno); + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate the internal parser class include code, if any */ + $this->tplt_print($out, $this->include_classcode, $this->include_classln, + $lineno); + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate #defines for all tokens */ + //if ($mhflag) { + //fprintf($out, "#if INTERFACE\n"); + $lineno++; + if ($this->tokenprefix) { + $prefix = $this->tokenprefix; + } else { + $prefix = ''; + } + for ($i = 1; $i < $this->nterminal; $i++) { + fprintf($out, " const %s%-30s = %2d;\n", $prefix, $this->symbols[$i]->name, $i); + $lineno++; + } + //fwrite($out, "#endif\n"); + $lineno++; + //} + fwrite($out, " const YY_NO_ACTION = " . + ($this->nstate + $this->nrule + 2) . ";\n"); + $lineno++; + fwrite($out, " const YY_ACCEPT_ACTION = " . + ($this->nstate + $this->nrule + 1) . ";\n"); + $lineno++; + fwrite($out, " const YY_ERROR_ACTION = " . + ($this->nstate + $this->nrule) . ";\n"); + $lineno++; + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate the action table and its associates: + ** + ** yy_action[] A single table containing all actions. + ** yy_lookahead[] A table containing the lookahead for each entry in + ** yy_action. Used to detect hash collisions. + ** yy_shift_ofst[] For each state, the offset into yy_action for + ** shifting terminals. + ** yy_reduce_ofst[] For each state, the offset into yy_action for + ** shifting non-terminals after a reduce. + ** yy_default[] Default action for each state. + */ + + /* Compute the actions on all states and count them up */ + + $ax = array(); + for ($i = 0; $i < $this->nstate; $i++) { + $stp = $this->sorted[$i]; + $ax[$i * 2] = array(); + $ax[$i * 2]['stp'] = $stp; + $ax[$i * 2]['isTkn'] = 1; + $ax[$i * 2]['nAction'] = $stp->nTknAct; + $ax[$i * 2 + 1] = array(); + $ax[$i * 2 + 1]['stp'] = $stp; + $ax[$i * 2 + 1]['isTkn'] = 0; + $ax[$i * 2 + 1]['nAction'] = $stp->nNtAct; + } + $mxTknOfst = $mnTknOfst = 0; + $mxNtOfst = $mnNtOfst = 0; + + /* Compute the action table. In order to try to keep the size of the + ** action table to a minimum, the heuristic of placing the largest action + ** sets first is used. + */ + + usort($ax, array('PHP_ParserGenerator_Data', 'axset_compare')); + $pActtab = new PHP_ParserGenerator_ActionTable; + for ($i = 0; $i < $this->nstate * 2 && $ax[$i]['nAction'] > 0; $i++) { + $stp = $ax[$i]['stp']; + if ($ax[$i]['isTkn']) { + for ($ap = $stp->ap; $ap; $ap = $ap->next) { + if ($ap->sp->index >= $this->nterminal) { + continue; + } + $action = $this->compute_action($ap); + if ($action < 0) { + continue; + } + $pActtab->acttab_action($ap->sp->index, $action); + } + $stp->iTknOfst = $pActtab->acttab_insert(); + if ($stp->iTknOfst < $mnTknOfst) { + $mnTknOfst = $stp->iTknOfst; + } + if ($stp->iTknOfst > $mxTknOfst) { + $mxTknOfst = $stp->iTknOfst; + } + } else { + for ($ap = $stp->ap; $ap; $ap = $ap->next) { + if ($ap->sp->index < $this->nterminal) { + continue; + } + if ($ap->sp->index == $this->nsymbol) { + continue; + } + $action = $this->compute_action($ap); + if ($action < 0) { + continue; + } + $pActtab->acttab_action($ap->sp->index, $action); + } + $stp->iNtOfst = $pActtab->acttab_insert(); + if ($stp->iNtOfst < $mnNtOfst) { + $mnNtOfst = $stp->iNtOfst; + } + if ($stp->iNtOfst > $mxNtOfst) { + $mxNtOfst = $stp->iNtOfst; + } + } + } + /* Output the yy_action table */ + + fprintf($out, " const YY_SZ_ACTTAB = %d;\n", $pActtab->nAction); + $lineno++; + fwrite($out, "static public \$yy_action = array(\n"); + $lineno++; + $n = $pActtab->nAction; + for($i = $j = 0; $i < $n; $i++) { + $action = $pActtab->aAction[$i]['action']; + if ($action < 0) { + $action = $this->nsymbol + $this->nrule + 2; + } + // change next line + if ($j === 0) { + fprintf($out, " /* %5d */ ", $i); + } + fprintf($out, " %4d,", $action); + if ($j == 9 || $i == $n - 1) { + fwrite($out, "\n"); + $lineno++; + $j = 0; + } else { + $j++; + } + } + fwrite($out, " );\n"); $lineno++; + + /* Output the yy_lookahead table */ + + fwrite($out, " static public \$yy_lookahead = array(\n"); + $lineno++; + for ($i = $j = 0; $i < $n; $i++) { + $la = $pActtab->aAction[$i]['lookahead']; + if ($la < 0) { + $la = $this->nsymbol; + } + // change next line + if ($j === 0) { + fprintf($out, " /* %5d */ ", $i); + } + fprintf($out, " %4d,", $la); + if ($j == 9 || $i == $n - 1) { + fwrite($out, "\n"); + $lineno++; + $j = 0; + } else { + $j++; + } + } + fwrite($out, ");\n"); + $lineno++; + + /* Output the yy_shift_ofst[] table */ + fprintf($out, " const YY_SHIFT_USE_DFLT = %d;\n", $mnTknOfst - 1); + $lineno++; + $n = $this->nstate; + while ($n > 0 && $this->sorted[$n - 1]->iTknOfst == PHP_ParserGenerator_Data::NO_OFFSET) { + $n--; + } + fprintf($out, " const YY_SHIFT_MAX = %d;\n", $n - 1); + $lineno++; + fwrite($out, " static public \$yy_shift_ofst = array(\n"); + $lineno++; + for ($i = $j = 0; $i < $n; $i++) { + $stp = $this->sorted[$i]; + $ofst = $stp->iTknOfst; + if ($ofst === PHP_ParserGenerator_Data::NO_OFFSET) { + $ofst = $mnTknOfst - 1; + } + // change next line + if ($j === 0) { + fprintf($out, " /* %5d */ ", $i); + } + fprintf($out, " %4d,", $ofst); + if ($j == 9 || $i == $n - 1) { + fwrite($out, "\n"); + $lineno++; + $j = 0; + } else { + $j++; + } + } + fwrite($out, ");\n"); + $lineno++; + + + /* Output the yy_reduce_ofst[] table */ + + fprintf($out, " const YY_REDUCE_USE_DFLT = %d;\n", $mnNtOfst - 1); + $lineno++; + $n = $this->nstate; + while ($n > 0 && $this->sorted[$n - 1]->iNtOfst == PHP_ParserGenerator_Data::NO_OFFSET) { + $n--; + } + fprintf($out, " const YY_REDUCE_MAX = %d;\n", $n - 1); + $lineno++; + fwrite($out, " static public \$yy_reduce_ofst = array(\n"); + $lineno++; + for ($i = $j = 0; $i < $n; $i++) { + $stp = $this->sorted[$i]; + $ofst = $stp->iNtOfst; + if ($ofst == PHP_ParserGenerator_Data::NO_OFFSET) { + $ofst = $mnNtOfst - 1; + } + // change next line + if ($j == 0) { + fprintf($out, " /* %5d */ ", $i); + } + fprintf($out, " %4d,", $ofst); + if ($j == 9 || $i == $n - 1) { + fwrite($out, "\n"); + $lineno++; + $j = 0; + } else { + $j++; + } + } + fwrite($out, ");\n"); + $lineno++; + + /* Output the expected tokens table */ + + fwrite($out, " static public \$yyExpectedTokens = array(\n"); + $lineno++; + for ($i = 0; $i < $this->nstate; $i++) { + $stp = $this->sorted[$i]; + fwrite($out, " /* $i */ array("); + for ($ap = $stp->ap; $ap; $ap = $ap->next) { + if ($ap->sp->index < $this->nterminal) { + if ($ap->type == PHP_ParserGenerator_Action::SHIFT || + $ap->type == PHP_ParserGenerator_Action::REDUCE) { + fwrite($out, $ap->sp->index . ', '); + } + } + } + fwrite($out, "),\n"); + $lineno++; + } + fwrite($out, ");\n"); + $lineno++; + + /* Output the default action table */ + + fwrite($out, " static public \$yy_default = array(\n"); + $lineno++; + $n = $this->nstate; + for ($i = $j = 0; $i < $n; $i++) { + $stp = $this->sorted[$i]; + // change next line + if ($j == 0) { + fprintf($out, " /* %5d */ ", $i); + } + fprintf($out, " %4d,", $stp->iDflt); + if ($j == 9 || $i == $n - 1) { + fprintf($out, "\n"); $lineno++; + $j = 0; + } else { + $j++; + } + } + fwrite($out, ");\n"); + $lineno++; + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate the defines */ + fprintf($out, " const YYNOCODE = %d;\n", $this->nsymbol + 1); + $lineno++; + if ($this->stacksize) { + if($this->stacksize <= 0) { + PHP_ParserGenerator::ErrorMsg($this->filename, 0, + "Illegal stack size: [%s]. The stack size should be an integer constant.", + $this->stacksize); + $this->errorcnt++; + $this->stacksize = "100"; + } + fprintf($out, " const YYSTACKDEPTH = %s;\n", $this->stacksize); + $lineno++; + } else { + fwrite($out," const YYSTACKDEPTH = 100;\n"); + $lineno++; + } + fprintf($out, " const YYNSTATE = %d;\n", $this->nstate); + $lineno++; + fprintf($out, " const YYNRULE = %d;\n", $this->nrule); + $lineno++; + fprintf($out, " const YYERRORSYMBOL = %d;\n", $this->errsym->index); + $lineno++; + fprintf($out, " const YYERRSYMDT = 'yy%d';\n", $this->errsym->dtnum); + $lineno++; + if ($this->has_fallback) { + fwrite($out, " const YYFALLBACK = 1;\n"); + } else { + fwrite($out, " const YYFALLBACK = 0;\n"); + } + $lineno++; + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate the table of fallback tokens. + */ + + if ($this->has_fallback) { + for ($i = 0; $i < $this->nterminal; $i++) { + $p = $this->symbols[$i]; + if ($p->fallback === 0) { + // change next line + fprintf($out, " 0, /* %10s => nothing */\n", $p->name); + } else { + // change next line + fprintf($out, " %3d, /* %10s => %s */\n", + $p->fallback->index, $p->name, $p->fallback->name); + } + $lineno++; + } + } + $this->tplt_xfer($this->name, $in, $out, $lineno); + + + /* Generate a table containing the symbolic name of every symbol + ($yyTokenName) + */ + + for ($i = 0; $i < $this->nsymbol; $i++) { + fprintf($out," %-15s", "'" . $this->symbols[$i]->name . "',"); + if (($i & 3) == 3) { + fwrite($out,"\n"); + $lineno++; + } + } + if (($i & 3) != 0) { + fwrite($out, "\n"); + $lineno++; + } + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate a table containing a text string that describes every + ** rule in the rule set of the grammer. This information is used + ** when tracing REDUCE actions. + */ + + for ($i = 0, $rp = $this->rule; $rp; $rp = $rp->next, $i++) { + if ($rp->index !== $i) { + throw new Exception('rp->index != i and should be'); + } + // change next line + fprintf($out, " /* %3d */ \"%s ::=", $i, $rp->lhs->name); + for ($j = 0; $j < $rp->nrhs; $j++) { + $sp = $rp->rhs[$j]; + fwrite($out,' ' . $sp->name); + if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + for($k = 1; $k < $sp->nsubsym; $k++) { + fwrite($out, '|' . $sp->subsym[$k]->name); + } + } + } + fwrite($out, "\",\n"); + $lineno++; + } + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate code which executes every time a symbol is popped from + ** the stack while processing errors or while destroying the parser. + ** (In other words, generate the %destructor actions) + */ + + if ($this->tokendest) { + for ($i = 0; $i < $this->nsymbol; $i++) { + $sp = $this->symbols[$i]; + if ($sp === 0 || $sp->type != PHP_ParserGenerator_Symbol::TERMINAL) { + continue; + } + fprintf($out, " case %d:\n", $sp->index); + $lineno++; + } + for ($i = 0; $i < $this->nsymbol && + $this->symbols[$i]->type != PHP_ParserGenerator_Symbol::TERMINAL; $i++); + if ($i < $this->nsymbol) { + $this->emit_destructor_code($out, $this->symbols[$i], $lineno); + fprintf($out, " break;\n"); + $lineno++; + } + } + if ($this->vardest) { + $dflt_sp = 0; + for ($i = 0; $i < $this->nsymbol; $i++) { + $sp = $this->symbols[$i]; + if ($sp === 0 || $sp->type == PHP_ParserGenerator_Symbol::TERMINAL || + $sp->index <= 0 || $sp->destructor != 0) { + continue; + } + fprintf($out, " case %d:\n", $sp->index); + $lineno++; + $dflt_sp = $sp; + } + if ($dflt_sp != 0) { + $this->emit_destructor_code($out, $dflt_sp, $lineno); + fwrite($out, " break;\n"); + $lineno++; + } + } + for ($i = 0; $i < $this->nsymbol; $i++) { + $sp = $this->symbols[$i]; + if ($sp === 0 || $sp->type == PHP_ParserGenerator_Symbol::TERMINAL || + $sp->destructor === 0) { + continue; + } + fprintf($out, " case %d:\n", $sp->index); + $lineno++; + + /* Combine duplicate destructors into a single case */ + + for ($j = $i + 1; $j < $this->nsymbol; $j++) { + $sp2 = $this->symbols[$j]; + if ($sp2 && $sp2->type != PHP_ParserGenerator_Symbol::TERMINAL && $sp2->destructor + && $sp2->dtnum == $sp->dtnum + && $sp->destructor == $sp2->destructor) { + fprintf($out, " case %d:\n", $sp2->index); + $lineno++; + $sp2->destructor = 0; + } + } + + $this->emit_destructor_code($out, $this->symbols[$i], $lineno); + fprintf($out, " break;\n"); + $lineno++; + } + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate code which executes whenever the parser stack overflows */ + + $this->tplt_print($out, $this->overflow, $this->overflowln, $lineno); + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate the table of rule information + ** + ** Note: This code depends on the fact that rules are number + ** sequentually beginning with 0. + */ + + for ($rp = $this->rule; $rp; $rp = $rp->next) { + fprintf($out, " array( 'lhs' => %d, 'rhs' => %d ),\n", + $rp->lhs->index, $rp->nrhs); + $lineno++; + } + $this->tplt_xfer($this->name, $in, $out, $lineno); + + + /* Generate code which executes during each REDUCE action */ + + for ($rp = $this->rule; $rp; $rp = $rp->next) { + if ($rp->code) { + $this->translate_code($rp); + } + } + + /* Generate the method map for each REDUCE action */ + + for ($rp = $this->rule; $rp; $rp = $rp->next) { + if ($rp->code === 0) { + continue; + } + fwrite($out, ' ' . $rp->index . ' => ' . $rp->index . ",\n"); + $lineno++; + for ($rp2 = $rp->next; $rp2; $rp2 = $rp2->next) { + if ($rp2->code === $rp->code) { + fwrite($out, ' ' . $rp2->index . ' => ' . + $rp->index . ",\n"); + $lineno++; + $rp2->code = 0; + } + } + } + $this->tplt_xfer($this->name, $in, $out, $lineno); + + for ($rp = $this->rule; $rp; $rp = $rp->next) { + if ($rp->code === 0) { + continue; + } + $this->emit_code($out, $rp, $lineno); + } + $this->tplt_xfer($this->name, $in, $out, $lineno); + + + /* Generate code which executes if a parse fails */ + + $this->tplt_print($out, $this->failure, $this->failureln, $lineno); + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate code which executes when a syntax error occurs */ + + $this->tplt_print($out, $this->error, $this->errorln, $lineno); + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Generate code which executes when the parser accepts its input */ + + $this->tplt_print($out, $this->accept, $this->acceptln, $lineno); + $this->tplt_xfer($this->name, $in, $out, $lineno); + + /* Append any addition code the user desires */ + + $this->tplt_print($out, $this->extracode, $this->extracodeln, $lineno); + + fclose($in); + fclose($out); + } + + /** + * Generate code which executes when the rule "rp" is reduced. Write + * the code to "out". Make sure lineno stays up-to-date. + */ + function emit_code($out, PHP_ParserGenerator_Rule $rp, &$lineno) + { + $linecnt = 0; + + /* Generate code to do the reduce action */ + if ($rp->code) { + $this->tplt_linedir($out, $rp->line, $this->filename); + fwrite($out, " function yy_r$rp->index(){" . $rp->code); + $linecnt += count(explode("\n", $rp->code)) - 1; + $lineno += 3 + $linecnt; + fwrite($out, " }\n"); + $this->tplt_linedir($out, $lineno, $this->outname); + } /* End if( rp->code ) */ + } + + /** + * Append text to a dynamically allocated string. If zText is 0 then + * reset the string to be empty again. Always return the complete text + * of the string (which is overwritten with each call). + * + * n bytes of zText are stored. If n==0 then all of zText is stored. + * + * If n==-1, then the previous character is overwritten. + * @param string + * @param int + */ + function append_str($zText, $n) + { + static $z = ''; + $zInt = ''; + + if ($zText === '') { + $ret = $z; + $z = ''; + return $ret; + } + if ($n <= 0) { + if ($n < 0) { + if (!strlen($z)) { + throw new Exception('z is zero-length'); + } + $z = substr($z, 0, strlen($z) - 1); + if (!$z) { + $z = ''; + } + } + $n = strlen($zText); + } + $i = 0; + $z .= substr($zText, 0, $n); + return $z; + } + + /** + * zCode is a string that is the action associated with a rule. Expand + * the symbols in this string so that the refer to elements of the parser + * stack. + */ + function translate_code(PHP_ParserGenerator_Rule $rp) + { + $lhsused = 0; /* True if the LHS element has been used */ + $used = array(); /* True for each RHS element which is used */ + + for($i = 0; $i < $rp->nrhs; $i++) { + $used[$i] = 0; + } + + $this->append_str('', 0); + for ($i = 0; $i < strlen($rp->code); $i++) { + $cp = $rp->code[$i]; + if (preg_match('/[A-Za-z]/', $cp) && + ($i === 0 || (!preg_match('/[A-Za-z0-9_]/', $rp->code[$i - 1])))) { + //*xp = 0; + // previous line is in essence a temporary substr, so + // we will simulate it + $test = substr($rp->code, $i); + preg_match('/[A-Za-z0-9_]+/', $test, $matches); + $tempcp = $matches[0]; + $j = strlen($tempcp) + $i; + if ($rp->lhsalias && $tempcp == $rp->lhsalias) { + $this->append_str("\$this->_retvalue", 0); + $cp = $rp->code[$j]; + $i = $j; + $lhsused = 1; + } else { + for ($ii = 0; $ii < $rp->nrhs; $ii++) { + if ($rp->rhsalias[$ii] && $tempcp == $rp->rhsalias[$ii]) { + if ($ii !== 0 && $rp->code[$ii - 1] == '@') { + /* If the argument is of the form @X then substitute + ** the token number of X, not the value of X */ + $this->append_str("\$this->yystack[\$this->yyidx + " . + ($ii - $rp->nrhs + 1) . "]->major", -1); + } else { + $sp = $rp->rhs[$ii]; + if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + $dtnum = $sp->subsym[0]->dtnum; + } else { + $dtnum = $sp->dtnum; + } + $this->append_str("\$this->yystack[\$this->yyidx + " . + ($ii - $rp->nrhs + 1) . "]->minor", 0); + } + $cp = $rp->code[$j]; + $i = $j; + $used[$ii] = 1; + break; + } + } + } + } + $this->append_str($cp, 1); + } /* End loop */ + + /* Check to make sure the LHS has been used */ + if ($rp->lhsalias && !$lhsused) { + PHP_ParserGenerator::ErrorMsg($this->filename, $rp->ruleline, + "Label \"%s\" for \"%s(%s)\" is never used.", + $rp->lhsalias, $rp->lhs->name, $rp->lhsalias); + $this->errorcnt++; + } + + /* Generate destructor code for RHS symbols which are not used in the + ** reduce code */ + for($i = 0; $i < $rp->nrhs; $i++) { + if ($rp->rhsalias[$i] && !isset($used[$i])) { + PHP_ParserGenerator::ErrorMsg($this->filename, $rp->ruleline, + "Label %s for \"%s(%s)\" is never used.", + $rp->rhsalias[$i], $rp->rhs[$i]->name, $rp->rhsalias[$i]); + $this->errorcnt++; + } elseif ($rp->rhsalias[$i] == 0) { + if ($rp->rhs[$i]->type == PHP_ParserGenerator_Symbol::TERMINAL) { + $hasdestructor = $this->tokendest != 0; + }else{ + $hasdestructor = $this->vardest !== 0 || $rp->rhs[$i]->destructor !== 0; + } + if ($hasdestructor) { + $this->append_str(" \$this->yy_destructor(" . + ($rp->rhs[$i]->index) . ", \$this->yystack[\$this->yyidx + " . + ($i - $rp->nrhs + 1) . "]->minor);\n", 0); + } else { + /* No destructor defined for this term */ + } + } + } + $cp = $this->append_str('', 0); + $rp->code = $cp; + } + + /** + * The following routine emits code for the destructor for the + * symbol sp + */ + function emit_destructor_code($out, PHP_ParserGenerator_Symbol $sp, &$lineno) +// FILE *out; +// struct symbol *sp; +// struct lemon *lemp; +// int *lineno; + { + $cp = 0; + + $linecnt = 0; + if ($sp->type == PHP_ParserGenerator_Symbol::TERMINAL) { + $cp = $this->tokendest; + if ($cp === 0) { + return; + } + $this->tplt_linedir($out, $this->tokendestln, $this->filename); + fwrite($out, "{"); + } elseif ($sp->destructor) { + $cp = $sp->destructor; + $this->tplt_linedir($out, $sp->destructorln, $this->filename); + fwrite($out, "{"); + } elseif ($this->vardest) { + $cp = $this->vardest; + if ($cp === 0) { + return; + } + $this->tplt_linedir($out, $this->vardestln, $this->filename); + fwrite($out, "{"); + } else { + throw new Exception('emit_destructor'); /* Cannot happen */ + } + for ($i = 0; $i < strlen($cp); $i++) { + if ($cp[$i]=='$' && $cp[$i + 1]=='$' ) { + fprintf($out, "(yypminor->yy%d)", $sp->dtnum); + $i++; + continue; + } + if ($cp[$i] == "\n") { + $linecnt++; + } + fwrite($out, $cp[$i]); + } + $lineno += 3 + $linecnt; + fwrite($out, "}\n"); + $this->tplt_linedir($out, $lineno, $this->outname); + } + + /** + * Compare to axset structures for sorting purposes + */ + static function axset_compare($a, $b) + { + return $b['nAction'] - $a['nAction']; + } +} diff --git a/libs/lexer/ParserGenerator/Parser.php b/libs/lexer/ParserGenerator/Parser.php new file mode 100644 index 00000000..55305cf1 --- /dev/null +++ b/libs/lexer/ParserGenerator/Parser.php @@ -0,0 +1,844 @@ + + * @copyright 2006 Gregory Beaver + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version CVS: $Id: Parser.php,v 1.2 2007/03/02 16:36:24 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** + * The grammar parser for lemon grammar files. + * + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @since Class available since Release 0.1.0 + */ +class PHP_ParserGenerator_Parser +{ + const INITIALIZE = 1; + const WAITING_FOR_DECL_OR_RULE = 2; + const WAITING_FOR_DECL_KEYWORD = 3; + const WAITING_FOR_DECL_ARG = 4; + const WAITING_FOR_PRECEDENCE_SYMBOL = 5; + const WAITING_FOR_ARROW = 6; + const IN_RHS = 7; + const LHS_ALIAS_1 = 8; + const LHS_ALIAS_2 = 9; + const LHS_ALIAS_3 = 10; + const RHS_ALIAS_1 = 11; + const RHS_ALIAS_2 = 12; + const PRECEDENCE_MARK_1 = 13; + const PRECEDENCE_MARK_2 = 14; + const RESYNC_AFTER_RULE_ERROR = 15; + const RESYNC_AFTER_DECL_ERROR = 16; + const WAITING_FOR_DESTRUCTOR_SYMBOL = 17; + const WAITING_FOR_DATATYPE_SYMBOL = 18; + const WAITING_FOR_FALLBACK_ID = 19; + + /** + * Name of the input file + * + * @var string + */ + public $filename; + /** + * Linenumber at which current token starts + * @var int + */ + public $tokenlineno; + /** + * Number of parsing errors so far + * @var int + */ + public $errorcnt; + /** + * Index of current token within the input string + * @var int + */ + public $tokenstart; + /** + * Global state vector + * @var PHP_ParserGenerator_Data + */ + public $gp; + /** + * Parser state (one of the class constants for this class) + * + * - PHP_ParserGenerator_Parser::INITIALIZE, + * - PHP_ParserGenerator_Parser::WAITING_FOR_DECL_OR_RULE, + * - PHP_ParserGenerator_Parser::WAITING_FOR_DECL_KEYWORD, + * - PHP_ParserGenerator_Parser::WAITING_FOR_DECL_ARG, + * - PHP_ParserGenerator_Parser::WAITING_FOR_PRECEDENCE_SYMBOL, + * - PHP_ParserGenerator_Parser::WAITING_FOR_ARROW, + * - PHP_ParserGenerator_Parser::IN_RHS, + * - PHP_ParserGenerator_Parser::LHS_ALIAS_1, + * - PHP_ParserGenerator_Parser::LHS_ALIAS_2, + * - PHP_ParserGenerator_Parser::LHS_ALIAS_3, + * - PHP_ParserGenerator_Parser::RHS_ALIAS_1, + * - PHP_ParserGenerator_Parser::RHS_ALIAS_2, + * - PHP_ParserGenerator_Parser::PRECEDENCE_MARK_1, + * - PHP_ParserGenerator_Parser::PRECEDENCE_MARK_2, + * - PHP_ParserGenerator_Parser::RESYNC_AFTER_RULE_ERROR, + * - PHP_ParserGenerator_Parser::RESYNC_AFTER_DECL_ERROR, + * - PHP_ParserGenerator_Parser::WAITING_FOR_DESTRUCTOR_SYMBOL, + * - PHP_ParserGenerator_Parser::WAITING_FOR_DATATYPE_SYMBOL, + * - PHP_ParserGenerator_Parser::WAITING_FOR_FALLBACK_ID + * @var int + */ + public $state; + /** + * The fallback token + * @var PHP_ParserGenerator_Symbol + */ + public $fallback; + /** + * Left-hand side of the current rule + * @var PHP_ParserGenerator_Symbol + */ + public $lhs; + /** + * Alias for the LHS + * @var string + */ + public $lhsalias; + /** + * Number of right-hand side symbols seen + * @var int + */ + public $nrhs; + /** + * Right-hand side symbols + * @var array array of {@link PHP_ParserGenerator_Symbol} objects + */ + public $rhs = array(); + /** + * Aliases for each RHS symbol name (or NULL) + * @var array array of strings + */ + public $alias = array(); + /** + * Previous rule parsed + * @var PHP_ParserGenerator_Rule + */ + public $prevrule; + /** + * Keyword of a declaration + * + * This is one of the %keyword keywords in the grammar file + * @var string + */ + public $declkeyword; + /** + * Where the declaration argument should be put + * + * This is assigned as a reference to an internal variable + * @var mixed + */ + public $declargslot = array(); + /** + * Where the declaration linenumber is put + * + * This is assigned as a reference to an internal variable + * @var mixed + */ + public $decllnslot; + /*enum e_assoc*/ + public $declassoc; /* Assign this association to decl arguments */ + public $preccounter; /* Assign this precedence to decl arguments */ + /** + * @var PHP_ParserGenerator_Rule + */ + public $firstrule; /* Pointer to first rule in the grammar */ + /** + * @var PHP_ParserGenerator_Rule + */ + public $lastrule; /* Pointer to the most recently parsed rule */ + + /** + * @var PHP_ParserGenerator + */ + private $lemon; + + function __construct(PHP_ParserGenerator $lem) + { + $this->lemon = $lem; + } + + /** + * Run the preprocessor over the input file text. The Lemon variable + * $azDefine contains the names of all defined + * macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and + * comments them out. Text in between is also commented out as appropriate. + * @param string + */ + private function preprocess_input(&$z) + { + $lineno = $exclude = 0; + for ($i=0; $i < strlen($z); $i++) { + if ($z[$i] == "\n") { + $lineno++; + } + if ($z[$i] != '%' || ($i > 0 && $z[$i-1] != "\n")) { + continue; + } + if (substr($z, $i, 6) === "%endif" && trim($z[$i+6]) === '') { + if ($exclude) { + $exclude--; + if ($exclude === 0) { + for ($j = $start; $j < $i; $j++) { + if ($z[$j] != "\n") $z[$j] = ' '; + } + } + } + for ($j = $i; $j < strlen($z) && $z[$j] != "\n"; $j++) { + $z[$j] = ' '; + } + } elseif (substr($z, $i, 6) === "%ifdef" && trim($z[$i+6]) === '' || + substr($z, $i, 7) === "%ifndef" && trim($z[$i+7]) === '') { + if ($exclude) { + $exclude++; + } else { + $j = $i; + $n = strtok(substr($z, $j), " \t"); + $exclude = 1; + if (isset($this->lemon->azDefine[$n])) { + $exclude = 0; + } + if ($z[$i + 3]=='n') { + // this is a rather obtuse way of checking whether this is %ifndef + $exclude = !$exclude; + } + if ($exclude) { + $start = $i; + $start_lineno = $lineno; + } + } + //for ($j = $i; $j < strlen($z) && $z[$j] != "\n"; $j++) $z[$j] = ' '; + $j = strpos(substr($z, $i), "\n"); + if ($j === false) { + $z = substr($z, 0, $i); // remove instead of adding ' ' + } else { + $z = substr($z, 0, $i) . substr($z, $i + $j); // remove instead of adding ' ' + } + } + } + if ($exclude) { + throw new Exception("unterminated %ifdef starting on line $start_lineno\n"); + } + } + + /** + * In spite of its name, this function is really a scanner. + * + * It reads in the entire input file (all at once) then tokenizes it. + * Each token is passed to the function "parseonetoken" which builds all + * the appropriate data structures in the global state vector "gp". + * @param PHP_ParserGenerator_Data + */ + function Parse(PHP_ParserGenerator_Data $gp) + { + $startline = 0; + + $this->gp = $gp; + $this->filename = $gp->filename; + $this->errorcnt = 0; + $this->state = self::INITIALIZE; + + /* Begin by reading the input file */ + $filebuf = file_get_contents($this->filename); + if (!$filebuf) { + PHP_ParserGenerator::ErrorMsg($this->filename, 0, "Can't open this file for reading."); + $gp->errorcnt++; + return; + } + if (filesize($this->filename) != strlen($filebuf)) { + ErrorMsg($this->filename, 0, "Can't read in all %d bytes of this file.", + filesize($this->filename)); + $gp->errorcnt++; + return; + } + + /* Make an initial pass through the file to handle %ifdef and %ifndef */ + $this->preprocess_input($filebuf); + + /* Now scan the text of the input file */ + $lineno = 1; + for ($cp = 0, $c = $filebuf[0]; $cp < strlen($filebuf); $cp++) { + $c = $filebuf[$cp]; + if ($c == "\n") $lineno++; /* Keep track of the line number */ + if (trim($c) === '') { + continue; + } /* Skip all white space */ + if ($filebuf[$cp] == '/' && ($cp + 1 < strlen($filebuf)) && $filebuf[$cp + 1] == '/') { + /* Skip C++ style comments */ + $cp += 2; + $z = strpos(substr($filebuf, $cp), "\n"); + if ($z === false) { + $cp = strlen($filebuf); + break; + } + $lineno++; + $cp += $z; + continue; + } + if ($filebuf[$cp] == '/' && ($cp + 1 < strlen($filebuf)) && $filebuf[$cp + 1] == '*') { + /* Skip C style comments */ + $cp += 2; + $z = strpos(substr($filebuf, $cp), '*/'); + if ($z !== false) { + $lineno += count(explode("\n", substr($filebuf, $cp, $z))) - 1; + } + $cp += $z + 1; + continue; + } + $this->tokenstart = $cp; /* Mark the beginning of the token */ + $this->tokenlineno = $lineno; /* Linenumber on which token begins */ + if ($filebuf[$cp] == '"') { /* String literals */ + $cp++; + $oldcp = $cp; + $test = strpos(substr($filebuf, $cp), '"'); + if ($test === false) { + PHP_ParserGenerator::ErrorMsg($this->filename, $startline, + "String starting on this line is not terminated before the end of the file."); + $this->errorcnt++; + $nextcp = $cp = strlen($filebuf); + } else { + $cp += $test; + $nextcp = $cp + 1; + } + $lineno += count(explode("\n", substr($filebuf, $oldcp, $cp - $oldcp))) - 1; + } elseif ($filebuf[$cp] == '{') { /* A block of C code */ + $cp++; + for ($level = 1; $cp < strlen($filebuf) && ($level > 1 || $filebuf[$cp] != '}'); $cp++) { + if ($filebuf[$cp] == "\n") { + $lineno++; + } elseif ($filebuf[$cp] == '{') { + $level++; + } elseif ($filebuf[$cp] == '}') { + $level--; + } elseif ($filebuf[$cp] == '/' && $filebuf[$cp + 1] == '*') { + /* Skip comments */ + $cp += 2; + $z = strpos(substr($filebuf, $cp), '*/'); + if ($z !== false) { + $lineno += count(explode("\n", substr($filebuf, $cp, $z))) - 1; + } + $cp += $z + 2; + } elseif ($filebuf[$cp] == '/' && $filebuf[$cp + 1] == '/') { + /* Skip C++ style comments too */ + $cp += 2; + $z = strpos(substr($filebuf, $cp), "\n"); + if ($z === false) { + $cp = strlen($filebuf); + break; + } else { + $lineno++; + } + $cp += $z; + } elseif ($filebuf[$cp] == "'" || $filebuf[$cp] == '"') { + /* String a character literals */ + $startchar = $filebuf[$cp]; + $prevc = 0; + for ($cp++; $cp < strlen($filebuf) && ($filebuf[$cp] != $startchar || $prevc === '\\'); $cp++) { + if ($filebuf[$cp] == "\n") { + $lineno++; + } + if ($prevc === '\\') { + $prevc = 0; + } else { + $prevc = $filebuf[$cp]; + } + } + } + } + if ($cp >= strlen($filebuf)) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "PHP code starting on this line is not terminated before the end of the file."); + $this->errorcnt++; + $nextcp = $cp; + } else { + $nextcp = $cp + 1; + } + } elseif (preg_match('/[a-zA-Z0-9]/', $filebuf[$cp])) { + /* Identifiers */ + preg_match('/[a-zA-Z0-9_]+/', substr($filebuf, $cp), $preg_results); + $cp += strlen($preg_results[0]); + $nextcp = $cp; + } elseif ($filebuf[$cp] == ':' && $filebuf[$cp + 1] == ':' && + $filebuf[$cp + 2] == '=') { + /* The operator "::=" */ + $cp += 3; + $nextcp = $cp; + } elseif (($filebuf[$cp] == '/' || $filebuf[$cp] == '|') && + preg_match('/[a-zA-Z]/', $filebuf[$cp + 1])) { + $cp += 2; + preg_match('/[a-zA-Z0-9_]+/', substr($filebuf, $cp), $preg_results); + $cp += strlen($preg_results[0]); + $nextcp = $cp; + } else { + /* All other (one character) operators */ + $cp ++; + $nextcp = $cp; + } + $this->parseonetoken(substr($filebuf, $this->tokenstart, + $cp - $this->tokenstart)); /* Parse the token */ + $cp = $nextcp - 1; + } + $gp->rule = $this->firstrule; + $gp->errorcnt = $this->errorcnt; + } + + /** + * Parse a single token + * @param string token + */ + function parseonetoken($token) + { + $x = $token; + $this->a = 0; // for referencing in WAITING_FOR_DECL_KEYWORD + if (PHP_ParserGenerator::DEBUG) { + printf("%s:%d: Token=[%s] state=%d\n", + $this->filename, $this->tokenlineno, $token, $this->state); + } + switch ($this->state) { + case self::INITIALIZE: + $this->prevrule = 0; + $this->preccounter = 0; + $this->firstrule = $this->lastrule = 0; + $this->gp->nrule = 0; + /* Fall thru to next case */ + case self::WAITING_FOR_DECL_OR_RULE: + if ($x[0] == '%') { + $this->state = self::WAITING_FOR_DECL_KEYWORD; + } elseif (preg_match('/[a-z]/', $x[0])) { + $this->lhs = PHP_ParserGenerator_Symbol::Symbol_new($x); + $this->nrhs = 0; + $this->lhsalias = 0; + $this->state = self::WAITING_FOR_ARROW; + } elseif ($x[0] == '{') { + if ($this->prevrule === 0) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "There is no prior rule opon which to attach the code + fragment which begins on this line."); + $this->errorcnt++; + } elseif ($this->prevrule->code != 0) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Code fragment beginning on this line is not the first \ + to follow the previous rule."); + $this->errorcnt++; + } else { + $this->prevrule->line = $this->tokenlineno; + $this->prevrule->code = substr($x, 1); + } + } elseif ($x[0] == '[') { + $this->state = self::PRECEDENCE_MARK_1; + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Token \"%s\" should be either \"%%\" or a nonterminal name.", + $x); + $this->errorcnt++; + } + break; + case self::PRECEDENCE_MARK_1: + if (!preg_match('/[A-Z]/', $x[0])) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "The precedence symbol must be a terminal."); + $this->errorcnt++; + } elseif ($this->prevrule === 0) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "There is no prior rule to assign precedence \"[%s]\".", $x); + $this->errorcnt++; + } elseif ($this->prevrule->precsym != 0) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Precedence mark on this line is not the first to follow the previous rule."); + $this->errorcnt++; + } else { + $this->prevrule->precsym = PHP_ParserGenerator_Symbol::Symbol_new($x); + } + $this->state = self::PRECEDENCE_MARK_2; + break; + case self::PRECEDENCE_MARK_2: + if ($x[0] != ']') { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Missing \"]\" on precedence mark."); + $this->errorcnt++; + } + $this->state = self::WAITING_FOR_DECL_OR_RULE; + break; + case self::WAITING_FOR_ARROW: + if ($x[0] == ':' && $x[1] == ':' && $x[2] == '=') { + $this->state = self::IN_RHS; + } elseif ($x[0] == '(') { + $this->state = self::LHS_ALIAS_1; + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Expected to see a \":\" following the LHS symbol \"%s\".", + $this->lhs->name); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_RULE_ERROR; + } + break; + case self::LHS_ALIAS_1: + if (preg_match('/[A-Za-z]/', $x[0])) { + $this->lhsalias = $x; + $this->state = self::LHS_ALIAS_2; + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "\"%s\" is not a valid alias for the LHS \"%s\"\n", + $x, $this->lhs->name); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_RULE_ERROR; + } + break; + case self::LHS_ALIAS_2: + if ($x[0] == ')') { + $this->state = self::LHS_ALIAS_3; + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Missing \")\" following LHS alias name \"%s\".",$this->lhsalias); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_RULE_ERROR; + } + break; + case self::LHS_ALIAS_3: + if ($x == '::=') { + $this->state = self::IN_RHS; + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Missing \"->\" following: \"%s(%s)\".", + $this->lhs->name, $this->lhsalias); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_RULE_ERROR; + } + break; + case self::IN_RHS: + if ($x[0] == '.') { + $rp = new PHP_ParserGenerator_Rule; + $rp->ruleline = $this->tokenlineno; + for ($i = 0; $i < $this->nrhs; $i++) { + $rp->rhs[$i] = $this->rhs[$i]; + $rp->rhsalias[$i] = $this->alias[$i]; + } + if (count(array_unique($rp->rhsalias)) != count($rp->rhsalias)) { + $used = array(); + foreach ($rp->rhsalias as $i => $symbol) { + if (!is_string($symbol)) { + continue; + } + if (isset($used[$symbol])) { + PHP_ParserGenerator::ErrorMsg($this->filename, + $this->tokenlineno, + "RHS symbol \"%s\" used multiple times.", + $symbol); + $this->errorcnt++; + } else { + $used[$symbol] = $i; + } + } + } + $rp->lhs = $this->lhs; + $rp->lhsalias = $this->lhsalias; + $rp->nrhs = $this->nrhs; + $rp->code = 0; + $rp->precsym = 0; + $rp->index = $this->gp->nrule++; + $rp->nextlhs = $rp->lhs->rule; + $rp->lhs->rule = $rp; + $rp->next = 0; + if ($this->firstrule === 0) { + $this->firstrule = $this->lastrule = $rp; + } else { + $this->lastrule->next = $rp; + $this->lastrule = $rp; + } + $this->prevrule = $rp; + $this->state = self::WAITING_FOR_DECL_OR_RULE; + } elseif (preg_match('/[a-zA-Z]/', $x[0])) { + if ($this->nrhs >= PHP_ParserGenerator::MAXRHS) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Too many symbols on RHS or rule beginning at \"%s\".", + $x); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_RULE_ERROR; + } else { + if (isset($this->rhs[$this->nrhs - 1])) { + $msp = $this->rhs[$this->nrhs - 1]; + if ($msp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) { + $inf = array_reduce($msp->subsym, + array($this, '_printmulti'), ''); + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + 'WARNING: symbol ' . $x . ' will not' . + ' be part of previous multiterminal %s', + substr($inf, 0, strlen($inf) - 1) + ); + } + } + $this->rhs[$this->nrhs] = PHP_ParserGenerator_Symbol::Symbol_new($x); + $this->alias[$this->nrhs] = 0; + $this->nrhs++; + } + } elseif (($x[0] == '|' || $x[0] == '/') && $this->nrhs > 0) { + $msp = $this->rhs[$this->nrhs - 1]; + if ($msp->type != PHP_ParserGenerator_Symbol::MULTITERMINAL) { + $origsp = $msp; + $msp = new PHP_ParserGenerator_Symbol; + $msp->type = PHP_ParserGenerator_Symbol::MULTITERMINAL; + $msp->nsubsym = 1; + $msp->subsym = array($origsp); + $msp->name = $origsp->name; + $this->rhs[$this->nrhs - 1] = $msp; + } + $msp->nsubsym++; + $msp->subsym[$msp->nsubsym - 1] = PHP_ParserGenerator_Symbol::Symbol_new(substr($x, 1)); + if (preg_match('/[a-z]/', $x[1]) || + preg_match('/[a-z]/', $msp->subsym[0]->name[0])) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Cannot form a compound containing a non-terminal"); + $this->errorcnt++; + } + } elseif ($x[0] == '(' && $this->nrhs > 0) { + $this->state = self::RHS_ALIAS_1; + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Illegal character on RHS of rule: \"%s\".", $x); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_RULE_ERROR; + } + break; + case self::RHS_ALIAS_1: + if (preg_match('/[A-Za-z]/', $x[0])) { + $this->alias[$this->nrhs - 1] = $x; + $this->state = self::RHS_ALIAS_2; + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n", + $x, $this->rhs[$this->nrhs - 1]->name); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_RULE_ERROR; + } + break; + case self::RHS_ALIAS_2: + if ($x[0] == ')') { + $this->state = self::IN_RHS; + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Missing \")\" following LHS alias name \"%s\".", $this->lhsalias); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_RULE_ERROR; + } + break; + case self::WAITING_FOR_DECL_KEYWORD: + if(preg_match('/[A-Za-z]/', $x[0])) { + $this->declkeyword = $x; + $this->declargslot = &$this->a; + $this->decllnslot = &$this->a; + $this->state = self::WAITING_FOR_DECL_ARG; + if ('name' == $x) { + $this->declargslot = &$this->gp->name; + } elseif ('include' == $x) { + $this->declargslot = &$this->gp->include_code; + $this->decllnslot = &$this->gp->includeln; + } elseif ('include_class' == $x) { + $this->declargslot = &$this->gp->include_classcode; + $this->decllnslot = &$this->gp->include_classln; + } elseif ('declare_class' == $x) { + $this->declargslot = &$this->gp->declare_classcode; + $this->decllnslot = &$this->gp->declare_classln; + } elseif ('code' == $x) { + $this->declargslot = &$this->gp->extracode; + $this->decllnslot = &$this->gp->extracodeln; + } elseif ('token_destructor' == $x) { + $this->declargslot = &$this->gp->tokendest; + $this->decllnslot = &$this->gp->tokendestln; + } elseif ('default_destructor' == $x) { + $this->declargslot = &$this->gp->vardest; + $this->decllnslot = &$this->gp->vardestln; + } elseif ('token_prefix' == $x) { + $this->declargslot = &$this->gp->tokenprefix; + } elseif ('syntax_error' == $x) { + $this->declargslot = &$this->gp->error; + $this->decllnslot = &$this->gp->errorln; + } elseif ('parse_accept' == $x) { + $this->declargslot = &$this->gp->accept; + $this->decllnslot = &$this->gp->acceptln; + } elseif ('parse_failure' == $x) { + $this->declargslot = &$this->gp->failure; + $this->decllnslot = &$this->gp->failureln; + } elseif ('stack_overflow' == $x) { + $this->declargslot = &$this->gp->overflow; + $this->decllnslot = &$this->gp->overflowln; + } elseif ('token_type' == $x) { + $this->declargslot = &$this->gp->tokentype; + } elseif ('default_type' == $x) { + $this->declargslot = &$this->gp->vartype; + } elseif ('stack_size' == $x) { + $this->declargslot = &$this->gp->stacksize; + } elseif ('start_symbol' == $x) { + $this->declargslot = &$this->gp->start; + } elseif ('left' == $x) { + $this->preccounter++; + $this->declassoc = PHP_ParserGenerator_Symbol::LEFT; + $this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL; + } elseif ('right' == $x) { + $this->preccounter++; + $this->declassoc = PHP_ParserGenerator_Symbol::RIGHT; + $this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL; + } elseif ('nonassoc' == $x) { + $this->preccounter++; + $this->declassoc = PHP_ParserGenerator_Symbol::NONE; + $this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL; + } elseif ('destructor' == $x) { + $this->state = self::WAITING_FOR_DESTRUCTOR_SYMBOL; + } elseif ('type' == $x) { + $this->state = self::WAITING_FOR_DATATYPE_SYMBOL; + } elseif ('fallback' == $x) { + $this->fallback = 0; + $this->state = self::WAITING_FOR_FALLBACK_ID; + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Unknown declaration keyword: \"%%%s\".", $x); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_DECL_ERROR; + } + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Illegal declaration keyword: \"%s\".", $x); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_DECL_ERROR; + } + break; + case self::WAITING_FOR_DESTRUCTOR_SYMBOL: + if (!preg_match('/[A-Za-z]/', $x[0])) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Symbol name missing after %destructor keyword"); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_DECL_ERROR; + } else { + $sp = PHP_ParserGenerator_Symbol::Symbol_new($x); + $this->declargslot = &$sp->destructor; + $this->decllnslot = &$sp->destructorln; + $this->state = self::WAITING_FOR_DECL_ARG; + } + break; + case self::WAITING_FOR_DATATYPE_SYMBOL: + if (!preg_match('/[A-Za-z]/', $x[0])) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Symbol name missing after %destructor keyword"); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_DECL_ERROR; + } else { + $sp = PHP_ParserGenerator_Symbol::Symbol_new($x); + $this->declargslot = &$sp->datatype; + $this->state = self::WAITING_FOR_DECL_ARG; + } + break; + case self::WAITING_FOR_PRECEDENCE_SYMBOL: + if ($x[0] == '.') { + $this->state = self::WAITING_FOR_DECL_OR_RULE; + } elseif (preg_match('/[A-Z]/', $x[0])) { + $sp = PHP_ParserGenerator_Symbol::Symbol_new($x); + if ($sp->prec >= 0) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Symbol \"%s\" has already been given a precedence.", $x); + $this->errorcnt++; + } else { + $sp->prec = $this->preccounter; + $sp->assoc = $this->declassoc; + } + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Can't assign a precedence to \"%s\".", $x); + $this->errorcnt++; + } + break; + case self::WAITING_FOR_DECL_ARG: + if (preg_match('/[A-Za-z0-9{"]/', $x[0])) { + if ($this->declargslot != 0) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "The argument \"%s\" to declaration \"%%%s\" is not the first.", + $x[0] == '"' ? substr($x, 1) : $x, $this->declkeyword); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_DECL_ERROR; + } else { + $this->declargslot = ($x[0] == '"' || $x[0] == '{') ? substr($x, 1) : $x; + $this->a = 1; + if (!$this->decllnslot) { + $this->decllnslot = $this->tokenlineno; + } + $this->state = self::WAITING_FOR_DECL_OR_RULE; + } + } else { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "Illegal argument to %%%s: %s",$this->declkeyword, $x); + $this->errorcnt++; + $this->state = self::RESYNC_AFTER_DECL_ERROR; + } + break; + case self::WAITING_FOR_FALLBACK_ID: + if ($x[0] == '.') { + $this->state = self::WAITING_FOR_DECL_OR_RULE; + } elseif (!preg_match('/[A-Z]/', $x[0])) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "%%fallback argument \"%s\" should be a token", $x); + $this->errorcnt++; + } else { + $sp = PHP_ParserGenerator_Symbol::Symbol_new($x); + if ($this->fallback === 0) { + $this->fallback = $sp; + } elseif (is_object($sp->fallback)) { + PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno, + "More than one fallback assigned to token %s", $x); + $this->errorcnt++; + } else { + $sp->fallback = $this->fallback; + $this->gp->has_fallback = 1; + } + } + break; + case self::RESYNC_AFTER_RULE_ERROR: + /* if ($x[0] == '.') $this->state = self::WAITING_FOR_DECL_OR_RULE; + ** break; */ + case self::RESYNC_AFTER_DECL_ERROR: + if ($x[0] == '.') { + $this->state = self::WAITING_FOR_DECL_OR_RULE; + } + if ($x[0] == '%') { + $this->state = self::WAITING_FOR_DECL_KEYWORD; + } + break; + } + } + + /** + * return a descriptive string for a multi-terminal token. + * + * @param string $a + * @param string $b + * @return string + */ + private function _printmulti($a, $b) + { + if (!$a) { + $a = ''; + } + $a .= $b->name . '|'; + return $a; + } +} diff --git a/libs/lexer/ParserGenerator/PropagationLink.php b/libs/lexer/ParserGenerator/PropagationLink.php new file mode 100644 index 00000000..85d7a1df --- /dev/null +++ b/libs/lexer/ParserGenerator/PropagationLink.php @@ -0,0 +1,117 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_ParserGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: PropagationLink.php,v 1.1 2006/07/18 00:53:10 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** + * A followset propagation link indicates that the contents of one + * configuration followset should be propagated to another whenever + * the first changes. + * + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version 0.1.5 + * @since Class available since Release 0.1.0 + */ + +class PHP_ParserGenerator_PropagationLink { + /** + * The configuration that defines this propagation link + * @var PHP_ParserGenerator_Config + */ + public $cfp; + /** + * The next propagation link + * @var PHP_ParserGenerator_PropagationLink|0 + */ + public $next = 0; + + /** + * Add a propagation link to the current list + * + * This prepends the configuration passed in to the first parameter + * which is either 0 or a PHP_ParserGenerator_PropagationLink defining + * an existing list. + * @param PHP_ParserGenerator_PropagationLink|null + * @param PHP_ParserGenerator_Config + */ + static function Plink_add(&$plpp, PHP_ParserGenerator_Config $cfp) + { + $new = new PHP_ParserGenerator_PropagationLink; + $new->next = $plpp; + $plpp = $new; + $new->cfp = $cfp; + } + + /** + * Transfer every propagation link on the list "from" to the list "to" + */ + static function Plink_copy(PHP_ParserGenerator_PropagationLink &$to, + PHP_ParserGenerator_PropagationLink $from) + { + while ($from) { + $nextpl = $from->next; + $from->next = $to; + $to = $from; + $from = $nextpl; + } + } + + /** + * Delete every propagation link on the list + * @param PHP_ParserGenerator_PropagationLink|0 + */ + static function Plink_delete($plp) + { + while ($plp) { + $nextpl = $plp->next; + $plp->next = 0; + $plp = $nextpl; + } + } +} + diff --git a/libs/lexer/ParserGenerator/Rule.php b/libs/lexer/ParserGenerator/Rule.php new file mode 100644 index 00000000..d36b5980 --- /dev/null +++ b/libs/lexer/ParserGenerator/Rule.php @@ -0,0 +1,140 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_ParserGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Rule.php,v 1.1 2006/07/18 00:53:10 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** + * Each production rule in the grammar is stored in this class + * + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version 0.1.5 + * @since Class available since Release 0.1.0 + */ +class PHP_ParserGenerator_Rule { + /** + * Left-hand side of the rule + * @var array an array of {@link PHP_ParserGenerator_Symbol} objects + */ + public $lhs; + /** + * Alias for the LHS (NULL if none) + * + * @var array + */ + public $lhsalias = array(); + /** + * Line number for the rule + * @var int + */ + public $ruleline; + /** + * Number of right-hand side symbols + */ + public $nrhs; + /** + * The right-hand side symbols + * @var array an array of {@link PHP_ParserGenerator_Symbol} objects + */ + public $rhs; + /** + * Aliases for each right-hand side symbol, or null if no alis. + * + * In this rule: + *
+     * foo ::= BAR(A) baz(B).
+     * 
+ * + * The right-hand side aliases are A for BAR, and B for baz. + * @var array aliases are indexed by the right-hand side symbol index. + */ + public $rhsalias = array(); + /** + * Line number at which code begins + * @var int + */ + public $line; + /** + * The code executed when this rule is reduced + * + *
+     * foo(R) ::= BAR(A) baz(B). {R = A + B;}
+     * 
+ * + * In the rule above, the code is "R = A + B;" + * @var string|0 + */ + public $code; + /** + * Precedence symbol for this rule + * @var PHP_ParserGenerator_Symbol + */ + public $precsym; + /** + * An index number for this rule + * + * Used in both naming of reduce functions and determining which rule code + * to use for reduce actions + * @var int + */ + public $index; + /** + * True if this rule is ever reduced + * @var boolean + */ + public $canReduce; + /** + * Next rule with the same left-hand side + * @var PHP_ParserGenerator_Rule|0 + */ + public $nextlhs; + /** + * Next rule in the global list + * @var PHP_ParserGenerator_Rule|0 + */ + public $next; +} diff --git a/libs/lexer/ParserGenerator/State.php b/libs/lexer/ParserGenerator/State.php new file mode 100644 index 00000000..350a07ef --- /dev/null +++ b/libs/lexer/ParserGenerator/State.php @@ -0,0 +1,277 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_ParserGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: State.php,v 1.1 2006/07/18 00:53:10 cellog Exp $ + * @since File available since Release 0.1.0 + */ + +/** + * The structure used to represent a state in the associative array + * for a PHP_ParserGenerator_Config. + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version 0.1.5 + * @since Class available since Release 0.1.0 + */ +class PHP_ParserGenerator_StateNode +{ + public $key; + public $data; + public $from = 0; + public $next = 0; +} + +/** + * Each state of the generated parser's finite state machine + * is encoded as an instance of this class + * + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version 0.1.5 + * @since Class available since Release 0.1.0 + */ +class PHP_ParserGenerator_State { + /** + * The basis configurations for this state + * @var PHP_ParserGenerator_Config + */ + public $bp; + /** + * All configurations in this state + * @var PHP_ParserGenerator_Config + */ + public $cfp; + /** + * Sequential number for this state + * + * @var int + */ + public $statenum; + /** + * Linked list of actions for this state. + * @var PHP_ParserGenerator_Action + */ + public $ap; + /** + * Number of terminal (token) actions + * + * @var int + */ + public $nTknAct, + /** + * Number of non-terminal actions + * + * @var int + */ + $nNtAct; + /** + * The offset into the $yy_action table for terminal tokens. + * + * @var int + */ + public $iTknOfst, + /** + * The offset into the $yy_action table for non-terminals. + * + * @var int + */ + $iNtOfst; + /** + * Default action + * + * @var int + */ + public $iDflt; + /** + * Associative array of PHP_ParserGenerator_State objects + * + * @var array + */ + public static $x3a = array(); + /** + * Array of PHP_ParserGenerator_State objects + * + * @var array + */ + public static $states = array(); + + /** + * Compare two states for sorting purposes. The smaller state is the + * one with the most non-terminal actions. If they have the same number + * of non-terminal actions, then the smaller is the one with the most + * token actions. + */ + static function stateResortCompare($a, $b) + { + $n = $b->nNtAct - $a->nNtAct; + if ($n === 0) { + $n = $b->nTknAct - $a->nTknAct; + } + return $n; + } + + /** + * Compare two states based on their configurations + * + * @param PHP_ParserGenerator_Config|0 $a + * @param PHP_ParserGenerator_Config|0 $b + * @return int + */ + static function statecmp($a, $b) + { + for ($rc = 0; $rc == 0 && $a && $b; $a = $a->bp, $b = $b->bp) { + $rc = $a->rp->index - $b->rp->index; + if ($rc === 0) { + $rc = $a->dot - $b->dot; + } + } + if ($rc == 0) { + if ($a) { + $rc = 1; + } + if ($b) { + $rc = -1; + } + } + return $rc; + } + + /** + * Hash a state based on its configuration + * @return int + */ + private static function statehash(PHP_ParserGenerator_Config $a) + { + $h = 0; + while ($a) { + $h = $h * 571 + $a->rp->index * 37 + $a->dot; + $a = $a->bp; + } + return (int) $h; + } + + /** + * Return a pointer to data assigned to the given key. Return NULL + * if no such key. + * @param PHP_ParserGenerator_Config + * @return null|PHP_ParserGenerator_State + */ + static function State_find(PHP_ParserGenerator_Config $key) + { + if (!count(self::$x3a)) { + return 0; + } + $h = self::statehash($key); + if (!isset(self::$x3a[$h])) { + return 0; + } + $np = self::$x3a[$h]; + while ($np) { + if (self::statecmp($np->key, $key) == 0) { + break; + } + $np = $np->next; + } + return $np ? $np->data : 0; + } + + /** + * Insert a new record into the array. Return TRUE if successful. + * Prior data with the same key is NOT overwritten + * + * @param PHP_ParserGenerator_State $state + * @param PHP_ParserGenerator_Config $key + * @return unknown + */ + static function State_insert(PHP_ParserGenerator_State $state, + PHP_ParserGenerator_Config $key) + { + $h = self::statehash($key); + if (isset(self::$x3a[$h])) { + $np = self::$x3a[$h]; + } else { + $np = 0; + } + while ($np) { + if (self::statecmp($np->key, $key) == 0) { + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + $np = $np->next; + } + /* Insert the new data */ + $np = new PHP_ParserGenerator_StateNode; + $np->key = $key; + $np->data = $state; + self::$states[] = $np; + // the original lemon code sets the from link always to itself + // setting up a faulty double-linked list + // however, the from links are never used, so I suspect a copy/paste + // error from a standard algorithm that was never caught + if (isset(self::$x3a[$h])) { + self::$x3a[$h]->from = $np; // lemon has $np->next here + } else { + self::$x3a[$h] = 0; // dummy to avoid notice + } + $np->next = self::$x3a[$h]; + self::$x3a[$h] = $np; + $np->from = self::$x3a[$h]; + return 1; + } + + /** + * Get an array indexed by state number + * + * @return array + */ + static function State_arrayof() + { + return self::$states; + } +} diff --git a/libs/lexer/ParserGenerator/Symbol.php b/libs/lexer/ParserGenerator/Symbol.php new file mode 100644 index 00000000..894a3940 --- /dev/null +++ b/libs/lexer/ParserGenerator/Symbol.php @@ -0,0 +1,284 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * * Neither the name of the PHP_ParserGenerator nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category php + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Symbol.php,v 1.1 2006/07/18 00:53:10 cellog Exp $ + * @since File available since Release 0.1.0 + */ +/** + * Symbols (terminals and nonterminals) of the grammar are stored in this class + * + * @package PHP_ParserGenerator + * @author Gregory Beaver + * @copyright 2006 Gregory Beaver + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version 0.1.5 + * @since Class available since Release 0.1.0 + */ +class PHP_ParserGenerator_Symbol +{ + /** + * Symbols that start with a capital letter like FOO. + * + * These are tokens directly from the lexer + */ + const TERMINAL = 1; + /** + * Symbols that start with a lower-case letter like foo. + * + * These are grammar rules like "foo ::= BLAH." + */ + const NONTERMINAL = 2; + /** + * Multiple terminal symbols. + * + * These are a grammar rule that consists of several terminals like + * FOO|BAR|BAZ. Note that non-terminals cannot be in a multi-terminal, + * and a multi-terminal acts like a single terminal. + * + * "FOO|BAR FOO|BAZ" is actually two multi-terminals, FOO|BAR and FOO|BAZ. + */ + const MULTITERMINAL = 3; + + const LEFT = 1; + const RIGHT = 2; + const NONE = 3; + const UNK = 4; + /** + * Name of the symbol + * + * @var string + */ + public $name; + /** + * Index of this symbol. + * + * This will ultimately end up representing the symbol in the generated + * parser + * @var int + */ + public $index; + /** + * Symbol type + * + * One of PHP_ParserGenerator_Symbol::TERMINAL, + * PHP_ParserGenerator_Symbol::NONTERMINAL or + * PHP_ParserGenerator_Symbol::MULTITERMINAL + * @var int + */ + public $type; + /** + * Linked list of rules that use this symbol, if it is a non-terminal. + * @var PHP_ParserGenerator_Rule + */ + public $rule; + /** + * Fallback token in case this token doesn't parse + * @var PHP_ParserGenerator_Symbol + */ + public $fallback; + /** + * Precendence, if defined. + * + * -1 if no unusual precedence + * @var int + */ + public $prec = -1; + /** + * Associativity if precedence is defined. + * + * One of PHP_ParserGenerator_Symbol::LEFT, + * PHP_ParserGenerator_Symbol::RIGHT, PHP_ParserGenerator_Symbol::NONE + * or PHP_ParserGenerator_Symbol::UNK + * @var unknown_type + */ + public $assoc; + /** + * First-set for all rules of this symbol + * + * @var array + */ + public $firstset; + /** + * True if this symbol is a non-terminal and can generate an empty + * result. + * + * For instance "foo ::= ." + * @var boolean + */ + public $lambda; + /** + * Code that executes whenever this symbol is popped from the stack during + * error processing. + * + * @var string|0 + */ + public $destructor = 0; + /** + * Line number of destructor code + * @var int + */ + public $destructorln; + /** + * Unused relic of the C version of Lemon. + * + * The data type of information held by this object. Only used + * if this is a non-terminal + * @var string + */ + public $datatype; + /** + * Unused relic of the C version of Lemon. + * + * The data type number. In the parser, the value + * stack is a union. The .yy%d element of this + * union is the correct data type for this object + * @var string + */ + public $dtnum; + /**#@+ + * The following fields are used by MULTITERMINALs only + */ + /** + * Number of terminal symbols in the MULTITERMINAL + * + * This is of course the same as count($this->subsym) + * @var int + */ + public $nsubsym; + /** + * Array of terminal symbols in the MULTITERMINAL + * @var array an array of {@link PHP_ParserGenerator_Symbol} objects + */ + public $subsym = array(); + /**#@-*/ + /** + * Singleton storage of symbols + * + * @var array an array of PHP_ParserGenerator_Symbol objects + */ + private static $symbol_table = array(); + /** + * Return a pointer to the (terminal or nonterminal) symbol "x". + * Create a new symbol if this is the first time "x" has been seen. + * (this is a singleton) + * @param string + * @return PHP_ParserGenerator_Symbol + */ + public static function Symbol_new($x) + { + if (isset(self::$symbol_table[$x])) { + return self::$symbol_table[$x]; + } + $sp = new PHP_ParserGenerator_Symbol; + $sp->name = $x; + $sp->type = preg_match('/[A-Z]/', $x[0]) ? self::TERMINAL : self::NONTERMINAL; + $sp->rule = 0; + $sp->fallback = 0; + $sp->prec = -1; + $sp->assoc = self::UNK; + $sp->firstset = array(); + $sp->lambda = false; + $sp->destructor = 0; + $sp->datatype = 0; + self::$symbol_table[$sp->name] = $sp; + return $sp; + } + + /** + * Return the number of unique symbols + * @return int + */ + public static function Symbol_count() + { + return count(self::$symbol_table); + } + + public static function Symbol_arrayof() + { + return array_values(self::$symbol_table); + } + + public static function Symbol_find($x) + { + if (isset(self::$symbol_table[$x])) { + return self::$symbol_table[$x]; + } + return 0; + } + + /** + * Sort function helper for symbols + * + * Symbols that begin with upper case letters (terminals or tokens) + * must sort before symbols that begin with lower case letters + * (non-terminals). Other than that, the order does not matter. + * + * We find experimentally that leaving the symbols in their original + * order (the order they appeared in the grammar file) gives the + * smallest parser tables in SQLite. + * @param PHP_ParserGenerator_Symbol + * @param PHP_ParserGenerator_Symbol + */ + public static function sortSymbols($a, $b) + { + $i1 = $a->index + 10000000*(ord($a->name[0]) > ord('Z')); + $i2 = $b->index + 10000000*(ord($b->name[0]) > ord('Z')); + return $i1 - $i2; + } + + /** + * Return true if two symbols are the same. + */ + public static function same_symbol(PHP_ParserGenerator_Symbol $a, PHP_ParserGenerator_Symbol $b) + { + if ($a === $b) return 1; + if ($a->type != self::MULTITERMINAL) return 0; + if ($b->type != self::MULTITERMINAL) return 0; + if ($a->nsubsym != $b->nsubsym) return 0; + for ($i = 0; $i < $a->nsubsym; $i++) { + if ($a->subsym[$i] != $b->subsym[$i]) return 0; + } + return 1; + } +} diff --git a/libs/lexer/ParserGenerator/cli.php b/libs/lexer/ParserGenerator/cli.php new file mode 100644 index 00000000..059eeba2 --- /dev/null +++ b/libs/lexer/ParserGenerator/cli.php @@ -0,0 +1,5 @@ +main(); +?> diff --git a/libs/lexer/internal.configfilelexer.plex b/libs/lexer/internal.configfilelexer.plex new file mode 100644 index 00000000..2d1e1f53 --- /dev/null +++ b/libs/lexer/internal.configfilelexer.plex @@ -0,0 +1,108 @@ +data = $data; + $this->counter = 0; + $this->line = 1; + $this->smarty = Smarty::instance(); + } + public static function &instance($new_instance = null) + { + static $instance = null; + if (isset($new_instance) && is_object($new_instance)) + $instance = $new_instance; + return $instance; + } + + +/*!lex2php +%input $this->data +%counter $this->counter +%token $this->token +%value $this->value +%line $this->line +commentstart = /#/ +openB = /\[/ +closeB = /]/ +number = /\d+(\.\d+)?/ +dot = /\./ +equal = /\s*\=\s*/ +eol = /(\n|\r\n)/ +space = /[\s]+/ +id = /\w+/ +si_qstr = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'' +ml_qstr = '\"\"\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"\"\"' +do_qstr = '\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"' +other = /./ +*/ +/*!lex2php +%statename START + +commentstart { + $this->token = Smarty_Internal_Configfileparser::TPC_COMMENTSTART; +} +si_qstr { + $this->token = Smarty_Internal_Configfileparser::TPC_SI_QSTR; +} +ml_qstr { + $this->token = Smarty_Internal_Configfileparser::TPC_ML_QSTR; +} +do_qstr { + $this->token = Smarty_Internal_Configfileparser::TPC_DO_QSTR; +} +openB { + $this->token = Smarty_Internal_Configfileparser::TPC_OPENB; +} +closeB { + $this->token = Smarty_Internal_Configfileparser::TPC_CLOSEB; +} +equal { + $this->token = Smarty_Internal_Configfileparser::TPC_EQUAL; +} +number { + $this->token = Smarty_Internal_Configfileparser::TPC_NUMBER; +} +eol { + $this->token = Smarty_Internal_Configfileparser::TPC_EOL; +} +space { + $this->token = Smarty_Internal_Configfileparser::TPC_SPACE; +} +dot { + $this->token = Smarty_Internal_Configfileparser::TPC_DOT; +} +id { + $this->token = Smarty_Internal_Configfileparser::TPC_ID; +} +other { + $this->token = Smarty_Internal_Configfileparser::TPC_OTHER; +} +*/ +} diff --git a/libs/lexer/internal.configfileparser.y b/libs/lexer/internal.configfileparser.y new file mode 100644 index 00000000..4e0eaea7 --- /dev/null +++ b/libs/lexer/internal.configfileparser.y @@ -0,0 +1,123 @@ +/** +* Smarty Internal Plugin Configfileparser +* +* This is the config file parser +* +* +* @package Smarty +* @subpackage Config +* @author Uwe Tews +*/ +%name TPC_ +%declare_class {class Smarty_Internal_Configfileparser} +%include_class +{ + // states whether the parse was successful or not + public $successful = true; + public $retvalue = 0; + private $lex; + private $internalError = false; + + function __construct($lex, $compiler) { + // set instance object + self::instance($this); + $this->lex = $lex; + $this->smarty = Smarty::instance(); + $this->compiler = $compiler; + $this->current_section = null; + $this->hidden_section = false; + } + public static function &instance($new_instance = null) + { + static $instance = null; + if (isset($new_instance) && is_object($new_instance)) + $instance = $new_instance; + return $instance; + } + +} + + +%token_prefix TPC_ + +%parse_accept +{ + $this->successful = !$this->internalError; + $this->internalError = false; + $this->retvalue = $this->_retvalue; + //echo $this->retvalue."\n\n"; +} + +%syntax_error +{ + $this->internalError = true; + $this->yymajor = $yymajor; + $this->compiler->trigger_config_file_error(); +} + +// +// fallback definition to catch all non Smarty template text +// +%fallback OTHER COMMENTSTART NUMBER OPENB CLOSEB DOT BOOLEANTRUE BOOLEANFALSE SI_QSTR DO_QSTR EQUAL SPACE ID. + + +// +// complete config file +// +start(res) ::= config(r). { res = r; } + +// +// loop over config file elements +// + // single config element +config(res) ::= config_element(e). {res = e;} + // loop of elements +config(res) ::= config(c) config_element(e). {res = c.e;} + +// +// config elements +// + // Section defifinition +config_element(res) ::= OPENB ID(i) CLOSEB EOL. { $this->hidden_section = false; $this->current_section = i; res ='';} + // Hidden section defifinition +config_element(res) ::= OPENB DOT ID(i) CLOSEB EOL. { if ($this->smarty->config_read_hidden) { + $this->hidden_section = false; $this->current_section = i; + } else {$this->hidden_section = true; } res ='';} +// variable assignment +config_element(res) ::= ID(i) EQUAL value(v) EOL. {if (!$this->hidden_section) { + $value=v; + if ($this->smarty->config_booleanize) { + if (in_array(strtolower($value),array('on','yes','true'))) + $value = true; + else if (in_array(strtolower($value),array('off','no','false'))) + $value = false; + } + if ($this->current_section == null) { + if ($this->smarty->config_overwrite) { + $this->compiler->config_data['vars'][i]=$value; + } else { + settype($this->compiler->config_data['vars'][i], 'array'); + $this->compiler->config_data['vars'][i][]=$value; + } + } else { + if ($this->smarty->config_overwrite) { + $this->compiler->config_data['sections'][$this->current_section]['vars'][i]=$value; + } else { + settype($this->compiler->config_data['sections'][$this->current_section]['vars'][i], 'array'); + $this->compiler->config_data['sections'][$this->current_section]['vars'][i][]=$value; + } + }} res ='';} +// empty and comment lines +config_element(res) ::= EOL. { res ='';} +config_element(res) ::= COMMENTSTART text(t) EOL. { res ='';} + +value(res) ::= text(t). {res = t;} +value(res) ::= SI_QSTR(s). {res = trim(s,"'");} +value(res) ::= DO_QSTR(s). {res = trim(s,'"');} +value(res) ::= ML_QSTR(s). {res = trim(s,'"');} +value(res) ::= NUMBER(n). {res = (int)n;} + + +text(res) ::= text(t) textelement(e). {res = t.e;} +text(res) ::= textelement(e). {res = e;} +textelement(res) ::= OTHER(o). {res = o;} diff --git a/libs/lexer/internal.templatelexer.php b/libs/lexer/internal.templatelexer.php new file mode 100644 index 00000000..979a33fd --- /dev/null +++ b/libs/lexer/internal.templatelexer.php @@ -0,0 +1,708 @@ + '{', + 'RDEL' => '}', + 'IDENTITY' => '===', + 'NONEIDENTITY' => '!==', + 'EQUALS' => '==', + 'NOTEQUALS' => '!=', + 'GREATEREQUAL' => '(>=,GE)', + 'LESSEQUAL' => '(<=,LE)', + 'GREATERTHAN' => '(>,GT)', + 'LESSTHAN' => '(<,LT)', + 'NOT' => '(!,NOT)', + 'LAND' => '(&&,AND)', + 'LOR' => '(||,OR)', + 'OPENP' => '(', + 'CLOSEP' => ')', + 'OPENB' => '[', + 'CLOSEB' => ']', + 'PTR' => '->', + 'APTR' => '=>', + 'EQUAL' => '=', + 'NUMBER' => 'number', + 'UNIMATH' => '+" , "-', + 'MATH' => '*" , "/" , "%', + 'INCDEC' => '++" , "--', + 'SPACE' => ' ', + 'DOLLAR' => '$', + 'SEMICOLON' => ';', + 'COLON' => ':', + 'DOUBLECOLON' => '::', + 'AT' => '@', + 'HATCH' => '#', + 'QUOTE' => '"', + 'SINGLEQUOTE' => "'", + 'BACKTICK' => '`', + 'VERT' => '|', + 'DOT' => '.', + 'COMMA' => '","', + 'ANDSYM' => '"&"', + 'ID' => 'identifier', + 'OTHER' => 'text', + 'PHP' => 'PHP code', + 'LDELSLASH' => 'closing tag', + 'COMMENTSTART' => '{*', + 'COMMENTEND' => '*}', + 'LITERALEND' => 'literal close', + 'IN' => 'in', + 'NULL' => 'null', + 'BOOLEAN' => 'boolean' + ); + + + function __construct($data) + { + // set instance object + self::instance($this); + $this->data = $data; + $this->counter = 0; + $this->line = 1; + $this->smarty = Smarty::instance(); + $this->ldel = preg_quote($this->smarty->left_delimiter); + $this->rdel = preg_quote($this->smarty->right_delimiter); + } + public static function &instance($new_instance = null) + { + static $instance = null; + if (isset($new_instance) && is_object($new_instance)) + $instance = $new_instance; + return $instance; + } + + + + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{'yylex' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + + + + function yylex1() + { + $tokenMap = array ( + 1 => 0, + 2 => 0, + 3 => 0, + 4 => 0, + 5 => 0, + 6 => 0, + 7 => 0, + 8 => 0, + 9 => 1, + 11 => 0, + 12 => 0, + 13 => 0, + 14 => 0, + 15 => 0, + 16 => 0, + 17 => 0, + 18 => 0, + 19 => 0, + 20 => 0, + 21 => 1, + 23 => 0, + 24 => 0, + 25 => 0, + 26 => 0, + 27 => 1, + 29 => 1, + 31 => 1, + 33 => 1, + 35 => 1, + 37 => 1, + 39 => 1, + 41 => 1, + 43 => 1, + 45 => 0, + 46 => 0, + 47 => 0, + 48 => 0, + 49 => 0, + 50 => 0, + 51 => 0, + 52 => 0, + 53 => 0, + 54 => 0, + 55 => 0, + 56 => 0, + 57 => 0, + 58 => 0, + 59 => 0, + 60 => 0, + 61 => 0, + 62 => 1, + 64 => 1, + 66 => 1, + 68 => 1, + 70 => 0, + 71 => 0, + 72 => 0, + 73 => 0, + 74 => 0, + 75 => 0, + 76 => 0, + 77 => 0, + 78 => 0, + 79 => 0, + 80 => 0, + 81 => 0, + 82 => 0, + 83 => 0, + 84 => 0, + ); + if ($this->counter >= strlen($this->data)) { + return false; // end of input + } + $yy_global_pattern = "/^(<\\?xml.*\\?>)|^(<\\?php.*\\?>)|^(<\\?=)|^(\\?>)|^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)/"; + + do { + if (preg_match($yy_global_pattern, substr($this->data, $this->counter), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + if (!count($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . + 'an empty string. Input "' . substr($this->data, + $this->counter, 5) . '... state START'); + } + next($yymatches); // skip global match + $this->token = key($yymatches); // token number + if ($tokenMap[$this->token]) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, $this->token + 1, + $tokenMap[$this->token]); + } else { + $yysubmatches = array(); + } + $this->value = current($yymatches); // token value + $r = $this->{'yy_r1_' . $this->token}($yysubmatches); + if ($r === null) { + $this->counter += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + $this->counter += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + if ($this->counter >= strlen($this->data)) { + return false; // end of input + } + // skip this token + continue; + } else { $yy_yymore_patterns = array( + 1 => array(0, "^(<\\?php.*\\?>)|^(<\\?=)|^(\\?>)|^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 2 => array(0, "^(<\\?=)|^(\\?>)|^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 3 => array(0, "^(\\?>)|^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 4 => array(0, "^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 5 => array(0, "^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 6 => array(0, "^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 7 => array(0, "^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 8 => array(0, "^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 9 => array(1, "^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 11 => array(1, "^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 12 => array(1, "^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 13 => array(1, "^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 14 => array(1, "^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 15 => array(1, "^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 16 => array(1, "^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 17 => array(1, "^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 18 => array(1, "^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 19 => array(1, "^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 20 => array(1, "^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 21 => array(2, "^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 23 => array(2, "^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 24 => array(2, "^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 25 => array(2, "^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 26 => array(2, "^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 27 => array(3, "^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 29 => array(4, "^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 31 => array(5, "^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 33 => array(6, "^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 35 => array(7, "^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 37 => array(8, "^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 39 => array(9, "^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 41 => array(10, "^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 43 => array(11, "^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 45 => array(11, "^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 46 => array(11, "^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 47 => array(11, "^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 48 => array(11, "^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 49 => array(11, "^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 50 => array(11, "^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 51 => array(11, "^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 52 => array(11, "^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 53 => array(11, "^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 54 => array(11, "^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 55 => array(11, "^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 56 => array(11, "^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 57 => array(11, "^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 58 => array(11, "^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 59 => array(11, "^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 60 => array(11, "^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 61 => array(11, "^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 62 => array(12, "^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 64 => array(13, "^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 66 => array(14, "^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 68 => array(15, "^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 70 => array(15, "^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 71 => array(15, "^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 72 => array(15, "^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 73 => array(15, "^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 74 => array(15, "^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 75 => array(15, "^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 76 => array(15, "^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 77 => array(15, "^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 78 => array(15, "^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 79 => array(15, "^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 80 => array(15, "^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"), + 81 => array(15, "^(\\s?&\\s?)|^(\\w+)|^(.)"), + 82 => array(15, "^(\\w+)|^(.)"), + 83 => array(15, "^(.)"), + 84 => array(15, ""), + ); + + // yymore is needed + do { + if (!strlen($yy_yymore_patterns[$this->token][1])) { + throw new Exception('cannot do yymore for the last token'); + } + $yysubmatches = array(); + if (preg_match('/' . $yy_yymore_patterns[$this->token][1] . '/', + substr($this->data, $this->counter), $yymatches)) { + $yysubmatches = $yymatches; + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + next($yymatches); // skip global match + $this->token += key($yymatches) + $yy_yymore_patterns[$this->token][0]; // token number + $this->value = current($yymatches); // token value + $this->line = substr_count($this->value, "\n"); + if ($tokenMap[$this->token]) { + // extract sub-patterns for passing to lex function + $yysubmatches = array_slice($yysubmatches, $this->token + 1, + $tokenMap[$this->token]); + } else { + $yysubmatches = array(); + } + } + $r = $this->{'yy_r1_' . $this->token}($yysubmatches); + } while ($r !== null && !is_bool($r)); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + $this->counter += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + if ($this->counter >= strlen($this->data)) { + return false; // end of input + } + // skip this token + continue; + } else { + // accept + $this->counter += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + return true; + } + } + } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->data[$this->counter]); + } + break; + } while (true); + + } // end function + + + const START = 1; + function yy_r1_1($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_XML; + } + function yy_r1_2($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_PHP; + } + function yy_r1_3($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_SHORTTAGSTART; + } + function yy_r1_4($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_SHORTTAGEND; + } + function yy_r1_5($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_PHPSTART; + } + function yy_r1_6($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_PHPEND; + } + function yy_r1_7($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_COMMENTEND; + } + function yy_r1_8($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_COMMENTSTART; + } + function yy_r1_9($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_OTHER; + } + function yy_r1_11($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTE; + } + function yy_r1_12($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_LITERALSTART; + } + function yy_r1_13($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_LITERALEND; + } + function yy_r1_14($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_LDELIMTAG; + } + function yy_r1_15($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_RDELIMTAG; + } + function yy_r1_16($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_OTHER; + } + function yy_r1_17($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_OTHER; + } + function yy_r1_18($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_LDELSLASH; + } + function yy_r1_19($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_LDEL; + } + function yy_r1_20($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_RDEL; + } + function yy_r1_21($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_IN; + } + function yy_r1_23($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_BOOLEAN; + } + function yy_r1_24($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_NULL; + } + function yy_r1_25($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_IDENTITY; + } + function yy_r1_26($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_NONEIDENTITY; + } + function yy_r1_27($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_EQUALS; + } + function yy_r1_29($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_NOTEQUALS; + } + function yy_r1_31($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_GREATEREQUAL; + } + function yy_r1_33($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_LESSEQUAL; + } + function yy_r1_35($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_GREATERTHAN; + } + function yy_r1_37($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_LESSTHAN; + } + function yy_r1_39($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_NOT; + } + function yy_r1_41($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_LAND; + } + function yy_r1_43($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_LOR; + } + function yy_r1_45($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISODDBY; + } + function yy_r1_46($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISNOTODDBY; + } + function yy_r1_47($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISODD; + } + function yy_r1_48($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISNOTODD; + } + function yy_r1_49($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISEVENBY; + } + function yy_r1_50($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISNOTEVENBY; + } + function yy_r1_51($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISEVEN; + } + function yy_r1_52($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISNOTEVEN; + } + function yy_r1_53($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISDIVBY; + } + function yy_r1_54($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ISNOTDIVBY; + } + function yy_r1_55($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_OPENP; + } + function yy_r1_56($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_CLOSEP; + } + function yy_r1_57($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_OPENB; + } + function yy_r1_58($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_CLOSEB; + } + function yy_r1_59($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_PTR; + } + function yy_r1_60($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_APTR; + } + function yy_r1_61($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_EQUAL; + } + function yy_r1_62($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_NUMBER; + } + function yy_r1_64($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_INCDEC; + } + function yy_r1_66($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_UNIMATH; + } + function yy_r1_68($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_MATH; + } + function yy_r1_70($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_SPACE; + } + function yy_r1_71($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_DOLLAR; + } + function yy_r1_72($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_SEMICOLON; + } + function yy_r1_73($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON; + } + function yy_r1_74($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_COLON; + } + function yy_r1_75($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_AT; + } + function yy_r1_76($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_HATCH; + } + function yy_r1_77($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_QUOTE; + } + function yy_r1_78($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_BACKTICK; + } + function yy_r1_79($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_VERT; + } + function yy_r1_80($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_DOT; + } + function yy_r1_81($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_COMMA; + } + function yy_r1_82($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ANDSYM; + } + function yy_r1_83($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_ID; + } + function yy_r1_84($yy_subpatterns) + { + + $this->token = Smarty_Internal_Templateparser::TP_OTHER; + } + +} diff --git a/libs/lexer/internal.templatelexer.plex b/libs/lexer/internal.templatelexer.plex new file mode 100644 index 00000000..480a0a3b --- /dev/null +++ b/libs/lexer/internal.templatelexer.plex @@ -0,0 +1,382 @@ + '{', + 'RDEL' => '}', + 'IDENTITY' => '===', + 'NONEIDENTITY' => '!==', + 'EQUALS' => '==', + 'NOTEQUALS' => '!=', + 'GREATEREQUAL' => '(>=,GE)', + 'LESSEQUAL' => '(<=,LE)', + 'GREATERTHAN' => '(>,GT)', + 'LESSTHAN' => '(<,LT)', + 'NOT' => '(!,NOT)', + 'LAND' => '(&&,AND)', + 'LOR' => '(||,OR)', + 'OPENP' => '(', + 'CLOSEP' => ')', + 'OPENB' => '[', + 'CLOSEB' => ']', + 'PTR' => '->', + 'APTR' => '=>', + 'EQUAL' => '=', + 'NUMBER' => 'number', + 'UNIMATH' => '+" , "-', + 'MATH' => '*" , "/" , "%', + 'INCDEC' => '++" , "--', + 'SPACE' => ' ', + 'DOLLAR' => '$', + 'SEMICOLON' => ';', + 'COLON' => ':', + 'DOUBLECOLON' => '::', + 'AT' => '@', + 'HATCH' => '#', + 'QUOTE' => '"', + 'SINGLEQUOTE' => "'", + 'BACKTICK' => '`', + 'VERT' => '|', + 'DOT' => '.', + 'COMMA' => '","', + 'ANDSYM' => '"&"', + 'ID' => 'identifier', + 'OTHER' => 'text', + 'PHP' => 'PHP code', + 'LDELSLASH' => 'closing tag', + 'COMMENTSTART' => '{*', + 'COMMENTEND' => '*}', + 'LITERALEND' => 'literal close', + 'IN' => 'in', + 'NULL' => 'null', + 'BOOLEAN' => 'boolean' + ); + + + function __construct($data) + { + // set instance object + self::instance($this); + $this->data = $data; + $this->counter = 0; + $this->line = 1; + $this->smarty = Smarty::instance(); + $this->ldel = preg_quote($this->smarty->left_delimiter); + $this->rdel = preg_quote($this->smarty->right_delimiter); + } + public static function &instance($new_instance = null) + { + static $instance = null; + if (isset($new_instance) && is_object($new_instance)) + $instance = $new_instance; + return $instance; + } + + +/*!lex2php +%input $this->data +%counter $this->counter +%token $this->token +%value $this->value +%line $this->line +php = /\<\?php.*\?\>/ +xml = /\<\?xml.*\?\>/ +shorttagstart = /\<\?=/ +shorttagend = /\?\>/ +phpstart = /SMARTYldelphpSMARTYrdel/ +phpend = /SMARTYldel\/phpSMARTYrdel/ +ldels = /SMARTYldel\s{1,}/ +rdels = /\s{1,}SMARTYrdel/ +ldelslash = /SMARTYldel\// +ldel = /SMARTYldel/ +rdel = /SMARTYrdel/ +number = /\d+(\.\d+)?/ +boolean = /true|TRUE|True|false|FALSE|False/ +null = /null|NULL|Null/ +math = /\s*\*(?!\})\s*|\s*(\/|\%)\s*/ +commentstart = /SMARTYldel\*/ +commentend = /\*SMARTYrdel/ +escapedquotes = /(\\\"|\\\')/ +incdec = /(\+\+|\-\-)\s*/ +unimath = /\s*(\+|\-)\s*/ +openP = /\(/ +closeP = /\)/ +openB = /\[/ +closeB = /]/ +dollar = /\$/ +dot = /\./ +comma = /\s*\,\s*/ +doublecolon = /\:\:/ +colon = /\:/ +at = /@/ +hatch = /#/ +semicolon = /\s*\;\s*/ +vert = /\s*\|/ +equal = /\s*=\s*/ +space = /[\s]+/ +ptr = /\s*\->/ +aptr = /\s*=>\s*/ +quote = /\"/ +singlequote = /\'/ +backtick = /`/ +andsym = /\s?\&\s?/ +id = /\w+/ +literalstart = 'SMARTYldelliteralSMARTYrdel' +literalend = 'SMARTYldel/literalSMARTYrdel' +ldelim = 'SMARTYldelldelimSMARTYrdel' +rdelim = 'SMARTYldelrdelimSMARTYrdel' +equals = /\s*==\s*|\s+(EQ|eq)\s+/ +notequals = /\s*\!=\s*|\s+(NE|ne)\s+/ +greaterthan = /\s*\>\s*|\s+(GT|gt)\s+/ +lessthan = /\s*\<\s*|\s+(LT|lt)\s+/ +greaterequal = /\s*\>=\s*|\s+(GE|ge)\s+/ +lessequal = /\s*<=\s*|\s+(LE|le)\s+/ +identity = /\s*===\s*/ +noneidentity = /\s*!==\s*/ +isoddby = /\s+is\s+odd\s+by\s+/ +isnotoddby = /\s+is\s+not\s+odd\s+by\s+/ +isodd = /\s+is\s+odd/ +isnotodd = /\s+is\s+not\s+odd/ +isevenby = /\s+is\s+even\s+by\s+/ +isnotevenby = /\s+is\s+not\s+even\s+by\s+/ +iseven = /\s+is\s+even/ +isnoteven = /\s+is\s+not\s+even/ +isdivby = /\s+is\s+div\s+by\s+/ +isnotdivby = /\s+is\s+not\s+div\s+by\s+/ +in = /\s+(IN|in)\s+/ +not = /!|(NOT|not)\s+/ +land = /\s*\&\&\s*|\s+(AND|and)\s+/ +lor = /\s*\|\|\s*|\s+(OR|or)\s+/ +other = /./ +*/ +/*!lex2php +%statename START +xml { + $this->token = Smarty_Internal_Templateparser::TP_XML; +} +php { + $this->token = Smarty_Internal_Templateparser::TP_PHP; +} +shorttagstart { + $this->token = Smarty_Internal_Templateparser::TP_SHORTTAGSTART; +} +shorttagend { + $this->token = Smarty_Internal_Templateparser::TP_SHORTTAGEND; +} +phpstart { + $this->token = Smarty_Internal_Templateparser::TP_PHPSTART; +} +phpend { + $this->token = Smarty_Internal_Templateparser::TP_PHPEND; +} +commentend { + $this->token = Smarty_Internal_Templateparser::TP_COMMENTEND; +} +commentstart { + $this->token = Smarty_Internal_Templateparser::TP_COMMENTSTART; +} +escapedquotes { + $this->token = Smarty_Internal_Templateparser::TP_OTHER; +} +singlequote { + $this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTE; +} +literalstart { + $this->token = Smarty_Internal_Templateparser::TP_LITERALSTART; +} +literalend { + $this->token = Smarty_Internal_Templateparser::TP_LITERALEND; +} +ldelim { + $this->token = Smarty_Internal_Templateparser::TP_LDELIMTAG; +} +rdelim { + $this->token = Smarty_Internal_Templateparser::TP_RDELIMTAG; +} +ldels { + $this->token = Smarty_Internal_Templateparser::TP_OTHER; +} +rdels { + $this->token = Smarty_Internal_Templateparser::TP_OTHER; +} +ldelslash { + $this->token = Smarty_Internal_Templateparser::TP_LDELSLASH; +} +ldel { + $this->token = Smarty_Internal_Templateparser::TP_LDEL; +} +rdel { + $this->token = Smarty_Internal_Templateparser::TP_RDEL; +} +in { + $this->token = Smarty_Internal_Templateparser::TP_IN; +} +boolean { + $this->token = Smarty_Internal_Templateparser::TP_BOOLEAN; +} +null { + $this->token = Smarty_Internal_Templateparser::TP_NULL; +} +identity{ + $this->token = Smarty_Internal_Templateparser::TP_IDENTITY; +} +noneidentity{ + $this->token = Smarty_Internal_Templateparser::TP_NONEIDENTITY; +} +equals{ + $this->token = Smarty_Internal_Templateparser::TP_EQUALS; +} +notequals{ + $this->token = Smarty_Internal_Templateparser::TP_NOTEQUALS; +} +greaterequal{ + $this->token = Smarty_Internal_Templateparser::TP_GREATEREQUAL; +} +lessequal{ + $this->token = Smarty_Internal_Templateparser::TP_LESSEQUAL; +} +greaterthan{ + $this->token = Smarty_Internal_Templateparser::TP_GREATERTHAN; +} +lessthan{ + $this->token = Smarty_Internal_Templateparser::TP_LESSTHAN; +} +not{ + $this->token = Smarty_Internal_Templateparser::TP_NOT; +} +land { + $this->token = Smarty_Internal_Templateparser::TP_LAND; +} +lor { + $this->token = Smarty_Internal_Templateparser::TP_LOR; +} +isoddby { + $this->token = Smarty_Internal_Templateparser::TP_ISODDBY; +} +isnotoddby { + $this->token = Smarty_Internal_Templateparser::TP_ISNOTODDBY; +} + +isodd { + $this->token = Smarty_Internal_Templateparser::TP_ISODD; +} +isnotodd { + $this->token = Smarty_Internal_Templateparser::TP_ISNOTODD; +} +isevenby { + $this->token = Smarty_Internal_Templateparser::TP_ISEVENBY; +} +isnotevenby { + $this->token = Smarty_Internal_Templateparser::TP_ISNOTEVENBY; +} +iseven{ + $this->token = Smarty_Internal_Templateparser::TP_ISEVEN; +} +isnoteven { + $this->token = Smarty_Internal_Templateparser::TP_ISNOTEVEN; +} +isdivby { + $this->token = Smarty_Internal_Templateparser::TP_ISDIVBY; +} +isnotdivby { + $this->token = Smarty_Internal_Templateparser::TP_ISNOTDIVBY; +} +openP { + $this->token = Smarty_Internal_Templateparser::TP_OPENP; +} +closeP { + $this->token = Smarty_Internal_Templateparser::TP_CLOSEP; +} +openB { + $this->token = Smarty_Internal_Templateparser::TP_OPENB; +} + +closeB { + $this->token = Smarty_Internal_Templateparser::TP_CLOSEB; +} +ptr { + $this->token = Smarty_Internal_Templateparser::TP_PTR; +} +aptr { + $this->token = Smarty_Internal_Templateparser::TP_APTR; +} +equal { + $this->token = Smarty_Internal_Templateparser::TP_EQUAL; +} +number { + $this->token = Smarty_Internal_Templateparser::TP_NUMBER; +} +incdec { + $this->token = Smarty_Internal_Templateparser::TP_INCDEC; +} +unimath { + $this->token = Smarty_Internal_Templateparser::TP_UNIMATH; +} +math { + $this->token = Smarty_Internal_Templateparser::TP_MATH; +} +space { + $this->token = Smarty_Internal_Templateparser::TP_SPACE; +} +dollar { + $this->token = Smarty_Internal_Templateparser::TP_DOLLAR; +} +semicolon { + $this->token = Smarty_Internal_Templateparser::TP_SEMICOLON; +} +doublecolon { + $this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON; +} +colon { + $this->token = Smarty_Internal_Templateparser::TP_COLON; +} +at { + $this->token = Smarty_Internal_Templateparser::TP_AT; +} +hatch { + $this->token = Smarty_Internal_Templateparser::TP_HATCH; +} +quote { + $this->token = Smarty_Internal_Templateparser::TP_QUOTE; +} +backtick { + $this->token = Smarty_Internal_Templateparser::TP_BACKTICK; +} +vert { + $this->token = Smarty_Internal_Templateparser::TP_VERT; +} +dot { + $this->token = Smarty_Internal_Templateparser::TP_DOT; +} +comma { + $this->token = Smarty_Internal_Templateparser::TP_COMMA; +} +andsym { + $this->token = Smarty_Internal_Templateparser::TP_ANDSYM; +} +id { + $this->token = Smarty_Internal_Templateparser::TP_ID; +} +other { + $this->token = Smarty_Internal_Templateparser::TP_OTHER; +} +*/ +} diff --git a/libs/lexer/internal.templateparser.php b/libs/lexer/internal.templateparser.php new file mode 100644 index 00000000..81955e8f --- /dev/null +++ b/libs/lexer/internal.templateparser.php @@ -0,0 +1,2350 @@ +string = $s->string; + $this->metadata = $s->metadata; + } else { + $this->string = (string) $s; + if ($m instanceof TP_yyToken) { + $this->metadata = $m->metadata; + } elseif (is_array($m)) { + $this->metadata = $m; + } + } + } + + function __toString() + { + return $this->_string; + } + + function offsetExists($offset) + { + return isset($this->metadata[$offset]); + } + + function offsetGet($offset) + { + return $this->metadata[$offset]; + } + + function offsetSet($offset, $value) + { + if ($offset === null) { + if (isset($value[0])) { + $x = ($value instanceof TP_yyToken) ? + $value->metadata : $value; + $this->metadata = array_merge($this->metadata, $x); + return; + } + $offset = count($this->metadata); + } + if ($value === null) { + return; + } + if ($value instanceof TP_yyToken) { + if ($value->metadata) { + $this->metadata[$offset] = $value->metadata; + } + } elseif ($value) { + $this->metadata[$offset] = $value; + } + } + + function offsetUnset($offset) + { + unset($this->metadata[$offset]); + } +} + +/** The following structure represents a single element of the + * parser's stack. Information stored includes: + * + * + The state number for the parser at this level of the stack. + * + * + The value of the token stored at this level of the stack. + * (In other words, the "major" token.) + * + * + The semantic value stored at this level of the stack. This is + * the information used by the action routines in the grammar. + * It is sometimes called the "minor" token. + */ +class TP_yyStackEntry +{ + public $stateno; /* The state-number */ + public $major; /* The major token value. This is the code + ** number for the token at this stack level */ + public $minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; + +// code external to the class is included here + +// declare_class is output here +#line 12 "internal.templateparser.y" +class Smarty_Internal_Templateparser#line 109 "internal.templateparser.php" +{ +/* First off, code is included which follows the "include_class" declaration +** in the input file. */ +#line 14 "internal.templateparser.y" + + // states whether the parse was successful or not + public $successful = true; + public $retvalue = 0; + private $lex; + private $internalError = false; + + function __construct($lex, $compiler) { + // set instance object + self::instance($this); + $this->lex = $lex; + $this->smarty = Smarty::instance(); + $this->compiler = $compiler; + $this->template = $this->compiler->template; + $this->cacher = $this->template->cacher_object; + $this->nocache = false; + $this->prefix_code = array(); + $this->prefix_number = 0; + } + public static function &instance($new_instance = null) + { + static $instance = null; + if (isset($new_instance) && is_object($new_instance)) + $instance = $new_instance; + return $instance; + } + +#line 142 "internal.templateparser.php" + +/* Next is all token values, as class constants +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ + const TP_OTHER = 1; + const TP_LDELSLASH = 2; + const TP_LDEL = 3; + const TP_RDEL = 4; + const TP_XML = 5; + const TP_PHP = 6; + const TP_SHORTTAGSTART = 7; + const TP_SHORTTAGEND = 8; + const TP_COMMENTEND = 9; + const TP_COMMENTSTART = 10; + const TP_NUMBER = 11; + const TP_MATH = 12; + const TP_UNIMATH = 13; + const TP_INCDEC = 14; + const TP_OPENP = 15; + const TP_CLOSEP = 16; + const TP_OPENB = 17; + const TP_CLOSEB = 18; + const TP_DOLLAR = 19; + const TP_DOT = 20; + const TP_COMMA = 21; + const TP_COLON = 22; + const TP_DOUBLECOLON = 23; + const TP_SEMICOLON = 24; + const TP_VERT = 25; + const TP_EQUAL = 26; + const TP_SPACE = 27; + const TP_PTR = 28; + const TP_APTR = 29; + const TP_ID = 30; + const TP_EQUALS = 31; + const TP_NOTEQUALS = 32; + const TP_GREATERTHAN = 33; + const TP_LESSTHAN = 34; + const TP_GREATEREQUAL = 35; + const TP_LESSEQUAL = 36; + const TP_IDENTITY = 37; + const TP_NONEIDENTITY = 38; + const TP_NOT = 39; + const TP_LAND = 40; + const TP_LOR = 41; + const TP_QUOTE = 42; + const TP_SINGLEQUOTE = 43; + const TP_BOOLEAN = 44; + const TP_NULL = 45; + const TP_IN = 46; + const TP_ANDSYM = 47; + const TP_BACKTICK = 48; + const TP_HATCH = 49; + const TP_AT = 50; + const TP_ISODD = 51; + const TP_ISNOTODD = 52; + const TP_ISEVEN = 53; + const TP_ISNOTEVEN = 54; + const TP_ISODDBY = 55; + const TP_ISNOTODDBY = 56; + const TP_ISEVENBY = 57; + const TP_ISNOTEVENBY = 58; + const TP_ISDIVBY = 59; + const TP_ISNOTDIVBY = 60; + const TP_LITERALSTART = 61; + const TP_LITERALEND = 62; + const TP_LDELIMTAG = 63; + const TP_RDELIMTAG = 64; + const TP_PHPSTART = 65; + const TP_PHPEND = 66; + const YY_NO_ACTION = 373; + const YY_ACCEPT_ACTION = 372; + const YY_ERROR_ACTION = 371; + +/* Next are that tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N < self::YYNSTATE Shift N. That is, +** push the lookahead +** token onto the stack +** and goto state N. +** +** self::YYNSTATE <= N < self::YYNSTATE+self::YYNRULE Reduce by rule N-YYNSTATE. +** +** N == self::YYNSTATE+self::YYNRULE A syntax error has occurred. +** +** N == self::YYNSTATE+self::YYNRULE+1 The parser accepts its +** input. (and concludes parsing) +** +** N == self::YYNSTATE+self::YYNRULE+2 No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large static array $yy_action. +** Given state S and lookahead X, the action is computed as +** +** self::$yy_action[self::$yy_shift_ofst[S] + X ] +** +** If the index value self::$yy_shift_ofst[S]+X is out of range or if the value +** self::$yy_lookahead[self::$yy_shift_ofst[S]+X] is not equal to X or if +** self::$yy_shift_ofst[S] is equal to self::YY_SHIFT_USE_DFLT, it means that +** the action is not in the table and that self::$yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the static $yy_reduce_ofst array is used in place of +** the static $yy_shift_ofst array and self::YY_REDUCE_USE_DFLT is used in place of +** self::YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** self::$yy_action A single table containing all actions. +** self::$yy_lookahead A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** self::$yy_shift_ofst For each state, the offset into self::$yy_action for +** shifting terminals. +** self::$yy_reduce_ofst For each state, the offset into self::$yy_action for +** shifting non-terminals after a reduce. +** self::$yy_default Default action for each state. +*/ + const YY_SZ_ACTTAB = 794; +static public $yy_action = array( + /* 0 */ 129, 236, 195, 141, 18, 120, 196, 168, 61, 26, + /* 10 */ 16, 52, 120, 163, 120, 167, 145, 146, 225, 224, + /* 20 */ 216, 184, 214, 212, 213, 217, 186, 157, 160, 166, + /* 30 */ 153, 3, 4, 5, 2, 11, 10, 145, 146, 60, + /* 40 */ 99, 230, 228, 174, 149, 204, 131, 203, 157, 160, + /* 50 */ 166, 153, 3, 4, 5, 2, 11, 10, 372, 42, + /* 60 */ 155, 177, 56, 88, 170, 171, 58, 101, 145, 146, + /* 70 */ 174, 163, 204, 167, 100, 199, 32, 9, 165, 157, + /* 80 */ 160, 166, 153, 3, 4, 5, 2, 11, 10, 145, + /* 90 */ 146, 151, 109, 33, 23, 8, 163, 12, 167, 53, + /* 100 */ 157, 160, 166, 153, 3, 4, 5, 2, 11, 10, + /* 110 */ 117, 154, 151, 219, 33, 140, 8, 24, 12, 6, + /* 120 */ 55, 185, 35, 49, 159, 156, 139, 190, 151, 126, + /* 130 */ 33, 114, 21, 205, 12, 19, 53, 31, 221, 189, + /* 140 */ 6, 137, 15, 35, 49, 159, 156, 117, 120, 23, + /* 150 */ 126, 53, 163, 28, 167, 125, 30, 147, 44, 35, + /* 160 */ 49, 159, 156, 70, 110, 23, 126, 183, 175, 187, + /* 170 */ 80, 151, 152, 33, 201, 21, 185, 12, 218, 53, + /* 180 */ 59, 23, 205, 222, 19, 17, 147, 151, 24, 33, + /* 190 */ 118, 21, 185, 12, 192, 53, 183, 175, 200, 76, + /* 200 */ 53, 152, 35, 49, 159, 156, 115, 218, 185, 126, + /* 210 */ 234, 79, 137, 169, 231, 29, 23, 123, 35, 49, + /* 220 */ 159, 156, 41, 223, 23, 126, 37, 173, 137, 59, + /* 230 */ 151, 218, 33, 197, 21, 104, 12, 123, 53, 25, + /* 240 */ 204, 215, 120, 185, 176, 147, 151, 24, 33, 116, + /* 250 */ 21, 185, 12, 209, 53, 183, 175, 78, 83, 14, + /* 260 */ 152, 35, 49, 159, 156, 113, 218, 86, 126, 123, + /* 270 */ 134, 234, 227, 22, 120, 93, 147, 35, 49, 159, + /* 280 */ 156, 230, 228, 29, 126, 210, 183, 175, 123, 75, + /* 290 */ 176, 152, 218, 147, 44, 123, 179, 218, 226, 64, + /* 300 */ 122, 120, 233, 183, 175, 151, 80, 33, 152, 21, + /* 310 */ 14, 12, 237, 57, 218, 82, 32, 110, 86, 222, + /* 320 */ 120, 151, 1, 130, 36, 21, 132, 12, 229, 53, + /* 330 */ 191, 90, 94, 111, 112, 47, 35, 49, 159, 156, + /* 340 */ 121, 210, 210, 126, 112, 28, 150, 218, 30, 14, + /* 350 */ 191, 123, 35, 49, 159, 156, 197, 86, 14, 126, + /* 360 */ 163, 202, 167, 148, 177, 120, 86, 20, 162, 123, + /* 370 */ 108, 225, 224, 216, 184, 214, 212, 213, 217, 147, + /* 380 */ 44, 147, 120, 226, 123, 69, 163, 89, 167, 183, + /* 390 */ 175, 232, 80, 81, 152, 14, 152, 210, 147, 44, + /* 400 */ 218, 48, 218, 86, 68, 222, 27, 46, 183, 175, + /* 410 */ 147, 80, 38, 152, 45, 187, 191, 147, 44, 218, + /* 420 */ 135, 136, 191, 74, 222, 152, 176, 183, 175, 191, + /* 430 */ 80, 218, 152, 112, 128, 51, 63, 107, 218, 147, + /* 440 */ 44, 235, 204, 222, 77, 72, 147, 87, 161, 183, + /* 450 */ 175, 127, 80, 7, 152, 218, 183, 175, 92, 80, + /* 460 */ 218, 152, 133, 147, 43, 222, 194, 218, 210, 65, + /* 470 */ 147, 181, 208, 183, 175, 182, 80, 176, 152, 97, + /* 480 */ 158, 188, 147, 44, 218, 152, 151, 180, 71, 222, + /* 490 */ 21, 218, 183, 175, 53, 80, 144, 152, 27, 172, + /* 500 */ 211, 147, 85, 218, 50, 121, 178, 53, 222, 34, + /* 510 */ 62, 183, 175, 147, 80, 187, 152, 35, 49, 159, + /* 520 */ 156, 13, 218, 220, 126, 123, 147, 44, 152, 193, + /* 530 */ 119, 206, 73, 164, 218, 54, 183, 175, 39, 80, + /* 540 */ 241, 152, 174, 147, 44, 241, 241, 218, 241, 67, + /* 550 */ 241, 241, 222, 183, 175, 241, 80, 241, 152, 241, + /* 560 */ 147, 44, 241, 241, 218, 241, 66, 147, 91, 222, + /* 570 */ 183, 175, 241, 80, 241, 152, 241, 183, 175, 241, + /* 580 */ 80, 218, 152, 241, 241, 207, 222, 241, 218, 241, + /* 590 */ 147, 91, 241, 241, 241, 241, 241, 241, 241, 241, + /* 600 */ 183, 175, 241, 80, 241, 152, 147, 91, 142, 241, + /* 610 */ 241, 218, 241, 241, 241, 241, 183, 175, 241, 80, + /* 620 */ 241, 152, 241, 241, 138, 241, 241, 218, 147, 85, + /* 630 */ 241, 241, 241, 241, 241, 147, 91, 241, 183, 175, + /* 640 */ 241, 80, 241, 152, 241, 183, 175, 241, 80, 218, + /* 650 */ 152, 147, 40, 143, 124, 241, 218, 241, 198, 241, + /* 660 */ 241, 183, 175, 241, 80, 241, 152, 241, 241, 241, + /* 670 */ 241, 241, 218, 241, 147, 98, 241, 241, 241, 241, + /* 680 */ 241, 147, 106, 241, 183, 175, 241, 80, 241, 152, + /* 690 */ 241, 183, 175, 241, 80, 218, 152, 241, 147, 95, + /* 700 */ 241, 241, 218, 241, 241, 241, 241, 241, 183, 175, + /* 710 */ 241, 80, 241, 152, 241, 147, 105, 241, 241, 218, + /* 720 */ 241, 241, 147, 84, 241, 183, 175, 241, 80, 241, + /* 730 */ 152, 241, 183, 175, 241, 80, 218, 152, 147, 96, + /* 740 */ 241, 241, 241, 218, 241, 241, 241, 241, 183, 175, + /* 750 */ 241, 80, 241, 152, 241, 147, 103, 241, 241, 218, + /* 760 */ 241, 241, 241, 241, 241, 183, 175, 241, 80, 241, + /* 770 */ 152, 241, 147, 102, 241, 241, 218, 241, 241, 241, + /* 780 */ 241, 241, 183, 175, 241, 80, 241, 152, 241, 241, + /* 790 */ 241, 241, 241, 218, + ); + static public $yy_lookahead = array( + /* 0 */ 24, 4, 1, 2, 3, 25, 5, 6, 7, 29, + /* 10 */ 21, 10, 25, 1, 25, 3, 40, 41, 31, 32, + /* 20 */ 33, 34, 35, 36, 37, 38, 30, 51, 52, 53, + /* 30 */ 54, 55, 56, 57, 58, 59, 60, 40, 41, 16, + /* 40 */ 92, 12, 13, 95, 16, 97, 50, 18, 51, 52, + /* 50 */ 53, 54, 55, 56, 57, 58, 59, 60, 68, 69, + /* 60 */ 70, 71, 61, 93, 63, 64, 65, 92, 40, 41, + /* 70 */ 95, 1, 97, 3, 21, 16, 47, 24, 66, 51, + /* 80 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 40, + /* 90 */ 41, 11, 30, 13, 3, 15, 1, 17, 3, 19, + /* 100 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + /* 110 */ 30, 4, 11, 43, 13, 19, 15, 26, 17, 39, + /* 120 */ 19, 30, 42, 43, 44, 45, 30, 4, 11, 49, + /* 130 */ 13, 30, 15, 1, 17, 3, 19, 46, 43, 18, + /* 140 */ 39, 50, 21, 42, 43, 44, 45, 30, 25, 3, + /* 150 */ 49, 19, 1, 17, 3, 82, 20, 73, 74, 42, + /* 160 */ 43, 44, 45, 79, 28, 3, 49, 83, 84, 96, + /* 170 */ 86, 11, 88, 13, 42, 15, 30, 17, 94, 19, + /* 180 */ 48, 3, 1, 99, 3, 15, 73, 11, 26, 13, + /* 190 */ 30, 15, 30, 17, 4, 19, 83, 84, 90, 86, + /* 200 */ 19, 88, 42, 43, 44, 45, 30, 94, 30, 49, + /* 210 */ 73, 72, 50, 62, 4, 22, 3, 27, 42, 43, + /* 220 */ 44, 45, 78, 42, 3, 49, 89, 14, 50, 48, + /* 230 */ 11, 94, 13, 16, 15, 92, 17, 27, 19, 26, + /* 240 */ 97, 104, 25, 30, 105, 73, 11, 26, 13, 30, + /* 250 */ 15, 30, 17, 4, 19, 83, 84, 72, 86, 15, + /* 260 */ 88, 42, 43, 44, 45, 30, 94, 23, 49, 27, + /* 270 */ 28, 73, 4, 29, 25, 75, 73, 42, 43, 44, + /* 280 */ 45, 12, 13, 22, 49, 85, 83, 84, 27, 86, + /* 290 */ 105, 88, 94, 73, 74, 27, 76, 94, 98, 79, + /* 300 */ 80, 25, 104, 83, 84, 11, 86, 13, 88, 15, + /* 310 */ 15, 17, 97, 19, 94, 81, 47, 28, 23, 99, + /* 320 */ 25, 11, 27, 28, 30, 15, 73, 17, 4, 19, + /* 330 */ 96, 75, 75, 77, 77, 81, 42, 43, 44, 45, + /* 340 */ 30, 85, 85, 49, 77, 17, 4, 94, 20, 15, + /* 350 */ 96, 27, 42, 43, 44, 45, 16, 23, 15, 49, + /* 360 */ 1, 18, 3, 70, 71, 25, 23, 100, 9, 27, + /* 370 */ 78, 31, 32, 33, 34, 35, 36, 37, 38, 73, + /* 380 */ 74, 73, 25, 98, 27, 79, 1, 75, 3, 83, + /* 390 */ 84, 83, 86, 72, 88, 15, 88, 85, 73, 74, + /* 400 */ 94, 81, 94, 23, 79, 99, 26, 81, 83, 84, + /* 410 */ 73, 86, 93, 88, 81, 96, 96, 73, 74, 94, + /* 420 */ 83, 84, 96, 79, 99, 88, 105, 83, 84, 96, + /* 430 */ 86, 94, 88, 77, 73, 19, 30, 92, 94, 73, + /* 440 */ 74, 48, 97, 99, 72, 79, 73, 74, 49, 83, + /* 450 */ 84, 30, 86, 101, 88, 94, 83, 84, 75, 86, + /* 460 */ 94, 88, 30, 73, 74, 99, 30, 94, 85, 79, + /* 470 */ 73, 8, 16, 83, 84, 4, 86, 105, 88, 30, + /* 480 */ 83, 30, 73, 74, 94, 88, 11, 4, 79, 99, + /* 490 */ 15, 94, 83, 84, 19, 86, 30, 88, 26, 4, + /* 500 */ 4, 73, 74, 94, 30, 30, 105, 19, 99, 87, + /* 510 */ 90, 83, 84, 73, 86, 96, 88, 42, 43, 44, + /* 520 */ 45, 15, 94, 83, 49, 27, 73, 74, 88, 85, + /* 530 */ 102, 103, 79, 76, 94, 19, 83, 84, 93, 86, + /* 540 */ 106, 88, 95, 73, 74, 106, 106, 94, 106, 79, + /* 550 */ 106, 106, 99, 83, 84, 106, 86, 106, 88, 106, + /* 560 */ 73, 74, 106, 106, 94, 106, 79, 73, 74, 99, + /* 570 */ 83, 84, 106, 86, 106, 88, 106, 83, 84, 106, + /* 580 */ 86, 94, 88, 106, 106, 91, 99, 106, 94, 106, + /* 590 */ 73, 74, 106, 106, 106, 106, 106, 106, 106, 106, + /* 600 */ 83, 84, 106, 86, 106, 88, 73, 74, 91, 106, + /* 610 */ 106, 94, 106, 106, 106, 106, 83, 84, 106, 86, + /* 620 */ 106, 88, 106, 106, 91, 106, 106, 94, 73, 74, + /* 630 */ 106, 106, 106, 106, 106, 73, 74, 106, 83, 84, + /* 640 */ 106, 86, 106, 88, 106, 83, 84, 106, 86, 94, + /* 650 */ 88, 73, 74, 91, 76, 106, 94, 106, 103, 106, + /* 660 */ 106, 83, 84, 106, 86, 106, 88, 106, 106, 106, + /* 670 */ 106, 106, 94, 106, 73, 74, 106, 106, 106, 106, + /* 680 */ 106, 73, 74, 106, 83, 84, 106, 86, 106, 88, + /* 690 */ 106, 83, 84, 106, 86, 94, 88, 106, 73, 74, + /* 700 */ 106, 106, 94, 106, 106, 106, 106, 106, 83, 84, + /* 710 */ 106, 86, 106, 88, 106, 73, 74, 106, 106, 94, + /* 720 */ 106, 106, 73, 74, 106, 83, 84, 106, 86, 106, + /* 730 */ 88, 106, 83, 84, 106, 86, 94, 88, 73, 74, + /* 740 */ 106, 106, 106, 94, 106, 106, 106, 106, 83, 84, + /* 750 */ 106, 86, 106, 88, 106, 73, 74, 106, 106, 94, + /* 760 */ 106, 106, 106, 106, 106, 83, 84, 106, 86, 106, + /* 770 */ 88, 106, 73, 74, 106, 106, 94, 106, 106, 106, + /* 780 */ 106, 106, 83, 84, 106, 86, 106, 88, 106, 106, + /* 790 */ 106, 106, 106, 94, +); + const YY_SHIFT_USE_DFLT = -25; + const YY_SHIFT_MAX = 144; + static public $yy_shift_ofst = array( + /* 0 */ 1, 101, 80, 80, 80, 80, 80, 80, 80, 80, + /* 10 */ 80, 80, 235, 117, 117, 235, 117, 117, 294, 117, + /* 20 */ 117, 117, 117, 117, 117, 117, 117, 117, 176, 219, + /* 30 */ 160, 310, 475, 475, 475, 132, 295, 181, 136, 136, + /* 40 */ 357, 261, 1, 340, -13, 91, 213, 162, 178, 95, + /* 50 */ 242, 146, 385, 146, 146, 146, 385, 146, 385, 488, + /* 60 */ 289, 488, 289, 498, -3, 28, -24, 49, 49, 49, + /* 70 */ 49, 49, 49, 49, 49, 29, 269, 12, 70, 151, + /* 80 */ 269, 359, 221, 269, 249, -20, 96, 217, 328, 342, + /* 90 */ 324, -11, 268, 210, 190, 123, 276, 506, 276, 289, + /* 100 */ 516, 289, 276, 276, 289, 276, 276, 289, 193, 170, + /* 110 */ 62, -25, -25, 244, 380, 343, 334, 334, 334, 121, + /* 120 */ -4, 334, 53, 432, 496, 471, 421, 399, 393, 416, + /* 130 */ 406, 436, 463, 472, 466, 495, 483, 451, 456, 170, + /* 140 */ 449, 474, 23, 59, 107, +); + const YY_REDUCE_USE_DFLT = -53; + const YY_REDUCE_MAX = 112; + static public $yy_reduce_ofst = array( + /* 0 */ -10, 220, 366, 344, 409, 325, 306, 84, 390, 487, + /* 10 */ 453, 470, 428, 517, 533, 555, 494, 562, 578, 649, + /* 20 */ 665, 373, 642, 625, 601, 699, 608, 682, 203, 172, + /* 30 */ 113, 337, 308, 397, 440, 137, 256, 198, -25, -52, + /* 40 */ 257, 200, 293, 267, 267, 319, 73, 319, 319, 185, + /* 50 */ 312, 326, 321, 320, 234, 333, 139, 254, 372, 361, + /* 60 */ 143, 253, 345, 383, 352, 352, 352, 352, 352, 352, + /* 70 */ 352, 352, 352, 352, 352, 422, 422, 401, 401, 401, + /* 80 */ 422, 401, 419, 422, 356, 356, 420, 356, 447, 444, + /* 90 */ 444, 356, 444, 444, 444, 356, 356, 445, 356, 215, + /* 100 */ 457, 215, 356, 356, 215, 356, 356, 215, 285, -30, + /* 110 */ 108, 144, 292, +); + static public $yyExpectedTokens = array( + /* 0 */ array(1, 2, 3, 5, 6, 7, 10, 61, 63, 64, 65, ), + /* 1 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 2 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 3 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 4 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 5 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 6 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 7 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 8 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 9 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 10 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 11 */ array(11, 13, 15, 17, 19, 30, 39, 42, 43, 44, 45, 49, ), + /* 12 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 13 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 14 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 15 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 16 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 17 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 18 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 19 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 20 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 21 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 22 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 23 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 24 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 25 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 26 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 27 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 28 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 29 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 30 */ array(11, 13, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 31 */ array(11, 15, 17, 19, 30, 42, 43, 44, 45, 49, ), + /* 32 */ array(11, 15, 19, 30, 42, 43, 44, 45, 49, ), + /* 33 */ array(11, 15, 19, 30, 42, 43, 44, 45, 49, ), + /* 34 */ array(11, 15, 19, 30, 42, 43, 44, 45, 49, ), + /* 35 */ array(1, 3, 19, 42, 48, ), + /* 36 */ array(15, 23, 25, 27, 28, ), + /* 37 */ array(1, 3, 19, 42, 48, ), + /* 38 */ array(17, 20, 28, ), + /* 39 */ array(17, 20, 28, ), + /* 40 */ array(25, 27, ), + /* 41 */ array(22, 27, ), + /* 42 */ array(1, 2, 3, 5, 6, 7, 10, 61, 63, 64, 65, ), + /* 43 */ array(16, 25, 31, 32, 33, 34, 35, 36, 37, 38, ), + /* 44 */ array(25, 31, 32, 33, 34, 35, 36, 37, 38, ), + /* 45 */ array(3, 26, 30, 46, 50, ), + /* 46 */ array(3, 14, 26, 30, ), + /* 47 */ array(3, 26, 30, 50, ), + /* 48 */ array(3, 30, 50, ), + /* 49 */ array(1, 3, 43, ), + /* 50 */ array(27, 28, ), + /* 51 */ array(3, 30, ), + /* 52 */ array(1, 3, ), + /* 53 */ array(3, 30, ), + /* 54 */ array(3, 30, ), + /* 55 */ array(3, 30, ), + /* 56 */ array(1, 3, ), + /* 57 */ array(3, 30, ), + /* 58 */ array(1, 3, ), + /* 59 */ array(19, ), + /* 60 */ array(28, ), + /* 61 */ array(19, ), + /* 62 */ array(28, ), + /* 63 */ array(27, ), + /* 64 */ array(4, 40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 65 */ array(16, 40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 66 */ array(24, 40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 67 */ array(40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 68 */ array(40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 69 */ array(40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 70 */ array(40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 71 */ array(40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 72 */ array(40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 73 */ array(40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 74 */ array(40, 41, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ), + /* 75 */ array(12, 13, 18, 47, ), + /* 76 */ array(12, 13, 47, ), + /* 77 */ array(1, 3, 66, ), + /* 78 */ array(1, 3, 43, ), + /* 79 */ array(1, 3, 62, ), + /* 80 */ array(12, 13, 47, ), + /* 81 */ array(1, 3, 9, ), + /* 82 */ array(3, 26, 30, ), + /* 83 */ array(12, 13, 47, ), + /* 84 */ array(4, 25, ), + /* 85 */ array(25, 29, ), + /* 86 */ array(19, 30, ), + /* 87 */ array(16, 25, ), + /* 88 */ array(17, 20, ), + /* 89 */ array(4, 27, ), + /* 90 */ array(4, 27, ), + /* 91 */ array(21, 25, ), + /* 92 */ array(4, 27, ), + /* 93 */ array(4, 27, ), + /* 94 */ array(4, 27, ), + /* 95 */ array(4, 25, ), + /* 96 */ array(25, ), + /* 97 */ array(15, ), + /* 98 */ array(25, ), + /* 99 */ array(28, ), + /* 100 */ array(19, ), + /* 101 */ array(28, ), + /* 102 */ array(25, ), + /* 103 */ array(25, ), + /* 104 */ array(28, ), + /* 105 */ array(25, ), + /* 106 */ array(25, ), + /* 107 */ array(28, ), + /* 108 */ array(22, ), + /* 109 */ array(15, ), + /* 110 */ array(30, ), + /* 111 */ array(), + /* 112 */ array(), + /* 113 */ array(15, 23, 29, ), + /* 114 */ array(15, 23, 26, ), + /* 115 */ array(15, 18, 23, ), + /* 116 */ array(15, 23, ), + /* 117 */ array(15, 23, ), + /* 118 */ array(15, 23, ), + /* 119 */ array(18, 21, ), + /* 120 */ array(30, 50, ), + /* 121 */ array(15, 23, ), + /* 122 */ array(21, 24, ), + /* 123 */ array(30, ), + /* 124 */ array(4, ), + /* 125 */ array(4, ), + /* 126 */ array(30, ), + /* 127 */ array(49, ), + /* 128 */ array(48, ), + /* 129 */ array(19, ), + /* 130 */ array(30, ), + /* 131 */ array(30, ), + /* 132 */ array(8, ), + /* 133 */ array(26, ), + /* 134 */ array(30, ), + /* 135 */ array(4, ), + /* 136 */ array(4, ), + /* 137 */ array(30, ), + /* 138 */ array(16, ), + /* 139 */ array(15, ), + /* 140 */ array(30, ), + /* 141 */ array(30, ), + /* 142 */ array(16, ), + /* 143 */ array(16, ), + /* 144 */ array(4, ), + /* 145 */ array(), + /* 146 */ array(), + /* 147 */ array(), + /* 148 */ array(), + /* 149 */ array(), + /* 150 */ array(), + /* 151 */ array(), + /* 152 */ array(), + /* 153 */ array(), + /* 154 */ array(), + /* 155 */ array(), + /* 156 */ array(), + /* 157 */ array(), + /* 158 */ array(), + /* 159 */ array(), + /* 160 */ array(), + /* 161 */ array(), + /* 162 */ array(), + /* 163 */ array(), + /* 164 */ array(), + /* 165 */ array(), + /* 166 */ array(), + /* 167 */ array(), + /* 168 */ array(), + /* 169 */ array(), + /* 170 */ array(), + /* 171 */ array(), + /* 172 */ array(), + /* 173 */ array(), + /* 174 */ array(), + /* 175 */ array(), + /* 176 */ array(), + /* 177 */ array(), + /* 178 */ array(), + /* 179 */ array(), + /* 180 */ array(), + /* 181 */ array(), + /* 182 */ array(), + /* 183 */ array(), + /* 184 */ array(), + /* 185 */ array(), + /* 186 */ array(), + /* 187 */ array(), + /* 188 */ array(), + /* 189 */ array(), + /* 190 */ array(), + /* 191 */ array(), + /* 192 */ array(), + /* 193 */ array(), + /* 194 */ array(), + /* 195 */ array(), + /* 196 */ array(), + /* 197 */ array(), + /* 198 */ array(), + /* 199 */ array(), + /* 200 */ array(), + /* 201 */ array(), + /* 202 */ array(), + /* 203 */ array(), + /* 204 */ array(), + /* 205 */ array(), + /* 206 */ array(), + /* 207 */ array(), + /* 208 */ array(), + /* 209 */ array(), + /* 210 */ array(), + /* 211 */ array(), + /* 212 */ array(), + /* 213 */ array(), + /* 214 */ array(), + /* 215 */ array(), + /* 216 */ array(), + /* 217 */ array(), + /* 218 */ array(), + /* 219 */ array(), + /* 220 */ array(), + /* 221 */ array(), + /* 222 */ array(), + /* 223 */ array(), + /* 224 */ array(), + /* 225 */ array(), + /* 226 */ array(), + /* 227 */ array(), + /* 228 */ array(), + /* 229 */ array(), + /* 230 */ array(), + /* 231 */ array(), + /* 232 */ array(), + /* 233 */ array(), + /* 234 */ array(), + /* 235 */ array(), + /* 236 */ array(), + /* 237 */ array(), +); + static public $yy_default = array( + /* 0 */ 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, + /* 10 */ 371, 371, 357, 321, 321, 371, 321, 321, 371, 371, + /* 20 */ 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, + /* 30 */ 371, 371, 371, 371, 371, 371, 266, 371, 299, 297, + /* 40 */ 266, 266, 238, 331, 331, 303, 371, 303, 303, 371, + /* 50 */ 266, 371, 371, 371, 371, 371, 371, 371, 371, 371, + /* 60 */ 293, 371, 292, 266, 371, 371, 371, 334, 338, 329, + /* 70 */ 333, 343, 339, 335, 342, 371, 305, 371, 371, 371, + /* 80 */ 272, 371, 371, 327, 371, 358, 371, 371, 315, 371, + /* 90 */ 371, 320, 371, 371, 371, 371, 332, 303, 270, 298, + /* 100 */ 371, 312, 260, 267, 295, 360, 359, 294, 273, 303, + /* 110 */ 371, 325, 325, 271, 271, 371, 326, 271, 304, 371, + /* 120 */ 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, + /* 130 */ 371, 371, 371, 371, 371, 371, 371, 371, 371, 296, + /* 140 */ 371, 371, 371, 371, 371, 352, 353, 281, 240, 330, + /* 150 */ 256, 283, 286, 337, 257, 239, 285, 340, 276, 284, + /* 160 */ 341, 282, 242, 369, 269, 247, 336, 370, 246, 243, + /* 170 */ 244, 245, 262, 261, 302, 274, 368, 241, 367, 268, + /* 180 */ 263, 248, 259, 275, 347, 310, 323, 309, 300, 354, + /* 190 */ 311, 308, 251, 264, 322, 250, 249, 287, 356, 318, + /* 200 */ 316, 291, 306, 307, 313, 366, 355, 319, 317, 365, + /* 210 */ 265, 252, 349, 350, 348, 362, 346, 351, 301, 288, + /* 220 */ 277, 289, 328, 290, 345, 344, 324, 254, 279, 253, + /* 230 */ 280, 255, 278, 361, 363, 364, 258, 314, +); +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** self::YYNOCODE is a number which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** self::YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** self::YYSTACKDEPTH is the maximum depth of the parser's stack. +** self::YYNSTATE the combined number of states. +** self::YYNRULE the number of rules in the grammar +** self::YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ + const YYNOCODE = 107; + const YYSTACKDEPTH = 100; + const YYNSTATE = 238; + const YYNRULE = 133; + const YYERRORSYMBOL = 67; + const YYERRSYMDT = 'yy0'; + const YYFALLBACK = 1; + /** The next table maps tokens into fallback tokens. If a construct + * like the following: + * + * %fallback ID X Y Z. + * + * appears in the grammer, then ID becomes a fallback token for X, Y, + * and Z. Whenever one of the tokens X, Y, or Z is input to the parser + * but it does not parse, the type of the token is changed to ID and + * the parse is retried before an error is thrown. + */ + static public $yyFallback = array( + 0, /* $ => nothing */ + 0, /* OTHER => nothing */ + 1, /* LDELSLASH => OTHER */ + 1, /* LDEL => OTHER */ + 1, /* RDEL => OTHER */ + 1, /* XML => OTHER */ + 1, /* PHP => OTHER */ + 1, /* SHORTTAGSTART => OTHER */ + 1, /* SHORTTAGEND => OTHER */ + 1, /* COMMENTEND => OTHER */ + 1, /* COMMENTSTART => OTHER */ + 1, /* NUMBER => OTHER */ + 1, /* MATH => OTHER */ + 1, /* UNIMATH => OTHER */ + 1, /* INCDEC => OTHER */ + 1, /* OPENP => OTHER */ + 1, /* CLOSEP => OTHER */ + 1, /* OPENB => OTHER */ + 1, /* CLOSEB => OTHER */ + 1, /* DOLLAR => OTHER */ + 1, /* DOT => OTHER */ + 1, /* COMMA => OTHER */ + 1, /* COLON => OTHER */ + 1, /* DOUBLECOLON => OTHER */ + 1, /* SEMICOLON => OTHER */ + 1, /* VERT => OTHER */ + 1, /* EQUAL => OTHER */ + 1, /* SPACE => OTHER */ + 1, /* PTR => OTHER */ + 1, /* APTR => OTHER */ + 1, /* ID => OTHER */ + 1, /* EQUALS => OTHER */ + 1, /* NOTEQUALS => OTHER */ + 1, /* GREATERTHAN => OTHER */ + 1, /* LESSTHAN => OTHER */ + 1, /* GREATEREQUAL => OTHER */ + 1, /* LESSEQUAL => OTHER */ + 1, /* IDENTITY => OTHER */ + 1, /* NONEIDENTITY => OTHER */ + 1, /* NOT => OTHER */ + 1, /* LAND => OTHER */ + 1, /* LOR => OTHER */ + 1, /* QUOTE => OTHER */ + 1, /* SINGLEQUOTE => OTHER */ + 1, /* BOOLEAN => OTHER */ + 1, /* NULL => OTHER */ + 1, /* IN => OTHER */ + 1, /* ANDSYM => OTHER */ + 1, /* BACKTICK => OTHER */ + 1, /* HATCH => OTHER */ + 1, /* AT => OTHER */ + 1, /* ISODD => OTHER */ + 1, /* ISNOTODD => OTHER */ + 1, /* ISEVEN => OTHER */ + 1, /* ISNOTEVEN => OTHER */ + 1, /* ISODDBY => OTHER */ + 1, /* ISNOTODDBY => OTHER */ + 1, /* ISEVENBY => OTHER */ + 1, /* ISNOTEVENBY => OTHER */ + 1, /* ISDIVBY => OTHER */ + 1, /* ISNOTDIVBY => OTHER */ + 0, /* LITERALSTART => nothing */ + 0, /* LITERALEND => nothing */ + 0, /* LDELIMTAG => nothing */ + 0, /* RDELIMTAG => nothing */ + 0, /* PHPSTART => nothing */ + 0, /* PHPEND => nothing */ + ); + /** + * Turn parser tracing on by giving a stream to which to write the trace + * and a prompt to preface each trace message. Tracing is turned off + * by making either argument NULL + * + * Inputs: + * + * - A stream resource to which trace output should be written. + * If NULL, then tracing is turned off. + * - A prefix string written at the beginning of every + * line of trace output. If NULL, then tracing is + * turned off. + * + * Outputs: + * + * - None. + * @param resource + * @param string + */ + static function Trace($TraceFILE, $zTracePrompt) + { + if (!$TraceFILE) { + $zTracePrompt = 0; + } elseif (!$zTracePrompt) { + $TraceFILE = 0; + } + self::$yyTraceFILE = $TraceFILE; + self::$yyTracePrompt = $zTracePrompt; + } + + /** + * Output debug information to output (php://output stream) + */ + static function PrintTrace() + { + self::$yyTraceFILE = fopen('php://output', 'w'); + self::$yyTracePrompt = '
'; + } + + /** + * @var resource|0 + */ + static public $yyTraceFILE; + /** + * String to prepend to debug output + * @var string|0 + */ + static public $yyTracePrompt; + /** + * @var int + */ + public $yyidx; /* Index of top element in stack */ + /** + * @var int + */ + public $yyerrcnt; /* Shifts left before out of the error */ + /** + * @var array + */ + public $yystack = array(); /* The parser's stack */ + + /** + * For tracing shifts, the names of all terminals and nonterminals + * are required. The following table supplies these names + * @var array + */ + public $yyTokenName = array( + '$', 'OTHER', 'LDELSLASH', 'LDEL', + 'RDEL', 'XML', 'PHP', 'SHORTTAGSTART', + 'SHORTTAGEND', 'COMMENTEND', 'COMMENTSTART', 'NUMBER', + 'MATH', 'UNIMATH', 'INCDEC', 'OPENP', + 'CLOSEP', 'OPENB', 'CLOSEB', 'DOLLAR', + 'DOT', 'COMMA', 'COLON', 'DOUBLECOLON', + 'SEMICOLON', 'VERT', 'EQUAL', 'SPACE', + 'PTR', 'APTR', 'ID', 'EQUALS', + 'NOTEQUALS', 'GREATERTHAN', 'LESSTHAN', 'GREATEREQUAL', + 'LESSEQUAL', 'IDENTITY', 'NONEIDENTITY', 'NOT', + 'LAND', 'LOR', 'QUOTE', 'SINGLEQUOTE', + 'BOOLEAN', 'NULL', 'IN', 'ANDSYM', + 'BACKTICK', 'HATCH', 'AT', 'ISODD', + 'ISNOTODD', 'ISEVEN', 'ISNOTEVEN', 'ISODDBY', + 'ISNOTODDBY', 'ISEVENBY', 'ISNOTEVENBY', 'ISDIVBY', + 'ISNOTDIVBY', 'LITERALSTART', 'LITERALEND', 'LDELIMTAG', + 'RDELIMTAG', 'PHPSTART', 'PHPEND', 'error', + 'start', 'template', 'template_element', 'smartytag', + 'text', 'variable', 'expr', 'attributes', + 'statement', 'modifier', 'modparameters', 'ifexprs', + 'statements', 'varvar', 'foraction', 'value', + 'array', 'attribute', 'exprs', 'math', + 'function', 'doublequoted', 'method', 'params', + 'objectchain', 'arrayindex', 'object', 'indexdef', + 'varvarele', 'objectelement', 'modparameter', 'ifexpr', + 'ifcond', 'lop', 'arrayelements', 'arrayelement', + 'doublequotedcontent', 'textelement', + ); + + /** + * For tracing reduce actions, the names of all rules are required. + * @var array + */ + static public $yyRuleName = array( + /* 0 */ "start ::= template", + /* 1 */ "template ::= template_element", + /* 2 */ "template ::= template template_element", + /* 3 */ "template_element ::= smartytag", + /* 4 */ "template_element ::= COMMENTSTART text COMMENTEND", + /* 5 */ "template_element ::= LITERALSTART text LITERALEND", + /* 6 */ "template_element ::= LDELIMTAG", + /* 7 */ "template_element ::= RDELIMTAG", + /* 8 */ "template_element ::= PHP", + /* 9 */ "template_element ::= PHPSTART text PHPEND", + /* 10 */ "template_element ::= SHORTTAGSTART variable SHORTTAGEND", + /* 11 */ "template_element ::= XML", + /* 12 */ "template_element ::= OTHER", + /* 13 */ "smartytag ::= LDEL expr attributes RDEL", + /* 14 */ "smartytag ::= LDEL statement RDEL", + /* 15 */ "smartytag ::= LDEL ID attributes RDEL", + /* 16 */ "smartytag ::= LDEL ID PTR ID attributes RDEL", + /* 17 */ "smartytag ::= LDEL ID modifier modparameters attributes RDEL", + /* 18 */ "smartytag ::= LDELSLASH ID attributes RDEL", + /* 19 */ "smartytag ::= LDELSLASH ID PTR ID RDEL", + /* 20 */ "smartytag ::= LDEL ID SPACE ifexprs RDEL", + /* 21 */ "smartytag ::= LDEL ID SPACE statements SEMICOLON ifexprs SEMICOLON DOLLAR varvar foraction RDEL", + /* 22 */ "foraction ::= EQUAL expr", + /* 23 */ "foraction ::= INCDEC", + /* 24 */ "smartytag ::= LDEL ID SPACE DOLLAR varvar IN value RDEL", + /* 25 */ "smartytag ::= LDEL ID SPACE DOLLAR varvar IN array RDEL", + /* 26 */ "attributes ::= attributes attribute", + /* 27 */ "attributes ::= attribute", + /* 28 */ "attributes ::=", + /* 29 */ "attribute ::= SPACE ID EQUAL expr", + /* 30 */ "statements ::= statement", + /* 31 */ "statements ::= statements COMMA statement", + /* 32 */ "statement ::= DOLLAR varvar EQUAL expr", + /* 33 */ "expr ::= ID", + /* 34 */ "expr ::= exprs", + /* 35 */ "expr ::= expr modifier modparameters", + /* 36 */ "exprs ::= array", + /* 37 */ "exprs ::= value", + /* 38 */ "exprs ::= UNIMATH value", + /* 39 */ "exprs ::= exprs math value", + /* 40 */ "exprs ::= exprs ANDSYM value", + /* 41 */ "math ::= UNIMATH", + /* 42 */ "math ::= MATH", + /* 43 */ "value ::= variable", + /* 44 */ "value ::= HATCH ID HATCH", + /* 45 */ "value ::= NUMBER", + /* 46 */ "value ::= BOOLEAN", + /* 47 */ "value ::= NULL", + /* 48 */ "value ::= function", + /* 49 */ "value ::= OPENP expr CLOSEP", + /* 50 */ "value ::= SINGLEQUOTE text SINGLEQUOTE", + /* 51 */ "value ::= SINGLEQUOTE SINGLEQUOTE", + /* 52 */ "value ::= QUOTE doublequoted QUOTE", + /* 53 */ "value ::= QUOTE QUOTE", + /* 54 */ "value ::= ID DOUBLECOLON method", + /* 55 */ "value ::= ID DOUBLECOLON DOLLAR ID OPENP params CLOSEP", + /* 56 */ "value ::= ID DOUBLECOLON method objectchain", + /* 57 */ "value ::= ID DOUBLECOLON DOLLAR ID OPENP params CLOSEP objectchain", + /* 58 */ "value ::= ID DOUBLECOLON ID", + /* 59 */ "value ::= ID DOUBLECOLON DOLLAR ID arrayindex", + /* 60 */ "value ::= ID DOUBLECOLON DOLLAR ID arrayindex objectchain", + /* 61 */ "variable ::= DOLLAR varvar arrayindex", + /* 62 */ "variable ::= DOLLAR varvar AT ID", + /* 63 */ "variable ::= object", + /* 64 */ "arrayindex ::= arrayindex indexdef", + /* 65 */ "arrayindex ::=", + /* 66 */ "indexdef ::= DOT ID", + /* 67 */ "indexdef ::= DOT exprs", + /* 68 */ "indexdef ::= OPENB ID CLOSEB", + /* 69 */ "indexdef ::= OPENB exprs CLOSEB", + /* 70 */ "varvar ::= varvarele", + /* 71 */ "varvar ::= varvar varvarele", + /* 72 */ "varvarele ::= ID", + /* 73 */ "varvarele ::= LDEL expr RDEL", + /* 74 */ "object ::= DOLLAR varvar arrayindex objectchain", + /* 75 */ "objectchain ::= objectelement", + /* 76 */ "objectchain ::= objectchain objectelement", + /* 77 */ "objectelement ::= PTR ID arrayindex", + /* 78 */ "objectelement ::= PTR method", + /* 79 */ "function ::= ID OPENP params CLOSEP", + /* 80 */ "method ::= ID OPENP params CLOSEP", + /* 81 */ "params ::= expr COMMA params", + /* 82 */ "params ::= expr", + /* 83 */ "params ::=", + /* 84 */ "modifier ::= VERT AT ID", + /* 85 */ "modifier ::= VERT ID", + /* 86 */ "modparameters ::= modparameters modparameter", + /* 87 */ "modparameters ::=", + /* 88 */ "modparameter ::= COLON ID", + /* 89 */ "modparameter ::= COLON exprs", + /* 90 */ "ifexprs ::= ifexpr", + /* 91 */ "ifexprs ::= NOT ifexprs", + /* 92 */ "ifexprs ::= OPENP ifexprs CLOSEP", + /* 93 */ "ifexpr ::= expr", + /* 94 */ "ifexpr ::= expr ifcond expr", + /* 95 */ "ifexpr ::= ifexprs lop ifexprs", + /* 96 */ "ifexpr ::= ifexprs ISDIVBY ifexprs", + /* 97 */ "ifexpr ::= ifexprs ISNOTDIVBY ifexprs", + /* 98 */ "ifexpr ::= ifexprs ISEVEN", + /* 99 */ "ifexpr ::= ifexprs ISNOTEVEN", + /* 100 */ "ifexpr ::= ifexprs ISEVENBY ifexprs", + /* 101 */ "ifexpr ::= ifexprs ISNOTEVENBY ifexprs", + /* 102 */ "ifexpr ::= ifexprs ISODD", + /* 103 */ "ifexpr ::= ifexprs ISNOTODD", + /* 104 */ "ifexpr ::= ifexprs ISODDBY ifexprs", + /* 105 */ "ifexpr ::= ifexprs ISNOTODDBY ifexprs", + /* 106 */ "ifcond ::= EQUALS", + /* 107 */ "ifcond ::= NOTEQUALS", + /* 108 */ "ifcond ::= GREATERTHAN", + /* 109 */ "ifcond ::= LESSTHAN", + /* 110 */ "ifcond ::= GREATEREQUAL", + /* 111 */ "ifcond ::= LESSEQUAL", + /* 112 */ "ifcond ::= IDENTITY", + /* 113 */ "ifcond ::= NONEIDENTITY", + /* 114 */ "lop ::= LAND", + /* 115 */ "lop ::= LOR", + /* 116 */ "array ::= OPENB arrayelements CLOSEB", + /* 117 */ "arrayelements ::= arrayelement", + /* 118 */ "arrayelements ::= arrayelements COMMA arrayelement", + /* 119 */ "arrayelements ::=", + /* 120 */ "arrayelement ::= expr", + /* 121 */ "arrayelement ::= expr APTR expr", + /* 122 */ "arrayelement ::= ID APTR expr", + /* 123 */ "doublequoted ::= doublequoted doublequotedcontent", + /* 124 */ "doublequoted ::= doublequotedcontent", + /* 125 */ "doublequotedcontent ::= variable", + /* 126 */ "doublequotedcontent ::= BACKTICK variable BACKTICK", + /* 127 */ "doublequotedcontent ::= LDEL expr RDEL", + /* 128 */ "doublequotedcontent ::= OTHER", + /* 129 */ "text ::= text textelement", + /* 130 */ "text ::= textelement", + /* 131 */ "textelement ::= OTHER", + /* 132 */ "textelement ::= LDEL", + ); + + /** + * This function returns the symbolic name associated with a token + * value. + * @param int + * @return string + */ + function tokenName($tokenType) + { + if ($tokenType === 0) { + return 'End of Input'; + } + if ($tokenType > 0 && $tokenType < count($this->yyTokenName)) { + return $this->yyTokenName[$tokenType]; + } else { + return "Unknown"; + } + } + + /** + * The following function deletes the value associated with a + * symbol. The symbol can be either a terminal or nonterminal. + * @param int the symbol code + * @param mixed the symbol's value + */ + static function yy_destructor($yymajor, $yypminor) + { + switch ($yymajor) { + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ + default: break; /* If no destructor action specified: do nothing */ + } + } + + /** + * Pop the parser's stack once. + * + * If there is a destructor routine associated with the token which + * is popped from the stack, then call it. + * + * Return the major token number for the symbol popped. + * @param TP_yyParser + * @return int + */ + function yy_pop_parser_stack() + { + if (!count($this->yystack)) { + return; + } + $yytos = array_pop($this->yystack); + if (self::$yyTraceFILE && $this->yyidx >= 0) { + fwrite(self::$yyTraceFILE, + self::$yyTracePrompt . 'Popping ' . $this->yyTokenName[$yytos->major] . + "\n"); + } + $yymajor = $yytos->major; + self::yy_destructor($yymajor, $yytos->minor); + $this->yyidx--; + return $yymajor; + } + + /** + * Deallocate and destroy a parser. Destructors are all called for + * all stack elements before shutting the parser down. + */ + function __destruct() + { + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + if (is_resource(self::$yyTraceFILE)) { + fclose(self::$yyTraceFILE); + } + } + + /** + * Based on the current state and parser stack, get a list of all + * possible lookahead tokens + * @param int + * @return array + */ + function yy_get_expected_tokens($token) + { + $state = $this->yystack[$this->yyidx]->stateno; + $expected = self::$yyExpectedTokens[$state]; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return $expected; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return array_unique($expected); + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate])) { + $expected += self::$yyExpectedTokens[$nextstate]; + if (in_array($token, + self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return array_unique($expected); + } + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new TP_yyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return array_unique($expected); + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return $expected; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + return array_unique($expected); + } + + /** + * Based on the parser state and current parser stack, determine whether + * the lookahead token is possible. + * + * The parser will convert the token value to an error token if not. This + * catches some unusual edge cases where the parser would fail. + * @param int + * @return bool + */ + function yy_is_expected_token($token) + { + if ($token === 0) { + return true; // 0 is not part of this + } + $state = $this->yystack[$this->yyidx]->stateno; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return true; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return true; + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate]) && + in_array($token, self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new TP_yyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + if (!$token) { + // end of input: this is valid + return true; + } + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return false; + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return true; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + + /** + * Find the appropriate action for a parser given the terminal + * look-ahead token iLookAhead. + * + * If the look-ahead token is YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return YY_NO_ACTION. + * @param int The look-ahead token + */ + function yy_find_shift_action($iLookAhead) + { + $stateno = $this->yystack[$this->yyidx]->stateno; + + /* if ($this->yyidx < 0) return self::YY_NO_ACTION; */ + if (!isset(self::$yy_shift_ofst[$stateno])) { + // no shift actions + return self::$yy_default[$stateno]; + } + $i = self::$yy_shift_ofst[$stateno]; + if ($i === self::YY_SHIFT_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback) + && ($iFallback = self::$yyFallback[$iLookAhead]) != 0) { + if (self::$yyTraceFILE) { + fwrite(self::$yyTraceFILE, self::$yyTracePrompt . "FALLBACK " . + $this->yyTokenName[$iLookAhead] . " => " . + $this->yyTokenName[$iFallback] . "\n"); + } + return $this->yy_find_shift_action($iFallback); + } + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Find the appropriate action for a parser given the non-terminal + * look-ahead token $iLookAhead. + * + * If the look-ahead token is self::YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return self::YY_NO_ACTION. + * @param int Current state number + * @param int The look-ahead token + */ + function yy_find_reduce_action($stateno, $iLookAhead) + { + /* $stateno = $this->yystack[$this->yyidx]->stateno; */ + + if (!isset(self::$yy_reduce_ofst[$stateno])) { + return self::$yy_default[$stateno]; + } + $i = self::$yy_reduce_ofst[$stateno]; + if ($i == self::YY_REDUCE_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Perform a shift action. + * @param int The new state to shift in + * @param int The major token to shift in + * @param mixed the minor token to shift in + */ + function yy_shift($yyNewState, $yyMajor, $yypMinor) + { + $this->yyidx++; + if ($this->yyidx >= self::YYSTACKDEPTH) { + $this->yyidx--; + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sStack Overflow!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will execute if the parser + ** stack ever overflows */ + return; + } + $yytos = new TP_yyStackEntry; + $yytos->stateno = $yyNewState; + $yytos->major = $yyMajor; + $yytos->minor = $yypMinor; + array_push($this->yystack, $yytos); + if (self::$yyTraceFILE && $this->yyidx > 0) { + fprintf(self::$yyTraceFILE, "%sShift %d\n", self::$yyTracePrompt, + $yyNewState); + fprintf(self::$yyTraceFILE, "%sStack:", self::$yyTracePrompt); + for($i = 1; $i <= $this->yyidx; $i++) { + fprintf(self::$yyTraceFILE, " %s", + $this->yyTokenName[$this->yystack[$i]->major]); + } + fwrite(self::$yyTraceFILE,"\n"); + } + } + + /** + * The following table contains information about every rule that + * is used during the reduce. + * + *
+     * array(
+     *  array(
+     *   int $lhs;         Symbol on the left-hand side of the rule
+     *   int $nrhs;     Number of right-hand side symbols in the rule
+     *  ),...
+     * );
+     * 
+ */ + static public $yyRuleInfo = array( + array( 'lhs' => 68, 'rhs' => 1 ), + array( 'lhs' => 69, 'rhs' => 1 ), + array( 'lhs' => 69, 'rhs' => 2 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 3 ), + array( 'lhs' => 70, 'rhs' => 3 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 3 ), + array( 'lhs' => 70, 'rhs' => 3 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 71, 'rhs' => 4 ), + array( 'lhs' => 71, 'rhs' => 3 ), + array( 'lhs' => 71, 'rhs' => 4 ), + array( 'lhs' => 71, 'rhs' => 6 ), + array( 'lhs' => 71, 'rhs' => 6 ), + array( 'lhs' => 71, 'rhs' => 4 ), + array( 'lhs' => 71, 'rhs' => 5 ), + array( 'lhs' => 71, 'rhs' => 5 ), + array( 'lhs' => 71, 'rhs' => 11 ), + array( 'lhs' => 82, 'rhs' => 2 ), + array( 'lhs' => 82, 'rhs' => 1 ), + array( 'lhs' => 71, 'rhs' => 8 ), + array( 'lhs' => 71, 'rhs' => 8 ), + array( 'lhs' => 75, 'rhs' => 2 ), + array( 'lhs' => 75, 'rhs' => 1 ), + array( 'lhs' => 75, 'rhs' => 0 ), + array( 'lhs' => 85, 'rhs' => 4 ), + array( 'lhs' => 80, 'rhs' => 1 ), + array( 'lhs' => 80, 'rhs' => 3 ), + array( 'lhs' => 76, 'rhs' => 4 ), + array( 'lhs' => 74, 'rhs' => 1 ), + array( 'lhs' => 74, 'rhs' => 1 ), + array( 'lhs' => 74, 'rhs' => 3 ), + array( 'lhs' => 86, 'rhs' => 1 ), + array( 'lhs' => 86, 'rhs' => 1 ), + array( 'lhs' => 86, 'rhs' => 2 ), + array( 'lhs' => 86, 'rhs' => 3 ), + array( 'lhs' => 86, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 1 ), + array( 'lhs' => 87, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 3 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 3 ), + array( 'lhs' => 83, 'rhs' => 3 ), + array( 'lhs' => 83, 'rhs' => 2 ), + array( 'lhs' => 83, 'rhs' => 3 ), + array( 'lhs' => 83, 'rhs' => 2 ), + array( 'lhs' => 83, 'rhs' => 3 ), + array( 'lhs' => 83, 'rhs' => 7 ), + array( 'lhs' => 83, 'rhs' => 4 ), + array( 'lhs' => 83, 'rhs' => 8 ), + array( 'lhs' => 83, 'rhs' => 3 ), + array( 'lhs' => 83, 'rhs' => 5 ), + array( 'lhs' => 83, 'rhs' => 6 ), + array( 'lhs' => 73, 'rhs' => 3 ), + array( 'lhs' => 73, 'rhs' => 4 ), + array( 'lhs' => 73, 'rhs' => 1 ), + array( 'lhs' => 93, 'rhs' => 2 ), + array( 'lhs' => 93, 'rhs' => 0 ), + array( 'lhs' => 95, 'rhs' => 2 ), + array( 'lhs' => 95, 'rhs' => 2 ), + array( 'lhs' => 95, 'rhs' => 3 ), + array( 'lhs' => 95, 'rhs' => 3 ), + array( 'lhs' => 81, 'rhs' => 1 ), + array( 'lhs' => 81, 'rhs' => 2 ), + array( 'lhs' => 96, 'rhs' => 1 ), + array( 'lhs' => 96, 'rhs' => 3 ), + array( 'lhs' => 94, 'rhs' => 4 ), + array( 'lhs' => 92, 'rhs' => 1 ), + array( 'lhs' => 92, 'rhs' => 2 ), + array( 'lhs' => 97, 'rhs' => 3 ), + array( 'lhs' => 97, 'rhs' => 2 ), + array( 'lhs' => 88, 'rhs' => 4 ), + array( 'lhs' => 90, 'rhs' => 4 ), + array( 'lhs' => 91, 'rhs' => 3 ), + array( 'lhs' => 91, 'rhs' => 1 ), + array( 'lhs' => 91, 'rhs' => 0 ), + array( 'lhs' => 77, 'rhs' => 3 ), + array( 'lhs' => 77, 'rhs' => 2 ), + array( 'lhs' => 78, 'rhs' => 2 ), + array( 'lhs' => 78, 'rhs' => 0 ), + array( 'lhs' => 98, 'rhs' => 2 ), + array( 'lhs' => 98, 'rhs' => 2 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 2 ), + array( 'lhs' => 79, 'rhs' => 3 ), + array( 'lhs' => 99, 'rhs' => 1 ), + array( 'lhs' => 99, 'rhs' => 3 ), + array( 'lhs' => 99, 'rhs' => 3 ), + array( 'lhs' => 99, 'rhs' => 3 ), + array( 'lhs' => 99, 'rhs' => 3 ), + array( 'lhs' => 99, 'rhs' => 2 ), + array( 'lhs' => 99, 'rhs' => 2 ), + array( 'lhs' => 99, 'rhs' => 3 ), + array( 'lhs' => 99, 'rhs' => 3 ), + array( 'lhs' => 99, 'rhs' => 2 ), + array( 'lhs' => 99, 'rhs' => 2 ), + array( 'lhs' => 99, 'rhs' => 3 ), + array( 'lhs' => 99, 'rhs' => 3 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 101, 'rhs' => 1 ), + array( 'lhs' => 101, 'rhs' => 1 ), + array( 'lhs' => 84, 'rhs' => 3 ), + array( 'lhs' => 102, 'rhs' => 1 ), + array( 'lhs' => 102, 'rhs' => 3 ), + array( 'lhs' => 102, 'rhs' => 0 ), + array( 'lhs' => 103, 'rhs' => 1 ), + array( 'lhs' => 103, 'rhs' => 3 ), + array( 'lhs' => 103, 'rhs' => 3 ), + array( 'lhs' => 89, 'rhs' => 2 ), + array( 'lhs' => 89, 'rhs' => 1 ), + array( 'lhs' => 104, 'rhs' => 1 ), + array( 'lhs' => 104, 'rhs' => 3 ), + array( 'lhs' => 104, 'rhs' => 3 ), + array( 'lhs' => 104, 'rhs' => 1 ), + array( 'lhs' => 72, 'rhs' => 2 ), + array( 'lhs' => 72, 'rhs' => 1 ), + array( 'lhs' => 105, 'rhs' => 1 ), + array( 'lhs' => 105, 'rhs' => 1 ), + ); + + /** + * The following table contains a mapping of reduce action to method name + * that handles the reduction. + * + * If a rule is not set, it has no handler. + */ + static public $yyReduceMap = array( + 0 => 0, + 37 => 0, + 43 => 0, + 45 => 0, + 46 => 0, + 47 => 0, + 48 => 0, + 63 => 0, + 117 => 0, + 1 => 1, + 34 => 1, + 36 => 1, + 41 => 1, + 42 => 1, + 70 => 1, + 90 => 1, + 124 => 1, + 130 => 1, + 131 => 1, + 132 => 1, + 2 => 2, + 64 => 2, + 123 => 2, + 129 => 2, + 3 => 3, + 4 => 4, + 5 => 5, + 6 => 6, + 7 => 7, + 8 => 8, + 9 => 9, + 10 => 10, + 11 => 11, + 12 => 12, + 13 => 13, + 14 => 14, + 15 => 15, + 16 => 16, + 17 => 17, + 18 => 18, + 19 => 19, + 20 => 20, + 21 => 21, + 22 => 22, + 23 => 23, + 27 => 23, + 82 => 23, + 120 => 23, + 24 => 24, + 25 => 24, + 26 => 26, + 28 => 28, + 29 => 29, + 30 => 30, + 31 => 31, + 32 => 32, + 33 => 33, + 35 => 35, + 38 => 38, + 39 => 39, + 40 => 40, + 44 => 44, + 49 => 49, + 50 => 50, + 51 => 51, + 53 => 51, + 52 => 52, + 54 => 54, + 55 => 55, + 56 => 56, + 57 => 57, + 58 => 58, + 59 => 59, + 60 => 60, + 61 => 61, + 62 => 62, + 65 => 65, + 87 => 65, + 66 => 66, + 67 => 67, + 68 => 68, + 69 => 69, + 71 => 71, + 72 => 72, + 73 => 73, + 92 => 73, + 74 => 74, + 75 => 75, + 76 => 76, + 77 => 77, + 78 => 78, + 79 => 79, + 80 => 80, + 81 => 81, + 83 => 83, + 84 => 84, + 85 => 85, + 86 => 86, + 88 => 88, + 89 => 89, + 91 => 91, + 93 => 93, + 94 => 94, + 95 => 94, + 96 => 96, + 97 => 97, + 98 => 98, + 103 => 98, + 99 => 99, + 102 => 99, + 100 => 100, + 105 => 100, + 101 => 101, + 104 => 101, + 106 => 106, + 107 => 107, + 108 => 108, + 109 => 109, + 110 => 110, + 111 => 111, + 112 => 112, + 113 => 113, + 114 => 114, + 115 => 115, + 116 => 116, + 118 => 118, + 119 => 119, + 121 => 121, + 122 => 122, + 125 => 125, + 126 => 126, + 127 => 127, + 128 => 128, + ); + /* Beginning here are the reduction cases. A typical example + ** follows: + ** #line + ** function yy_r0($yymsp){ ... } // User supplied code + ** #line + */ +#line 73 "internal.templateparser.y" + function yy_r0(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 1724 "internal.templateparser.php" +#line 79 "internal.templateparser.y" + function yy_r1(){$this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 1727 "internal.templateparser.php" +#line 81 "internal.templateparser.y" + function yy_r2(){$this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; } +#line 1730 "internal.templateparser.php" +#line 87 "internal.templateparser.y" + function yy_r3(){if ($this->compiler->has_code) { + $tmp =''; foreach ($this->prefix_code as $code) {$tmp.=$code;} $this->prefix_code=array(); + $this->_retvalue = $this->cacher->processNocacheCode($tmp.$this->yystack[$this->yyidx + 0]->minor, $this->compiler,$this->nocache,true); + } $this->nocache=false; } +#line 1736 "internal.templateparser.php" +#line 100 "internal.templateparser.y" + function yy_r4(){ $this->_retvalue = ''; } +#line 1739 "internal.templateparser.php" +#line 103 "internal.templateparser.y" + function yy_r5(){$this->_retvalue = $this->cacher->processNocacheCode($this->yystack[$this->yyidx + -1]->minor, $this->compiler,false,false); } +#line 1742 "internal.templateparser.php" +#line 105 "internal.templateparser.y" + function yy_r6(){$this->_retvalue = $this->cacher->processNocacheCode($this->smarty->left_delimiter, $this->compiler,false,false); } +#line 1745 "internal.templateparser.php" +#line 107 "internal.templateparser.y" + function yy_r7(){$this->_retvalue = $this->cacher->processNocacheCode($this->smarty->right_delimiter, $this->compiler,false,false); } +#line 1748 "internal.templateparser.php" +#line 109 "internal.templateparser.y" + function yy_r8(){if (!$this->template->security) { + $this->_retvalue = $this->cacher->processNocacheCode($this->yystack[$this->yyidx + 0]->minor, $this->compiler, false,true); + } elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_QUOTE) { + $this->_retvalue = $this->cacher->processNocacheCode(htmlspecialchars($this->yystack[$this->yyidx + 0]->minor, ENT_QUOTES), $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_PASSTHRU || $this->smarty->security_policy->php_handling == SMARTY_PHP_ALLOW) { + $this->_retvalue = $this->cacher->processNocacheCode("yystack[$this->yyidx + 0]->minor."';?>\n", $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_REMOVE) { + $this->_retvalue = ''; + } } +#line 1759 "internal.templateparser.php" +#line 119 "internal.templateparser.y" + function yy_r9(){if (!$this->template->security) { + $this->_retvalue = $this->cacher->processNocacheCode('yystack[$this->yyidx + -1]->minor.' ?>', $this->compiler, false,true); + } elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_QUOTE) { + $this->_retvalue = $this->cacher->processNocacheCode(htmlspecialchars('yystack[$this->yyidx + -1]->minor.' ?>', ENT_QUOTES), $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_PASSTHRU || $this->smarty->security_policy->php_handling == SMARTY_PHP_ALLOW) { + $this->_retvalue = $this->cacher->processNocacheCode("yystack[$this->yyidx + -1]->minor." ?>';?>\n", $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_REMOVE) { + $this->_retvalue = ''; + } } +#line 1770 "internal.templateparser.php" +#line 129 "internal.templateparser.y" + function yy_r10(){if (!$this->template->security) { + $this->_retvalue = $this->cacher->processNocacheCode($this->compiler->compileTag('print_expression',array('value'=>$this->yystack[$this->yyidx + -1]->minor)), $this->compiler, false,true); + } elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_QUOTE) { + $this->_retvalue = $this->cacher->processNocacheCode(htmlspecialchars('', ENT_QUOTES), $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_PASSTHRU || $this->smarty->security_policy->php_handling == SMARTY_PHP_ALLOW) { + $this->_retvalue = $this->cacher->processNocacheCode("';?>\n", $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_REMOVE) { + $this->_retvalue = ''; + } } +#line 1781 "internal.templateparser.php" +#line 139 "internal.templateparser.y" + function yy_r11(){$this->_retvalue = $this->cacher->processNocacheCode("yystack[$this->yyidx + 0]->minor."';?>\n", $this->compiler, true, true); } +#line 1784 "internal.templateparser.php" +#line 141 "internal.templateparser.y" + function yy_r12(){$this->_retvalue = $this->cacher->processNocacheCode($this->yystack[$this->yyidx + 0]->minor, $this->compiler,false,false); } +#line 1787 "internal.templateparser.php" +#line 149 "internal.templateparser.y" + function yy_r13(){ $this->_retvalue = $this->compiler->compileTag('print_expression',array_merge(array('value'=>$this->yystack[$this->yyidx + -2]->minor),$this->yystack[$this->yyidx + -1]->minor)); } +#line 1790 "internal.templateparser.php" +#line 151 "internal.templateparser.y" + function yy_r14(){ $this->_retvalue = $this->compiler->compileTag('assign',$this->yystack[$this->yyidx + -1]->minor); } +#line 1793 "internal.templateparser.php" +#line 153 "internal.templateparser.y" + function yy_r15(){ $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -2]->minor,$this->yystack[$this->yyidx + -1]->minor); } +#line 1796 "internal.templateparser.php" +#line 155 "internal.templateparser.y" + function yy_r16(){ $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -4]->minor,array_merge(array('object_methode'=>$this->yystack[$this->yyidx + -2]->minor),$this->yystack[$this->yyidx + -1]->minor)); } +#line 1799 "internal.templateparser.php" +#line 157 "internal.templateparser.y" + function yy_r17(){ $this->_retvalue = ''.$this->compiler->compileTag($this->yystack[$this->yyidx + -4]->minor,$this->yystack[$this->yyidx + -1]->minor).'smarty->plugin_handler->loadSmartyPlugin($this->yystack[$this->yyidx + -3]->minor[0],'modifier')) { + $this->_retvalue .= "\$_smarty_tpl->smarty->plugin_handler->".$this->yystack[$this->yyidx + -3]->minor[0] . "(array(ob_get_clean()". $this->yystack[$this->yyidx + -2]->minor ."),'modifier');?>"; + } else { + if ($this->yystack[$this->yyidx + -3]->minor[0] == 'isset' || $this->yystack[$this->yyidx + -3]->minor[0] == 'empty' || is_callable($this->yystack[$this->yyidx + -3]->minor[0])) { + if (!$this->template->security || $this->smarty->security_handler->isTrustedModifier($this->yystack[$this->yyidx + -3]->minor[0], $this->compiler)) { + $this->_retvalue .= $this->yystack[$this->yyidx + -3]->minor[0] . "(ob_get_clean()". $this->yystack[$this->yyidx + -2]->minor .");?>"; + } + } else { + $this->compiler->trigger_template_error ("unknown modifier \"" . $this->yystack[$this->yyidx + -3]->minor[0] . "\""); + } + } + } +#line 1814 "internal.templateparser.php" +#line 171 "internal.templateparser.y" + function yy_r18(){ $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -2]->minor.'close',$this->yystack[$this->yyidx + -1]->minor); } +#line 1817 "internal.templateparser.php" +#line 173 "internal.templateparser.y" + function yy_r19(){ $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -3]->minor.'close',array('object_methode'=>$this->yystack[$this->yyidx + -1]->minor)); } +#line 1820 "internal.templateparser.php" +#line 175 "internal.templateparser.y" + function yy_r20(){ $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -3]->minor,array('if condition'=>$this->yystack[$this->yyidx + -1]->minor)); } +#line 1823 "internal.templateparser.php" +#line 177 "internal.templateparser.y" + function yy_r21(){ $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -9]->minor,array('start'=>$this->yystack[$this->yyidx + -7]->minor,'ifexp'=>$this->yystack[$this->yyidx + -5]->minor,'varloop'=>$this->yystack[$this->yyidx + -2]->minor,'loop'=>$this->yystack[$this->yyidx + -1]->minor)); } +#line 1826 "internal.templateparser.php" +#line 178 "internal.templateparser.y" + function yy_r22(){ $this->_retvalue = '='.$this->yystack[$this->yyidx + 0]->minor; } +#line 1829 "internal.templateparser.php" +#line 179 "internal.templateparser.y" + function yy_r23(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 1832 "internal.templateparser.php" +#line 182 "internal.templateparser.y" + function yy_r24(){ $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -6]->minor,array('from'=>$this->yystack[$this->yyidx + -1]->minor,'item'=>$this->yystack[$this->yyidx + -3]->minor)); } +#line 1835 "internal.templateparser.php" +#line 189 "internal.templateparser.y" + function yy_r26(){ $this->_retvalue = array_merge($this->yystack[$this->yyidx + -1]->minor,$this->yystack[$this->yyidx + 0]->minor); } +#line 1838 "internal.templateparser.php" +#line 193 "internal.templateparser.y" + function yy_r28(){ $this->_retvalue = array(); } +#line 1841 "internal.templateparser.php" +#line 197 "internal.templateparser.y" + function yy_r29(){ $this->_retvalue = array($this->yystack[$this->yyidx + -2]->minor=>$this->yystack[$this->yyidx + 0]->minor); } +#line 1844 "internal.templateparser.php" +#line 202 "internal.templateparser.y" + function yy_r30(){ $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor); } +#line 1847 "internal.templateparser.php" +#line 203 "internal.templateparser.y" + function yy_r31(){ $this->yystack[$this->yyidx + -2]->minor[]=$this->yystack[$this->yyidx + 0]->minor; $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; } +#line 1850 "internal.templateparser.php" +#line 205 "internal.templateparser.y" + function yy_r32(){ $this->_retvalue = array('var' => $this->yystack[$this->yyidx + -2]->minor, 'value'=>$this->yystack[$this->yyidx + 0]->minor); } +#line 1853 "internal.templateparser.php" +#line 212 "internal.templateparser.y" + function yy_r33(){ $this->_retvalue = '\''.$this->yystack[$this->yyidx + 0]->minor.'\''; } +#line 1856 "internal.templateparser.php" +#line 216 "internal.templateparser.y" + function yy_r35(){ + if ($this->smarty->plugin_handler->loadSmartyPlugin($this->yystack[$this->yyidx + -1]->minor[0],'modifier')) { + $this->_retvalue = "\$_smarty_tpl->smarty->plugin_handler->".$this->yystack[$this->yyidx + -1]->minor[0] . "(array(". $this->yystack[$this->yyidx + -2]->minor . $this->yystack[$this->yyidx + 0]->minor ."),'modifier')"; + } else { + if ($this->yystack[$this->yyidx + -1]->minor[0] == 'isset' || $this->yystack[$this->yyidx + -1]->minor[0] == 'empty' || is_callable($this->yystack[$this->yyidx + -1]->minor[0])) { + if (!$this->template->security || $this->smarty->security_handler->isTrustedModifier($this->yystack[$this->yyidx + -1]->minor[0], $this->compiler)) { + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor[0] . "(". $this->yystack[$this->yyidx + -2]->minor . $this->yystack[$this->yyidx + 0]->minor .")"; + } + } else { + $this->compiler->trigger_template_error ("unknown modifier \"" . $this->yystack[$this->yyidx + -1]->minor[0] . "\""); + } + } + } +#line 1871 "internal.templateparser.php" +#line 234 "internal.templateparser.y" + function yy_r38(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; } +#line 1874 "internal.templateparser.php" +#line 236 "internal.templateparser.y" + function yy_r39(){ $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor . $this->yystack[$this->yyidx + -1]->minor . $this->yystack[$this->yyidx + 0]->minor; } +#line 1877 "internal.templateparser.php" +#line 238 "internal.templateparser.y" + function yy_r40(){ $this->_retvalue = '('. $this->yystack[$this->yyidx + -2]->minor . ').(' . $this->yystack[$this->yyidx + 0]->minor. ')'; } +#line 1880 "internal.templateparser.php" +#line 252 "internal.templateparser.y" + function yy_r44(){$this->_retvalue = '$_smarty_tpl->getConfigVariable(\''. $this->yystack[$this->yyidx + -1]->minor .'\')'; } +#line 1883 "internal.templateparser.php" +#line 263 "internal.templateparser.y" + function yy_r49(){ $this->_retvalue = "(". $this->yystack[$this->yyidx + -1]->minor .")"; } +#line 1886 "internal.templateparser.php" +#line 266 "internal.templateparser.y" + function yy_r50(){ $this->_retvalue = "'".$this->yystack[$this->yyidx + -1]->minor."'"; } +#line 1889 "internal.templateparser.php" +#line 267 "internal.templateparser.y" + function yy_r51(){ $this->_retvalue = "''"; } +#line 1892 "internal.templateparser.php" +#line 269 "internal.templateparser.y" + function yy_r52(){ $this->_retvalue = "'".str_replace('\"','"',$this->yystack[$this->yyidx + -1]->minor)."'"; } +#line 1895 "internal.templateparser.php" +#line 275 "internal.templateparser.y" + function yy_r54(){ $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.'::'.$this->yystack[$this->yyidx + 0]->minor; } +#line 1898 "internal.templateparser.php" +#line 276 "internal.templateparser.y" + function yy_r55(){ $this->prefix_number++; $this->prefix_code[] = 'prefix_number.'=$_smarty_tpl->getVariable(\''. $this->yystack[$this->yyidx + -3]->minor .'\')->value;?>'; $this->_retvalue = $this->yystack[$this->yyidx + -6]->minor.'::$_tmp'.$this->prefix_number.'('. $this->yystack[$this->yyidx + -1]->minor .')'; } +#line 1901 "internal.templateparser.php" +#line 278 "internal.templateparser.y" + function yy_r56(){ $this->_retvalue = $this->yystack[$this->yyidx + -3]->minor.'::'.$this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; } +#line 1904 "internal.templateparser.php" +#line 279 "internal.templateparser.y" + function yy_r57(){ $this->prefix_number++; $this->prefix_code[] = 'prefix_number.'=$_smarty_tpl->getVariable(\''. $this->yystack[$this->yyidx + -4]->minor .'\')->value;?>'; $this->_retvalue = $this->yystack[$this->yyidx + -7]->minor.'::$_tmp'.$this->prefix_number.'('. $this->yystack[$this->yyidx + -2]->minor .')'.$this->yystack[$this->yyidx + 0]->minor; } +#line 1907 "internal.templateparser.php" +#line 281 "internal.templateparser.y" + function yy_r58(){ $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.'::'.$this->yystack[$this->yyidx + 0]->minor; } +#line 1910 "internal.templateparser.php" +#line 283 "internal.templateparser.y" + function yy_r59(){ $this->_retvalue = $this->yystack[$this->yyidx + -4]->minor.'::$'.$this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; } +#line 1913 "internal.templateparser.php" +#line 285 "internal.templateparser.y" + function yy_r60(){ $this->_retvalue = $this->yystack[$this->yyidx + -5]->minor.'::$'.$this->yystack[$this->yyidx + -2]->minor.$this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; } +#line 1916 "internal.templateparser.php" +#line 292 "internal.templateparser.y" + function yy_r61(){ if ($this->yystack[$this->yyidx + -1]->minor == '\'smarty\'') { $this->_retvalue = $this->compiler->compileTag(trim($this->yystack[$this->yyidx + -1]->minor,"'"),$this->yystack[$this->yyidx + 0]->minor);} else { + $this->_retvalue = '$_smarty_tpl->getVariable('. $this->yystack[$this->yyidx + -1]->minor .')->value'.$this->yystack[$this->yyidx + 0]->minor; $this->nocache=$this->template->getVariable(trim($this->yystack[$this->yyidx + -1]->minor,"'"))->nocache;} } +#line 1920 "internal.templateparser.php" +#line 295 "internal.templateparser.y" + function yy_r62(){ $this->_retvalue = '$_smarty_tpl->getVariable('. $this->yystack[$this->yyidx + -2]->minor .')->'.$this->yystack[$this->yyidx + 0]->minor; $this->nocache=$this->template->getVariable(trim($this->yystack[$this->yyidx + -2]->minor,"'"))->nocache; } +#line 1923 "internal.templateparser.php" +#line 307 "internal.templateparser.y" + function yy_r65(){return; } +#line 1926 "internal.templateparser.php" +#line 311 "internal.templateparser.y" + function yy_r66(){ $this->_retvalue = "['". $this->yystack[$this->yyidx + 0]->minor ."']"; } +#line 1929 "internal.templateparser.php" +#line 312 "internal.templateparser.y" + function yy_r67(){ $this->_retvalue = "[". $this->yystack[$this->yyidx + 0]->minor ."]"; } +#line 1932 "internal.templateparser.php" +#line 314 "internal.templateparser.y" + function yy_r68(){ $this->_retvalue = '['.$this->compiler->compileTag('smarty','[\'section\'][\''.$this->yystack[$this->yyidx + -1]->minor.'\'][\'index\']').']'; } +#line 1935 "internal.templateparser.php" +#line 316 "internal.templateparser.y" + function yy_r69(){ $this->_retvalue = "[". $this->yystack[$this->yyidx + -1]->minor ."]"; } +#line 1938 "internal.templateparser.php" +#line 324 "internal.templateparser.y" + function yy_r71(){$this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.'.'.$this->yystack[$this->yyidx + 0]->minor; } +#line 1941 "internal.templateparser.php" +#line 326 "internal.templateparser.y" + function yy_r72(){$this->_retvalue = '\''.$this->yystack[$this->yyidx + 0]->minor.'\''; } +#line 1944 "internal.templateparser.php" +#line 328 "internal.templateparser.y" + function yy_r73(){$this->_retvalue = '('.$this->yystack[$this->yyidx + -1]->minor.')'; } +#line 1947 "internal.templateparser.php" +#line 333 "internal.templateparser.y" + function yy_r74(){ $this->_retvalue = '$_smarty_tpl->getVariable('. $this->yystack[$this->yyidx + -2]->minor .')->value'.$this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; $this->nocache=$this->template->getVariable(trim($this->yystack[$this->yyidx + -2]->minor,"'"))->nocache; } +#line 1950 "internal.templateparser.php" +#line 335 "internal.templateparser.y" + function yy_r75(){$this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 1953 "internal.templateparser.php" +#line 337 "internal.templateparser.y" + function yy_r76(){$this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; } +#line 1956 "internal.templateparser.php" +#line 339 "internal.templateparser.y" + function yy_r77(){ $this->_retvalue = '->'.$this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; } +#line 1959 "internal.templateparser.php" +#line 342 "internal.templateparser.y" + function yy_r78(){ $this->_retvalue = '->'.$this->yystack[$this->yyidx + 0]->minor; } +#line 1962 "internal.templateparser.php" +#line 348 "internal.templateparser.y" + function yy_r79(){if (!$this->template->security || $this->smarty->security_handler->isTrustedPhpFunction($this->yystack[$this->yyidx + -3]->minor, $this->compiler)) { + if ($this->yystack[$this->yyidx + -3]->minor == 'isset' || $this->yystack[$this->yyidx + -3]->minor == 'empty' || is_callable($this->yystack[$this->yyidx + -3]->minor)) { + $this->_retvalue = $this->yystack[$this->yyidx + -3]->minor . "(". $this->yystack[$this->yyidx + -1]->minor .")"; + } else { + $this->compiler->trigger_template_error ("unknown function \"" . $this->yystack[$this->yyidx + -3]->minor . "\""); + } + } } +#line 1971 "internal.templateparser.php" +#line 359 "internal.templateparser.y" + function yy_r80(){ $this->_retvalue = $this->yystack[$this->yyidx + -3]->minor . "(". $this->yystack[$this->yyidx + -1]->minor .")"; } +#line 1974 "internal.templateparser.php" +#line 363 "internal.templateparser.y" + function yy_r81(){ $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.",".$this->yystack[$this->yyidx + 0]->minor; } +#line 1977 "internal.templateparser.php" +#line 367 "internal.templateparser.y" + function yy_r83(){ return; } +#line 1980 "internal.templateparser.php" +#line 372 "internal.templateparser.y" + function yy_r84(){ $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor,true); } +#line 1983 "internal.templateparser.php" +#line 373 "internal.templateparser.y" + function yy_r85(){ $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor,false); } +#line 1986 "internal.templateparser.php" +#line 380 "internal.templateparser.y" + function yy_r86(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; } +#line 1989 "internal.templateparser.php" +#line 384 "internal.templateparser.y" + function yy_r88(){$this->_retvalue = ',\''.$this->yystack[$this->yyidx + 0]->minor.'\''; } +#line 1992 "internal.templateparser.php" +#line 385 "internal.templateparser.y" + function yy_r89(){$this->_retvalue = ','.$this->yystack[$this->yyidx + 0]->minor; } +#line 1995 "internal.templateparser.php" +#line 392 "internal.templateparser.y" + function yy_r91(){$this->_retvalue = '!'.$this->yystack[$this->yyidx + 0]->minor; } +#line 1998 "internal.templateparser.php" +#line 397 "internal.templateparser.y" + function yy_r93(){$this->_retvalue =$this->yystack[$this->yyidx + 0]->minor; } +#line 2001 "internal.templateparser.php" +#line 398 "internal.templateparser.y" + function yy_r94(){$this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.$this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; } +#line 2004 "internal.templateparser.php" +#line 400 "internal.templateparser.y" + function yy_r96(){$this->_retvalue = '!('.$this->yystack[$this->yyidx + -2]->minor.' % '.$this->yystack[$this->yyidx + 0]->minor.')'; } +#line 2007 "internal.templateparser.php" +#line 401 "internal.templateparser.y" + function yy_r97(){$this->_retvalue = '('.$this->yystack[$this->yyidx + -2]->minor.' % '.$this->yystack[$this->yyidx + 0]->minor.')'; } +#line 2010 "internal.templateparser.php" +#line 402 "internal.templateparser.y" + function yy_r98(){$this->_retvalue = '!(1 & '.$this->yystack[$this->yyidx + -1]->minor.')'; } +#line 2013 "internal.templateparser.php" +#line 403 "internal.templateparser.y" + function yy_r99(){$this->_retvalue = '(1 & '.$this->yystack[$this->yyidx + -1]->minor.')'; } +#line 2016 "internal.templateparser.php" +#line 404 "internal.templateparser.y" + function yy_r100(){$this->_retvalue = '!(1 & '.$this->yystack[$this->yyidx + -2]->minor.' / '.$this->yystack[$this->yyidx + 0]->minor.')'; } +#line 2019 "internal.templateparser.php" +#line 405 "internal.templateparser.y" + function yy_r101(){$this->_retvalue = '(1 & '.$this->yystack[$this->yyidx + -2]->minor.' / '.$this->yystack[$this->yyidx + 0]->minor.')'; } +#line 2022 "internal.templateparser.php" +#line 411 "internal.templateparser.y" + function yy_r106(){$this->_retvalue = '=='; } +#line 2025 "internal.templateparser.php" +#line 412 "internal.templateparser.y" + function yy_r107(){$this->_retvalue = '!='; } +#line 2028 "internal.templateparser.php" +#line 413 "internal.templateparser.y" + function yy_r108(){$this->_retvalue = '>'; } +#line 2031 "internal.templateparser.php" +#line 414 "internal.templateparser.y" + function yy_r109(){$this->_retvalue = '<'; } +#line 2034 "internal.templateparser.php" +#line 415 "internal.templateparser.y" + function yy_r110(){$this->_retvalue = '>='; } +#line 2037 "internal.templateparser.php" +#line 416 "internal.templateparser.y" + function yy_r111(){$this->_retvalue = '<='; } +#line 2040 "internal.templateparser.php" +#line 417 "internal.templateparser.y" + function yy_r112(){$this->_retvalue = '==='; } +#line 2043 "internal.templateparser.php" +#line 418 "internal.templateparser.y" + function yy_r113(){$this->_retvalue = '!=='; } +#line 2046 "internal.templateparser.php" +#line 420 "internal.templateparser.y" + function yy_r114(){$this->_retvalue = '&&'; } +#line 2049 "internal.templateparser.php" +#line 421 "internal.templateparser.y" + function yy_r115(){$this->_retvalue = '||'; } +#line 2052 "internal.templateparser.php" +#line 426 "internal.templateparser.y" + function yy_r116(){ $this->_retvalue = 'array('.$this->yystack[$this->yyidx + -1]->minor.')'; } +#line 2055 "internal.templateparser.php" +#line 428 "internal.templateparser.y" + function yy_r118(){ $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.','.$this->yystack[$this->yyidx + 0]->minor; } +#line 2058 "internal.templateparser.php" +#line 429 "internal.templateparser.y" + function yy_r119(){ return; } +#line 2061 "internal.templateparser.php" +#line 431 "internal.templateparser.y" + function yy_r121(){ $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.'=>'.$this->yystack[$this->yyidx + 0]->minor; } +#line 2064 "internal.templateparser.php" +#line 432 "internal.templateparser.y" + function yy_r122(){ $this->_retvalue = '\''.$this->yystack[$this->yyidx + -2]->minor.'\'=>'.$this->yystack[$this->yyidx + 0]->minor; } +#line 2067 "internal.templateparser.php" +#line 439 "internal.templateparser.y" + function yy_r125(){$this->_retvalue = "'.".$this->yystack[$this->yyidx + 0]->minor.".'"; } +#line 2070 "internal.templateparser.php" +#line 440 "internal.templateparser.y" + function yy_r126(){$this->_retvalue = "'.".$this->yystack[$this->yyidx + -1]->minor.".'"; } +#line 2073 "internal.templateparser.php" +#line 441 "internal.templateparser.y" + function yy_r127(){$this->_retvalue = "'.(".$this->yystack[$this->yyidx + -1]->minor.").'"; } +#line 2076 "internal.templateparser.php" +#line 442 "internal.templateparser.y" + function yy_r128(){$this->_retvalue = addcslashes($this->yystack[$this->yyidx + 0]->minor,"'"); } +#line 2079 "internal.templateparser.php" + + /** + * placeholder for the left hand side in a reduce operation. + * + * For a parser with a rule like this: + *
+     * rule(A) ::= B. { A = 1; }
+     * 
+ * + * The parser will translate to something like: + * + * + * function yy_r0(){$this->_retvalue = 1;} + * + */ + private $_retvalue; + + /** + * Perform a reduce action and the shift that must immediately + * follow the reduce. + * + * For a rule such as: + * + *
+     * A ::= B blah C. { dosomething(); }
+     * 
+ * + * This function will first call the action, if any, ("dosomething();" in our + * example), and then it will pop three states from the stack, + * one for each entry on the right-hand side of the expression + * (B, blah, and C in our example rule), and then push the result of the action + * back on to the stack with the resulting state reduced to (as described in the .out + * file) + * @param int Number of the rule by which to reduce + */ + function yy_reduce($yyruleno) + { + //int $yygoto; /* The next state */ + //int $yyact; /* The next action */ + //mixed $yygotominor; /* The LHS of the rule reduced */ + //TP_yyStackEntry $yymsp; /* The top of the parser's stack */ + //int $yysize; /* Amount to pop the stack */ + $yymsp = $this->yystack[$this->yyidx]; + if (self::$yyTraceFILE && $yyruleno >= 0 + && $yyruleno < count(self::$yyRuleName)) { + fprintf(self::$yyTraceFILE, "%sReduce (%d) [%s].\n", + self::$yyTracePrompt, $yyruleno, + self::$yyRuleName[$yyruleno]); + } + + $this->_retvalue = $yy_lefthand_side = null; + if (array_key_exists($yyruleno, self::$yyReduceMap)) { + // call the action + $this->_retvalue = null; + $this->{'yy_r' . self::$yyReduceMap[$yyruleno]}(); + $yy_lefthand_side = $this->_retvalue; + } + $yygoto = self::$yyRuleInfo[$yyruleno]['lhs']; + $yysize = self::$yyRuleInfo[$yyruleno]['rhs']; + $this->yyidx -= $yysize; + for($i = $yysize; $i; $i--) { + // pop all of the right-hand side parameters + array_pop($this->yystack); + } + $yyact = $this->yy_find_reduce_action($this->yystack[$this->yyidx]->stateno, $yygoto); + if ($yyact < self::YYNSTATE) { + /* If we are not debugging and the reduce action popped at least + ** one element off the stack, then we can push the new element back + ** onto the stack here, and skip the stack overflow test in yy_shift(). + ** That gives a significant speed improvement. */ + if (!self::$yyTraceFILE && $yysize) { + $this->yyidx++; + $x = new TP_yyStackEntry; + $x->stateno = $yyact; + $x->major = $yygoto; + $x->minor = $yy_lefthand_side; + $this->yystack[$this->yyidx] = $x; + } else { + $this->yy_shift($yyact, $yygoto, $yy_lefthand_side); + } + } elseif ($yyact == self::YYNSTATE + self::YYNRULE + 1) { + $this->yy_accept(); + } + } + + /** + * The following code executes when the parse fails + * + * Code from %parse_fail is inserted here + */ + function yy_parse_failed() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sFail!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser fails */ + } + + /** + * The following code executes when a syntax error first occurs. + * + * %syntax_error code is inserted here + * @param int The major type of the error token + * @param mixed The minor type of the error token + */ + function yy_syntax_error($yymajor, $TOKEN) + { +#line 55 "internal.templateparser.y" + + $this->internalError = true; + $this->yymajor = $yymajor; + $this->compiler->trigger_template_error(); +#line 2197 "internal.templateparser.php" + } + + /** + * The following is executed when the parser accepts + * + * %parse_accept code is inserted here + */ + function yy_accept() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sAccept!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $stack = $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser accepts */ +#line 47 "internal.templateparser.y" + + $this->successful = !$this->internalError; + $this->internalError = false; + $this->retvalue = $this->_retvalue; + //echo $this->retvalue."\n\n"; +#line 2222 "internal.templateparser.php" + } + + /** + * The main parser program. + * + * The first argument is the major token number. The second is + * the token value string as scanned from the input. + * + * @param int the token number + * @param mixed the token value + * @param mixed any extra arguments that should be passed to handlers + */ + function doParse($yymajor, $yytokenvalue) + { +// $yyact; /* The parser action. */ +// $yyendofinput; /* True if we are at the end of input */ + $yyerrorhit = 0; /* True if yymajor has invoked an error */ + + /* (re)initialize the parser, if necessary */ + if ($this->yyidx === null || $this->yyidx < 0) { + /* if ($yymajor == 0) return; // not sure why this was here... */ + $this->yyidx = 0; + $this->yyerrcnt = -1; + $x = new TP_yyStackEntry; + $x->stateno = 0; + $x->major = 0; + $this->yystack = array(); + array_push($this->yystack, $x); + } + $yyendofinput = ($yymajor==0); + + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sInput %s\n", + self::$yyTracePrompt, $this->yyTokenName[$yymajor]); + } + + do { + $yyact = $this->yy_find_shift_action($yymajor); + if ($yymajor < self::YYERRORSYMBOL && + !$this->yy_is_expected_token($yymajor)) { + // force a syntax error + $yyact = self::YY_ERROR_ACTION; + } + if ($yyact < self::YYNSTATE) { + $this->yy_shift($yyact, $yymajor, $yytokenvalue); + $this->yyerrcnt--; + if ($yyendofinput && $this->yyidx >= 0) { + $yymajor = 0; + } else { + $yymajor = self::YYNOCODE; + } + } elseif ($yyact < self::YYNSTATE + self::YYNRULE) { + $this->yy_reduce($yyact - self::YYNSTATE); + } elseif ($yyact == self::YY_ERROR_ACTION) { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sSyntax Error!\n", + self::$yyTracePrompt); + } + if (self::YYERRORSYMBOL) { + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if ($this->yyerrcnt < 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $yymx = $this->yystack[$this->yyidx]->major; + if ($yymx == self::YYERRORSYMBOL || $yyerrorhit ){ + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sDiscard input token %s\n", + self::$yyTracePrompt, $this->yyTokenName[$yymajor]); + } + $this->yy_destructor($yymajor, $yytokenvalue); + $yymajor = self::YYNOCODE; + } else { + while ($this->yyidx >= 0 && + $yymx != self::YYERRORSYMBOL && + ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE + ){ + $this->yy_pop_parser_stack(); + } + if ($this->yyidx < 0 || $yymajor==0) { + $this->yy_destructor($yymajor, $yytokenvalue); + $this->yy_parse_failed(); + $yymajor = self::YYNOCODE; + } elseif ($yymx != self::YYERRORSYMBOL) { + $u2 = 0; + $this->yy_shift($yyact, self::YYERRORSYMBOL, $u2); + } + } + $this->yyerrcnt = 3; + $yyerrorhit = 1; + } else { + /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if ($this->yyerrcnt <= 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $this->yyerrcnt = 3; + $this->yy_destructor($yymajor, $yytokenvalue); + if ($yyendofinput) { + $this->yy_parse_failed(); + } + $yymajor = self::YYNOCODE; + } + } else { + $this->yy_accept(); + $yymajor = self::YYNOCODE; + } + } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0); + } +} diff --git a/libs/lexer/internal.templateparser.y b/libs/lexer/internal.templateparser.y new file mode 100644 index 00000000..c8fb0db3 --- /dev/null +++ b/libs/lexer/internal.templateparser.y @@ -0,0 +1,452 @@ +/** +* Smarty Internal Plugin Templateparser +* +* This is the template parser +* +* +* @package Smarty +* @subpackage Compiler +* @author Uwe Tews +*/ +%name TP_ +%declare_class {class Smarty_Internal_Templateparser} +%include_class +{ + // states whether the parse was successful or not + public $successful = true; + public $retvalue = 0; + private $lex; + private $internalError = false; + + function __construct($lex, $compiler) { + // set instance object + self::instance($this); + $this->lex = $lex; + $this->smarty = Smarty::instance(); + $this->compiler = $compiler; + $this->template = $this->compiler->template; + $this->cacher = $this->template->cacher_object; + $this->nocache = false; + $this->prefix_code = array(); + $this->prefix_number = 0; + } + public static function &instance($new_instance = null) + { + static $instance = null; + if (isset($new_instance) && is_object($new_instance)) + $instance = $new_instance; + return $instance; + } + +} + + +%token_prefix TP_ + +%parse_accept +{ + $this->successful = !$this->internalError; + $this->internalError = false; + $this->retvalue = $this->_retvalue; + //echo $this->retvalue."\n\n"; +} + +%syntax_error +{ + $this->internalError = true; + $this->yymajor = $yymajor; + $this->compiler->trigger_template_error(); +} + +// +// fallback definition to catch all non Smarty template text +// +%fallback OTHER LDELSLASH LDEL RDEL XML PHP SHORTTAGSTART SHORTTAGEND COMMENTEND COMMENTSTART NUMBER MATH UNIMATH INCDEC OPENP CLOSEP OPENB CLOSEB DOLLAR DOT COMMA COLON DOUBLECOLON SEMICOLON + VERT EQUAL SPACE PTR APTR ID EQUALS NOTEQUALS GREATERTHAN LESSTHAN GREATEREQUAL LESSEQUAL IDENTITY NONEIDENTITY + NOT LAND LOR QUOTE SINGLEQUOTE BOOLEAN NULL IN ANDSYM BACKTICK HATCH AT ISODD ISNOTODD ISEVEN ISNOTEVEN ISODDBY ISNOTODDBY + ISEVENBY ISNOTEVENBY ISDIVBY ISNOTDIVBY. + + +// +// complete template +// +start(res) ::= template(t). { res = t; } + +// +// loop over template elements +// + // single template element +template(res) ::= template_element(e). {res = e;} + // loop of elements +template(res) ::= template(t) template_element(e). {res = t.e;} + +// +// template elements +// + // Smarty tag +template_element(res)::= smartytag(st). {if ($this->compiler->has_code) { + $tmp =''; foreach ($this->prefix_code as $code) {$tmp.=$code;} $this->prefix_code=array(); + res = $this->cacher->processNocacheCode($tmp.st, $this->compiler,$this->nocache,true); + } $this->nocache=false;} + // comments +//template_element(res)::= COMMENT(t). { res = $this->cacher->processNocacheCode('', $this->compiler,false,false);} +//template_element(res)::= COMMENTSTART text(t) COMMENTEND. {if ($this->smarty->comment_mode ==0) { +// res = ''; +// }elseif ($this->smarty->comment_mode ==1){ +// res = $this->cacher->processNocacheCode('', $this->compiler,false,false); +// }else{ +// res = $this->cacher->processNocacheCode('', $this->compiler,false,false); +// }} +template_element(res)::= COMMENTSTART text(t) COMMENTEND. { res = '';} + + // Literal +template_element(res)::= LITERALSTART text(t) LITERALEND. {res = $this->cacher->processNocacheCode(t, $this->compiler,false,false);} + // {ldelim} +template_element(res)::= LDELIMTAG. {res = $this->cacher->processNocacheCode($this->smarty->left_delimiter, $this->compiler,false,false);} + // {rdelim} +template_element(res)::= RDELIMTAG. {res = $this->cacher->processNocacheCode($this->smarty->right_delimiter, $this->compiler,false,false);} + // tag +template_element(res)::= PHP(phpt). {if (!$this->template->security) { + res = $this->cacher->processNocacheCode(phpt, $this->compiler, false,true); + } elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_QUOTE) { + res = $this->cacher->processNocacheCode(htmlspecialchars(phpt, ENT_QUOTES), $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_PASSTHRU || $this->smarty->security_policy->php_handling == SMARTY_PHP_ALLOW) { + res = $this->cacher->processNocacheCode("\n", $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_REMOVE) { + res = ''; + } } + // {PHP} tag +template_element(res)::= PHPSTART text(t) PHPEND. {if (!$this->template->security) { + res = $this->cacher->processNocacheCode('', $this->compiler, false,true); + } elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_QUOTE) { + res = $this->cacher->processNocacheCode(htmlspecialchars('', ENT_QUOTES), $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_PASSTHRU || $this->smarty->security_policy->php_handling == SMARTY_PHP_ALLOW) { + res = $this->cacher->processNocacheCode("';?>\n", $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_REMOVE) { + res = ''; + } } + +template_element(res)::= SHORTTAGSTART variable(v) SHORTTAGEND. {if (!$this->template->security) { + res = $this->cacher->processNocacheCode($this->compiler->compileTag('print_expression',array('value'=>v)), $this->compiler, false,true); + } elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_QUOTE) { + res = $this->cacher->processNocacheCode(htmlspecialchars('', ENT_QUOTES), $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_PASSTHRU || $this->smarty->security_policy->php_handling == SMARTY_PHP_ALLOW) { + res = $this->cacher->processNocacheCode("';?>\n", $this->compiler, false, false); + }elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_REMOVE) { + res = ''; + } } + // XML tag +template_element(res)::= XML(xml). {res = $this->cacher->processNocacheCode("\n", $this->compiler, true, true);} + // Other template text +template_element(res)::= OTHER(o). {res = $this->cacher->processNocacheCode(o, $this->compiler,false,false);} +//template_element(res)::= text(t). {res = $this->cacher->processNocacheCode(t, $this->compiler,false,false);} + + +// +// all Smarty tags start here +// + // output with optional attributes +smartytag(res) ::= LDEL expr(e) attributes(a) RDEL. { res = $this->compiler->compileTag('print_expression',array_merge(array('value'=>e),a));} + // assign new style +smartytag(res) ::= LDEL statement(s) RDEL. { res = $this->compiler->compileTag('assign',s);} + // tag with optional Smarty2 style attributes +smartytag(res) ::= LDEL ID(i) attributes(a) RDEL. { res = $this->compiler->compileTag(i,a);} + // registered object tag +smartytag(res) ::= LDEL ID(i) PTR ID(m) attributes(a) RDEL. { res = $this->compiler->compileTag(i,array_merge(array('object_methode'=>m),a));} + // tag with modifier and optional Smarty2 style attributes +smartytag(res) ::= LDEL ID(i) modifier(m) modparameters(p) attributes(a) RDEL. { res = ''.$this->compiler->compileTag(i,a).'smarty->plugin_handler->loadSmartyPlugin(m[0],'modifier')) { + res .= "\$_smarty_tpl->smarty->plugin_handler->".m[0] . "(array(ob_get_clean()". p ."),'modifier');?>"; + } else { + if (m[0] == 'isset' || m[0] == 'empty' || is_callable(m[0])) { + if (!$this->template->security || $this->smarty->security_handler->isTrustedModifier(m[0], $this->compiler)) { + res .= m[0] . "(ob_get_clean()". p .");?>"; + } + } else { + $this->compiler->trigger_template_error ("unknown modifier \"" . m[0] . "\""); + } + } + } + // end of block tag {/....} +smartytag(res) ::= LDELSLASH ID(i) attributes(a) RDEL. { res = $this->compiler->compileTag(i.'close',a);} + // end of block object tag {/....} +smartytag(res) ::= LDELSLASH ID(i) PTR ID(m) RDEL. { res = $this->compiler->compileTag(i.'close',array('object_methode'=>m));} + // {if}, {elseif} and {while} tag +smartytag(res) ::= LDEL ID(i)SPACE ifexprs(ie) RDEL. { res = $this->compiler->compileTag(i,array('if condition'=>ie));} + // {for} tag +smartytag(res) ::= LDEL ID(i) SPACE statements(s) SEMICOLON ifexprs(ie) SEMICOLON DOLLAR varvar(v2) foraction(e2) RDEL. { res = $this->compiler->compileTag(i,array('start'=>s,'ifexp'=>ie,'varloop'=>v2,'loop'=>e2));} + foraction(res) ::= EQUAL expr(e). { res = '='.e;} + foraction(res) ::= INCDEC(e). { res = e;} + // {for $var in $array} tag +// replaced with next line because config vars could an array!! smartytag(res) ::= LDEL ID(i) SPACE DOLLAR varvar(v0) IN variable(v1) RDEL. { res = $this->compiler->compileTag(i,array('from'=>v1,'item'=>v0));} +smartytag(res) ::= LDEL ID(i) SPACE DOLLAR varvar(v0) IN value(v1) RDEL. { res = $this->compiler->compileTag(i,array('from'=>v1,'item'=>v0));} +smartytag(res) ::= LDEL ID(i) SPACE DOLLAR varvar(v0) IN array(a) RDEL. { res = $this->compiler->compileTag(i,array('from'=>a,'item'=>v0));} + +// +//Attributes of Smarty tags +// + // list of attributes +attributes(res) ::= attributes(a1) attribute(a2). { res = array_merge(a1,a2);} + // single attribute +attributes(res) ::= attribute(a). { res = a;} + // no attributes +attributes(res) ::= . { res = array();} + + // different formats of attribute +//attribute(res) ::= SPACE ID(v) EQUAL ID(i). { res = array(v=>'\''.i.'\'');} +attribute(res) ::= SPACE ID(v) EQUAL expr(e). { res = array(v=>e);} + +// +// statement +// +statements(res) ::= statement(s). { res = array(s);} +statements(res) ::= statements(s1) COMMA statement(s). { s1[]=s; res = s1;} + +statement(res) ::= DOLLAR varvar(v) EQUAL expr(e). { res = array('var' => v, 'value'=>e);} +//statement(res) ::= DOLLAR varvar(v) EQUAL ID(i). { res = array('var' => v, 'value'=>'\''.i.'\'');} + +// +// expressions +// + // simple expression +expr(res) ::= ID(i). { res = '\''.i.'\''; } +//expr(res) ::= UNQ_STR(s). { res = '\''.s.'\''; } +//expr(res) ::= ID(i). { res = i; } +expr(res) ::= exprs(e). {res = e;} +expr(res) ::= expr(e) modifier(m) modparameters(p). { + if ($this->smarty->plugin_handler->loadSmartyPlugin(m[0],'modifier')) { + res = "\$_smarty_tpl->smarty->plugin_handler->".m[0] . "(array(". e . p ."),'modifier')"; + } else { + if (m[0] == 'isset' || m[0] == 'empty' || is_callable(m[0])) { + if (!$this->template->security || $this->smarty->security_handler->isTrustedModifier(m[0], $this->compiler)) { + res = m[0] . "(". e . p .")"; + } + } else { + $this->compiler->trigger_template_error ("unknown modifier \"" . m[0] . "\""); + } + } + } +exprs(res) ::= array(a). {res = a;} + + // single value +exprs(res) ::= value(v). { res = v; } + // +/- value +exprs(res) ::= UNIMATH(m) value(v). { res = m.v; } + // arithmetic expression +exprs(res) ::= exprs(e) math(m) value(v). { res = e . m . v; } + // catenate +exprs(res) ::= exprs(e) ANDSYM value(v). { res = '('. e . ').(' . v. ')'; } + +// +// mathematical operators +// + // +,- +math(res) ::= UNIMATH(m). {res = m;} + // *,/,% +math(res) ::= MATH(m). {res = m;} + + + // value +value(res) ::= variable(v). { res = v; } + // config variable +value(res) ::= HATCH ID(i) HATCH. {res = '$_smarty_tpl->getConfigVariable(\''. i .'\')';} + // numeric +value(res) ::= NUMBER(n). { res = n; } + // boolean +value(res) ::= BOOLEAN(b). { res = b; } + // null +value(res) ::= NULL(n). { res = n; } + + // function call +value(res) ::= function(f). { res = f; } + // expression +value(res) ::= OPENP expr(e) CLOSEP. { res = "(". e .")"; } + + // singele quoted string +value(res) ::= SINGLEQUOTE text(t) SINGLEQUOTE. { res = "'".t."'"; } +value(res) ::= SINGLEQUOTE SINGLEQUOTE. { res = "''"; } + // double quoted string +value(res) ::= QUOTE doublequoted(s) QUOTE. { res = "'".str_replace('\"','"',s)."'"; } +//value(res) ::= QUOTE doublequoted(s) QUOTE. { res = "'".addcslashes(str_replace(array('\"'),array('"'),s),"'")."'"; } +//value(res) ::= QUOTE doublequoted(s) QUOTE. { res = "'".s."'"; var_dump(s);} +value(res) ::= QUOTE QUOTE. { res = "''"; } + + // static class methode call +value(res) ::= ID(c) DOUBLECOLON method(m). { res = c.'::'.m; } +value(res) ::= ID(c) DOUBLECOLON DOLLAR ID(f) OPENP params(p) CLOSEP. { $this->prefix_number++; $this->prefix_code[] = 'prefix_number.'=$_smarty_tpl->getVariable(\''. f .'\')->value;?>'; res = c.'::$_tmp'.$this->prefix_number.'('. p .')'; } + // static class methode call with object chainig +value(res) ::= ID(c) DOUBLECOLON method(m) objectchain(oc). { res = c.'::'.m.oc; } +value(res) ::= ID(c) DOUBLECOLON DOLLAR ID(f) OPENP params(p) CLOSEP objectchain(oc). { $this->prefix_number++; $this->prefix_code[] = 'prefix_number.'=$_smarty_tpl->getVariable(\''. f .'\')->value;?>'; res = c.'::$_tmp'.$this->prefix_number.'('. p .')'.oc; } + // static class constant +value(res) ::= ID(c) DOUBLECOLON ID(v). { res = c.'::'.v;} + // static class variables +value(res) ::= ID(c) DOUBLECOLON DOLLAR ID(v) arrayindex(a). { res = c.'::$'.v.a;} + // static class variables with object chain +value(res) ::= ID(c) DOUBLECOLON DOLLAR ID(v) arrayindex(a) objectchain(oc). { res = c.'::$'.v.a.oc;} + + +// +// variables +// + // simple Smarty variable (optional array) +variable(res) ::= DOLLAR varvar(v) arrayindex(a). { if (v == '\'smarty\'') { res = $this->compiler->compileTag(trim(v,"'"),a);} else { + res = '$_smarty_tpl->getVariable('. v .')->value'.a; $this->nocache=$this->template->getVariable(trim(v,"'"))->nocache;}} + // variable with property +variable(res) ::= DOLLAR varvar(v) AT ID(p). { res = '$_smarty_tpl->getVariable('. v .')->'.p; $this->nocache=$this->template->getVariable(trim(v,"'"))->nocache;} + // object +variable(res) ::= object(o). { res = o; } + // config variable +//variable(res) ::= HATCH ID(i) HATCH. {res = '$_smarty_tpl->getConfigVariable(\''. i .'\')';} + +// +// array index +// + // multiple array index +arrayindex(res) ::= arrayindex(a1) indexdef(a2). {res = a1.a2;} + // no array index +arrayindex ::= . {return;} + +// single index definition + // Smarty2 style index +indexdef(res) ::= DOT ID(i). { res = "['". i ."']";} +indexdef(res) ::= DOT exprs(e). { res = "[". e ."]";} + // section tag index +indexdef(res) ::= OPENB ID(i)CLOSEB. { res = '['.$this->compiler->compileTag('smarty','[\'section\'][\''.i.'\'][\'index\']').']';} + // PHP style index +indexdef(res) ::= OPENB exprs(e) CLOSEB. { res = "[". e ."]";} + +// +// variable variable names +// + // singel identifier element +varvar(res) ::= varvarele(v). {res = v;} + // sequence of identifier elements +varvar(res) ::= varvar(v1) varvarele(v2). {res = v1.'.'.v2;} + // fix sections of element +varvarele(res) ::= ID(s). {res = '\''.s.'\'';} + // variable sections of element +varvarele(res) ::= LDEL expr(e) RDEL. {res = '('.e.')';} + +// +// objects +// +object(res) ::= DOLLAR varvar(v) arrayindex(a) objectchain(oc). { res = '$_smarty_tpl->getVariable('. v .')->value'.a.oc; $this->nocache=$this->template->getVariable(trim(v,"'"))->nocache;} + // single element +objectchain(res) ::= objectelement(oe). {res = oe; } + // chain of elements +objectchain(res) ::= objectchain(oc) objectelement(oe). {res = oc.oe; } + // variable +objectelement(res)::= PTR ID(i) arrayindex(a). { res = '->'.i.a;} +//objectelement(res)::= PTR varvar(v) arrayindex(a). { res = '->'.v.a;} + // method +objectelement(res)::= PTR method(f). { res = '->'.f;} + + +// +// function +// +function(res) ::= ID(f) OPENP params(p) CLOSEP. {if (!$this->template->security || $this->smarty->security_handler->isTrustedPhpFunction(f, $this->compiler)) { + if (f == 'isset' || f == 'empty' || is_callable(f)) { + res = f . "(". p .")"; + } else { + $this->compiler->trigger_template_error ("unknown function \"" . f . "\""); + } + }} + +// +// method +// +method(res) ::= ID(f) OPENP params(p) CLOSEP. { res = f . "(". p .")";} + +// function/method parameter + // multiple parameters +params(res) ::= expr(e) COMMA params(p). { res = e.",".p;} + // single parameter +params(res) ::= expr(e). { res = e;} + // kein parameter +params ::= . { return;} + +// +// modifier +// +modifier(res) ::= VERT AT ID(m). { res = array(m,true);} +modifier(res) ::= VERT ID(m). { res = array(m,false);} + + +// +// modifier parameter +// + // multiple parameter +modparameters(res) ::= modparameters(mps) modparameter(mp). { res = mps.mp;} + // no parameter +modparameters ::= . {return;} + // parameter expression +modparameter(res) ::= COLON ID(mp). {res = ',\''.mp.'\'';} +modparameter(res) ::= COLON exprs(mp). {res = ','.mp;} + +// +// if expressions +// + // single if expression +ifexprs(res) ::= ifexpr(e). {res = e;} +ifexprs(res) ::= NOT ifexprs(e). {res = '!'.e;} +ifexprs(res) ::= OPENP ifexprs(e) CLOSEP. {res = '('.e.')';} + +// if expression + // simple expression +ifexpr(res) ::= expr(e). {res =e;} +ifexpr(res) ::= expr(e1) ifcond(c) expr(e2). {res = e1.c.e2;} +ifexpr(res) ::= ifexprs(e1) lop(o) ifexprs(e2). {res = e1.o.e2;} +ifexpr(res) ::= ifexprs(e1) ISDIVBY ifexprs(e2). {res = '!('.e1.' % '.e2.')';} +ifexpr(res) ::= ifexprs(e1) ISNOTDIVBY ifexprs(e2). {res = '('.e1.' % '.e2.')';} +ifexpr(res) ::= ifexprs(e1) ISEVEN. {res = '!(1 & '.e1.')';} +ifexpr(res) ::= ifexprs(e1) ISNOTEVEN. {res = '(1 & '.e1.')';} +ifexpr(res) ::= ifexprs(e1) ISEVENBY ifexprs(e2). {res = '!(1 & '.e1.' / '.e2.')';} +ifexpr(res) ::= ifexprs(e1) ISNOTEVENBY ifexprs(e2). {res = '(1 & '.e1.' / '.e2.')';} +ifexpr(res) ::= ifexprs(e1) ISODD. {res = '(1 & '.e1.')';} +ifexpr(res) ::= ifexprs(e1) ISNOTODD. {res = '!(1 & '.e1.')';} +ifexpr(res) ::= ifexprs(e1) ISODDBY ifexprs(e2). {res = '(1 & '.e1.' / '.e2.')';} +ifexpr(res) ::= ifexprs(e1) ISNOTODDBY ifexprs(e2). {res = '!(1 & '.e1.' / '.e2.')';} + +ifcond(res) ::= EQUALS. {res = '==';} +ifcond(res) ::= NOTEQUALS. {res = '!=';} +ifcond(res) ::= GREATERTHAN. {res = '>';} +ifcond(res) ::= LESSTHAN. {res = '<';} +ifcond(res) ::= GREATEREQUAL. {res = '>=';} +ifcond(res) ::= LESSEQUAL. {res = '<=';} +ifcond(res) ::= IDENTITY. {res = '===';} +ifcond(res) ::= NONEIDENTITY. {res = '!==';} + +lop(res) ::= LAND. {res = '&&';} +lop(res) ::= LOR. {res = '||';} + +// +// ARRAY element assignment +// +array(res) ::= OPENB arrayelements(a) CLOSEB. { res = 'array('.a.')';} +arrayelements(res) ::= arrayelement(a). { res = a; } +arrayelements(res) ::= arrayelements(a1) COMMA arrayelement(a). { res = a1.','.a; } +arrayelements ::= . { return; } +arrayelement(res) ::= expr(e). { res = e;} +arrayelement(res) ::= expr(e1) APTR expr(e2). { res = e1.'=>'.e2;} +arrayelement(res) ::= ID(i) APTR expr(e2). { res = '\''.i.'\'=>'.e2;} + +// +// double qouted strings +// +doublequoted(res) ::= doublequoted(o1) doublequotedcontent(o2). {res = o1.o2;} +doublequoted(res) ::= doublequotedcontent(o). {res = o;} +doublequotedcontent(res) ::= variable(v). {res = "'.".v.".'";} +doublequotedcontent(res) ::= BACKTICK variable(v) BACKTICK. {res = "'.".v.".'";} +doublequotedcontent(res) ::= LDEL expr(e) RDEL. {res = "'.(".e.").'";} +doublequotedcontent(res) ::= OTHER(o). {res = addcslashes(o,"'");} +//doublequotedcontent(res) ::= OTHER(o). {res = o;} +//doublequotedcontent(res) ::= text(t). {res = addcslashes(t,"'");} + +// +// text string +// +text(res) ::= text(t) textelement(e). {res = t.e;} +text(res) ::= textelement(e). {res = e;} +textelement(res) ::= OTHER(o). {res = o;} +textelement(res) ::= LDEL(o). {res = o;} diff --git a/libs/plugins/block.textformat.php b/libs/plugins/block.textformat.php new file mode 100644 index 00000000..e6d1bb8f --- /dev/null +++ b/libs/plugins/block.textformat.php @@ -0,0 +1,103 @@ + +* Name: textformat
+* Purpose: format text a certain way with preset styles +* or custom wrap/indent settings
+* +* @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat} + (Smarty online manual) +* @param array $params parameters +*
+* Params:   style: string (email)
+*            indent: integer (0)
+*            wrap: integer (80)
+*            wrap_char string ("\n")
+*            indent_char: string (" ")
+*            wrap_boundary: boolean (true)
+* 
+* @author Monte Ohrt +* @param string $content contents of the block +* @param object $smarty Smarty object +* @param boolean &$repeat repeat flag +* @param object $template template object +* @return string content re-formatted +*/ +function smarty_block_textformat($params, $content, $smarty, &$repeat, $template) +{ + if (is_null($content)) { + return; + } + + $style = null; + $indent = 0; + $indent_first = 0; + $indent_char = ' '; + $wrap = 80; + $wrap_char = "\n"; + $wrap_cut = false; + $assign = null; + + foreach ($params as $_key => $_val) { + switch ($_key) { + case 'style': + case 'indent_char': + case 'wrap_char': + case 'assign': + $$_key = (string)$_val; + break; + + case 'indent': + case 'indent_first': + case 'wrap': + $$_key = (int)$_val; + break; + + case 'wrap_cut': + $$_key = (bool)$_val; + break; + + default: + $smarty->trigger_error("textformat: unknown attribute '$_key'"); + } + } + + if ($style == 'email') { + $wrap = 72; + } + // split into paragraphs + $_paragraphs = preg_split('![\r\n][\r\n]!', $content); + $_output = ''; + + for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) { + if ($_paragraphs[$_x] == '') { + continue; + } + // convert mult. spaces & special chars to single space + $_paragraphs[$_x] = preg_replace(array('!\s+!', '!(^\s+)|(\s+$)!'), array(' ', ''), $_paragraphs[$_x]); + // indent first line + if ($indent_first > 0) { + $_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x]; + } + // wordwrap sentences + $_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut); + // indent lines + if ($indent > 0) { + $_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]); + } + } + $_output = implode($wrap_char . $wrap_char, $_paragraphs); + + return $assign ? $template->assign($assign, $_output) : $_output; +} + +?> diff --git a/libs/plugins/function.counter.php b/libs/plugins/function.counter.php new file mode 100644 index 00000000..1e5e457b --- /dev/null +++ b/libs/plugins/function.counter.php @@ -0,0 +1,78 @@ + + * Name: counter
+ * Purpose: print out a counter value + * @author Monte Ohrt + * @link http://smarty.php.net/manual/en/language.function.counter.php {counter} + * (Smarty online manual) + * @param array $params parameters + * @param object $smarty Smarty object + * @param object $template template object + * @return string|null + */ +function smarty_function_counter($params, $smarty, $template) +{ + + $name = (isset($params['name'])) ? $params['name'] : 'default'; + if (!isset($template->plugin_data['counter'][$name])) { + $template->plugin_data['counter'][$name] = array( + 'start'=>1, + 'skip'=>1, + 'direction'=>'up', + 'count'=>1 + ); + } + $counter = &$template->plugin_data['counter'][$name]; + + if (isset($params['start'])) { + $counter['start'] = $counter['count'] = (int)$params['start']; + } + + if (!empty($params['assign'])) { + $counter['assign'] = $params['assign']; + } + + if (isset($counter['assign'])) { + $template->assign($counter['assign'], $counter['count']); + } + + if (isset($params['print'])) { + $print = (bool)$params['print']; + } else { + $print = empty($counter['assign']); + } + + if ($print) { + $retval = $counter['count']; + } else { + $retval = null; + } + + if (isset($params['skip'])) { + $counter['skip'] = $params['skip']; + } + + if (isset($params['direction'])) { + $counter['direction'] = $params['direction']; + } + + if ($counter['direction'] == "down") + $counter['count'] -= $counter['skip']; + else + $counter['count'] += $counter['skip']; + + return $retval; + +} + +?> diff --git a/libs/plugins/function.cycle.php b/libs/plugins/function.cycle.php new file mode 100644 index 00000000..dedd6579 --- /dev/null +++ b/libs/plugins/function.cycle.php @@ -0,0 +1,97 @@ + + * Name: cycle
+ * Date: May 3, 2002
+ * Purpose: cycle through given values
+ * + * Examples:
+ *
+ * {cycle values="#eeeeee,#d0d0d0d"}
+ * {cycle name=row values="one,two,three" reset=true}
+ * {cycle name=row}
+ * 
+ * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle} + * (Smarty online manual) + * @author Monte Ohrt + * @author credit to Mark Priatel + * @author credit to Gerard + * @author credit to Jason Sweat + * @param array $params parameters + * Input: + * - name = name of cycle (optional) + * - values = comma separated list of values to cycle, + * or an array of values to cycle + * (this can be left out for subsequent calls) + * - reset = boolean - resets given var to true + * - print = boolean - print var or not. default is true + * - advance = boolean - whether or not to advance the cycle + * - delimiter = the value delimiter, default is "," + * - assign = boolean, assigns to template var instead of + * printed. + * @param object $smarty Smarty object + * @param object $template template object + * @return string|null + */ +function smarty_function_cycle($params, $smarty, $template) +{ + $name = (empty($params['name'])) ? 'default' : $params['name']; + $print = (isset($params['print'])) ? (bool)$params['print'] : true; + $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; + $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; + + if (!in_array('values', array_keys($params))) { + if(!isset($template->plugin_data['cycle'][$name]['values'])) { + throw new Exception ("cycle: missing 'values' parameter"); + return; + } + } else { + if(isset($template->plugin_data['cycle'][$name]['values']) + && $template->plugin_data['cycle'][$name]['values'] != $params['values'] ) { + $template->plugin_data['cycle'][$name]['index'] = 0; + } + $template->plugin_data['cycle'][$name]['values'] = $params['values']; + } + + $template->plugin_data['cycle'][$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ','; + + if(is_array($template->plugin_data['cycle'][$name]['values'])) { + $cycle_array = $template->plugin_data['cycle'][$name]['values']; + } else { + $cycle_array = explode($template->plugin_data['cycle'][$name]['delimiter'],$template->plugin_data['cycle'][$name]['values']); + } + + if(!isset($template->plugin_data['cycle'][$name]['index']) || $reset ) { + $template->plugin_data['cycle'][$name]['index'] = 0; + } + + if (isset($params['assign'])) { + $print = false; + $template->assign($params['assign'], $cycle_array[$template->plugin_data['cycle'][$name]['index']]); + } + + if($print) { + $retval = $cycle_array[$template->plugin_data['cycle'][$name]['index']]; + } else { + $retval = null; + } + + if($advance) { + if ( $template->plugin_data['cycle'][$name]['index'] >= count($cycle_array) -1 ) { + $template->plugin_data['cycle'][$name]['index'] = 0; + } else { + $template->plugin_data['cycle'][$name]['index']++; + } + } + + return $retval; +} +?> diff --git a/libs/plugins/function.fetch.php b/libs/plugins/function.fetch.php new file mode 100644 index 00000000..1bf0e75a --- /dev/null +++ b/libs/plugins/function.fetch.php @@ -0,0 +1,217 @@ + + * Name: fetch
+ * Purpose: fetch file, web or ftp data and display results + * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} + * (Smarty online manual) + * @author Monte Ohrt + * @param array $params parameters + * @param object $smarty Smarty object + * @param object $template template object + * @return string|null if the assign parameter is passed, Smarty assigns the + * result to a template variable + */ +function smarty_function_fetch($params, $smarty, $template) +{ + if (empty($params['file'])) { + throw new Exception ("[plugin] fetch parameter 'file' cannot be empty"); + return; + } + + $content = ''; + if ($template->security && !preg_match('!^(http|ftp)://!i', $params['file'])) { + if(!$smarty->security_handler->isTrustedResourceDir($params['file'])) { + return; + } + + // fetch the file + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + throw new Exception ('[plugin] fetch cannot read file \'' . $params['file'] . '\''); + return; + } + } else { + // not a local file + if(preg_match('!^http://!i',$params['file'])) { + // http fetch + if($uri_parts = parse_url($params['file'])) { + // set defaults + $host = $server_name = $uri_parts['host']; + $timeout = 30; + $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + $agent = "Smarty Template Engine ".$smarty->_version; + $referer = ""; + $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; + $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; + $_is_proxy = false; + if(empty($uri_parts['port'])) { + $port = 80; + } else { + $port = $uri_parts['port']; + } + if(!empty($uri_parts['user'])) { + $user = $uri_parts['user']; + } + if(!empty($uri_parts['pass'])) { + $pass = $uri_parts['pass']; + } + // loop through parameters, setup headers + foreach($params as $param_key => $param_value) { + switch($param_key) { + case "file": + case "assign": + case "assign_headers": + break; + case "user": + if(!empty($param_value)) { + $user = $param_value; + } + break; + case "pass": + if(!empty($param_value)) { + $pass = $param_value; + } + break; + case "accept": + if(!empty($param_value)) { + $accept = $param_value; + } + break; + case "header": + if(!empty($param_value)) { + if(!preg_match('![\w\d-]+: .+!',$param_value)) { + throw new Exception ("[plugin] invalid header format '".$param_value."'"); + return; + } else { + $extra_headers[] = $param_value; + } + } + break; + case "proxy_host": + if(!empty($param_value)) { + $proxy_host = $param_value; + } + break; + case "proxy_port": + if(!preg_match('!\D!', $param_value)) { + $proxy_port = (int) $param_value; + } else { + throw new Exception ("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + case "agent": + if(!empty($param_value)) { + $agent = $param_value; + } + break; + case "referer": + if(!empty($param_value)) { + $referer = $param_value; + } + break; + case "timeout": + if(!preg_match('!\D!', $param_value)) { + $timeout = (int) $param_value; + } else { + throw new Exception ("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + default: + throw new Exception ("[plugin] unrecognized attribute '".$param_key."'"); + return; + } + } + if(!empty($proxy_host) && !empty($proxy_port)) { + $_is_proxy = true; + $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); + } else { + $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); + } + + if(!$fp) { + throw new Exception ("[plugin] unable to fetch: $errstr ($errno)"); + return; + } else { + if($_is_proxy) { + fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); + } else { + fputs($fp, "GET $uri HTTP/1.0\r\n"); + } + if(!empty($host)) { + fputs($fp, "Host: $host\r\n"); + } + if(!empty($accept)) { + fputs($fp, "Accept: $accept\r\n"); + } + if(!empty($agent)) { + fputs($fp, "User-Agent: $agent\r\n"); + } + if(!empty($referer)) { + fputs($fp, "Referer: $referer\r\n"); + } + if(isset($extra_headers) && is_array($extra_headers)) { + foreach($extra_headers as $curr_header) { + fputs($fp, $curr_header."\r\n"); + } + } + if(!empty($user) && !empty($pass)) { + fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); + } + + fputs($fp, "\r\n"); + while(!feof($fp)) { + $content .= fgets($fp,4096); + } + fclose($fp); + $csplit = split("\r\n\r\n",$content,2); + + $content = $csplit[1]; + + if(!empty($params['assign_headers'])) { + $template->assign($params['assign_headers'],split("\r\n",$csplit[0])); + } + } + } else { + throw new Exception ("[plugin] unable to parse URL, check syntax"); + return; + } + } else { + // ftp fetch + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + throw new Exception ('[plugin] fetch cannot read file \'' . $params['file'] .'\''); + return; + } + } + + } + + + if (!empty($params['assign'])) { + $template->assign($params['assign'],$content); + } else { + return $content; + } +} + +?> diff --git a/libs/plugins/function.html_checkboxes.php b/libs/plugins/function.html_checkboxes.php new file mode 100644 index 00000000..7c1d165c --- /dev/null +++ b/libs/plugins/function.html_checkboxes.php @@ -0,0 +1,144 @@ + + * Type: function
+ * Name: html_checkboxes
+ * Date: 24.Feb.2003
+ * Purpose: Prints out a list of checkbox input types
+ * Examples: + *
+ * {html_checkboxes values=$ids output=$names}
+ * {html_checkboxes values=$ids name='box' separator='
' output=$names} + * {html_checkboxes values=$ids checked=$checked separator='
' output=$names} + *
+ * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} + * (Smarty online manual) + * @author Christopher Kvarme + * @author credits to Monte Ohrt + * @version 1.0 + * @param array $params parameters + * Input:
+ * - name (optional) - string default "checkbox" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie
or   + * - output (optional) - the output next to each checkbox + * - assign (optional) - assign the output as an array to this variable + * @param object $smarty Smarty object + * @param object $template template object + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_checkboxes($params, $smarty, $template) +{ + $smarty->loadPlugin('Smarty_shared_escape_special_chars'); + + $name = 'checkbox'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = $_val; + break; + + case 'labels': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'checked': + case 'selected': + $selected = array_map('strval', array_values((array)$_val)); + break; + + case 'checkboxes': + throw new Exception ('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + case 'assign': + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + throw new Exception ("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + settype($selected, 'array'); + $_html_result = array(); + + if (isset($options)) { + + foreach ($options as $_key=>$_val) + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + + + } else { + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + } + + } + + if(!empty($params['assign'])) { + $template->assign($params['assign'], $_html_result); + } else { + return implode("\n",$_html_result); + } + +} + +function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) { + $_output = ''; + if ($labels) $_output .= ''; + $_output .= $separator; + + return $_output; +} + +?> diff --git a/libs/plugins/function.html_image.php b/libs/plugins/function.html_image.php new file mode 100644 index 00000000..829da8db --- /dev/null +++ b/libs/plugins/function.html_image.php @@ -0,0 +1,138 @@ + +* Name: html_image
+* Date: Feb 24, 2003
+* Purpose: format HTML tags for the image
+* Examples: {html_image file="/images/masthead.gif"} +* Output: +* +* @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} + (Smarty online manual) +* @author Monte Ohrt +* @author credits to Duda +* @version 1.0 +* @param array $params parameters +* Input:
+* - file = file (and path) of image (required) +* - height = image height (optional, default actual height) +* - width = image width (optional, default actual width) +* - basedir = base directory for absolute paths, default +* is environment variable DOCUMENT_ROOT +* - path_prefix = prefix for path output (optional, default empty) +* @param object $smarty Smarty object +* @param object $template template object +* @return string +* @uses smarty_function_escape_special_chars() +*/ +function smarty_function_html_image($params, $smarty, $template) +{ + $smarty->loadPlugin('Smarty_shared_escape_special_chars'); + + $alt = ''; + $file = ''; + $height = ''; + $width = ''; + $extra = ''; + $prefix = ''; + $suffix = ''; + $path_prefix = ''; + $server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : ''; + foreach($params as $_key => $_val) { + switch ($_key) { + case 'file': + case 'height': + case 'width': + case 'dpi': + case 'path_prefix': + case 'basedir': + $$_key = $_val; + break; + + case 'alt': + if (!is_array($_val)) { + $$_key = smarty_function_escape_special_chars($_val); + } else { + throw new Exception ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + + case 'link': + case 'href': + $prefix = ''; + $suffix = ''; + break; + + default: + if (!is_array($_val)) { + $extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"'; + } else { + throw new Exception ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (empty($file)) { + throw new Exception ("html_image: missing 'file' parameter", E_USER_NOTICE); + return; + } + + if (substr($file, 0, 1) == '/') { + $_image_path = $basedir . $file; + } else { + $_image_path = $file; + } + + if (!isset($params['width']) || !isset($params['height'])) { + if (!$_image_data = @getimagesize($_image_path)) { + if (!file_exists($_image_path)) { + throw new Exception ("html_image: unable to find '$_image_path'", E_USER_NOTICE); + return; + } else if (!is_readable($_image_path)) { + throw new Exception ("html_image: unable to read '$_image_path'", E_USER_NOTICE); + return; + } else { + throw new Exception ("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE); + return; + } + } + if ($template->security) { + if (!$smarty->security_handler->isTrustedResourceDir($_image_path)) { + return; + } + } + + if (!isset($params['width'])) { + $width = $_image_data[0]; + } + if (!isset($params['height'])) { + $height = $_image_data[1]; + } + } + + if (isset($params['dpi'])) { + if (strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) { + $dpi_default = 72; + } else { + $dpi_default = 96; + } + $_resize = $dpi_default / $params['dpi']; + $width = round($width * $_resize); + $height = round($height * $_resize); + } + + return $prefix . '' . $alt . '' . $suffix; +} + +?> diff --git a/libs/plugins/function.html_options.php b/libs/plugins/function.html_options.php new file mode 100644 index 00000000..fda0dc00 --- /dev/null +++ b/libs/plugins/function.html_options.php @@ -0,0 +1,121 @@ + +* Name: html_options
+* Purpose: Prints the list of