{"id":17769811,"url":"https://github.com/weltling/parle","last_synced_at":"2025-07-06T23:39:29.589Z","repository":{"id":47145801,"uuid":"102218597","full_name":"weltling/parle","owner":"weltling","description":"Parser and lexer for PHP","archived":false,"fork":false,"pushed_at":"2023-08-02T14:37:06.000Z","size":604,"stargazers_count":90,"open_issues_count":2,"forks_count":10,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-02-27T03:11:17.729Z","etag":null,"topics":["lexer","parser","php"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/weltling.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-09-02T19:22:28.000Z","updated_at":"2025-01-13T03:17:48.000Z","dependencies_parsed_at":"2024-10-27T01:03:06.089Z","dependency_job_id":null,"html_url":"https://github.com/weltling/parle","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weltling%2Fparle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weltling%2Fparle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weltling%2Fparle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weltling%2Fparle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/weltling","download_url":"https://codeload.github.com/weltling/parle/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243742692,"owners_count":20340689,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lexer","parser","php"],"created_at":"2024-10-26T21:19:07.615Z","updated_at":"2025-03-15T14:30:52.648Z","avatar_url":"https://github.com/weltling.png","language":"C++","readme":"\nParle provides lexing and parsing facilities for PHP\n=============================================\nLexing and parsing is used widely in the PHP core and extensions. Usually such a functionality is packed into a piece of C/C++ and depends on tools like [flex](http://flex.sourceforge.net/), [re2c](http://re2c.org/), [Bison](http://www.gnu.org/software/bison/), [LEMON](http://www.hwaci.com/sw/lemon/) or similar. With Parle, it is possible to implement lexing and parsing in PHP while relying on features and principles of the parser/lexer generator tools for C/C++. The Lexer and Parser classes are there in the Parle namespace.\nThe implementation bases on the work of [Ben Hanson](http://www.benhanson.net/)\n\n- https://github.com/BenHanson/lexertl14\n- https://github.com/BenHanson/parsertl14\n\nThe lexer is based on the pattern matching similar to flex. The parser is LALR(1).\n\nSupported is PHP 7.4 and above. A [C++14](http://en.cppreference.com/w/cpp/compiler_support) capable compiler is required. As of version 0.7.3 parle can optionally be compiled with internal UTF-32 support, making it possible to use Unicode character classes in patterns.\n\nThe full extension documentation is available in the [PHP Manual](http://php.net/parle).\n\nInstallation\n============\n\nRead the [INSTALL.md](./INSTALL.md) documentation.\n\n\nExample tokenizing comma separated integer list\n============================================\n```php\n\nuse Parle\\Token;\nuse Parle\\Lexer;\nuse Parle\\LexerException;\n\n/* name =\u003e id */\n$token = array(\n        \"COMMA\" =\u003e 1,\n        \"CRLF\" =\u003e 2,\n        \"DECIMAL\" =\u003e 3,\n);\n/* id =\u003e name */\n$tokenIdToName = array_flip($token);\n\n$lex = new Lexer;\n$lex-\u003epush(\"[\\x2c]\", $token[\"COMMA\"]);\n$lex-\u003epush(\"[\\r][\\n]\", $token[\"CRLF\"]);\n$lex-\u003epush(\"[\\d]+\", $token[\"DECIMAL\"]);\n$lex-\u003ebuild();\n\n$in = \"0,1,2\\r\\n3,42,5\\r\\n6,77,8\\r\\n\";\n\n$lex-\u003econsume($in);\n\ndo {\n        $lex-\u003eadvance();\n        $tok = $lex-\u003egetToken();\n\n        if (Token::UNKNOWN == $tok-\u003eid) {\n                throw new LexerException(\"Unknown token '{$tok-\u003evalue}' at offset {$lex-\u003emarker}.\");\n        }\n\n        echo \"TOKEN: \", $tokenIdToName[$tok-\u003eid], PHP_EOL;\n} while (Token::EOI != $tok-\u003eid);\n\n```\n\n\nExample parsing comma separated number list\n===========================\n```php\n\nuse Parle\\Lexer;\nuse Parle\\Parser;\nuse Parle\\ParserException;\n\n$p = new Parser;\n$p-\u003etoken(\"CRLF\");\n$p-\u003etoken(\"COMMA\");\n$p-\u003etoken(\"INTEGER\");\n$p-\u003etoken(\"'\\\"'\");\n$p-\u003epush(\"START\", \"RECORDS\");\n$prod_record_0 = $p-\u003epush(\"RECORDS\", \"RECORD CRLF\");\n$prod_record_1 = $p-\u003epush(\"RECORDS\", \"RECORDS RECORD CRLF\");\n$prod_int_0 = $p-\u003epush(\"RECORD\", \"INTEGER\");\n$prod_int_1 = $p-\u003epush(\"RECORD\", \"RECORD COMMA INTEGER\");\n$p-\u003epush(\"DECIMAL\", \"INTEGER COMMA INTEGER\"); /* Production index unused. */\n$prod_dec_0 = $p-\u003epush(\"RECORD\", \"'\\\"' DECIMAL '\\\"'\");\n$prod_dec_1 = $p-\u003epush(\"RECORD\", \"RECORD COMMA '\\\"' DECIMAL '\\\"'\");\n$p-\u003ebuild();\n\n$lex = new Lexer;\n$lex-\u003epush(\"[\\x2c]\", $p-\u003etokenId(\"COMMA\"));\n$lex-\u003epush(\"[\\r][\\n]\", $p-\u003etokenId(\"CRLF\"));\n$lex-\u003epush(\"[\\d]+\", $p-\u003etokenId(\"INTEGER\"));\n$lex-\u003epush(\"[\\x22]\", $p-\u003etokenId(\"'\\\"'\"));\n$lex-\u003ebuild();\n\n/* Specifically using comma as both list separator and as a decimal mark. */\n$in = \"000,111,222\\r\\n\\\"333,3\\\",444,555\\r\\n666,777,\\\"888,8\\\"\\r\\n\";\n\n$p-\u003econsume($in, $lex);\n\ndo {\n\tswitch ($p-\u003eaction) {\n\t\tcase Parser::ACTION_ERROR:\n\t\t\t$err = $p-\u003eerrorInfo();\n\t\t\tif (Parser::ERROR_UNKNOWN_TOKEN == $err-\u003eid) {\n\t\t\t\t$tok = $err-\u003etoken;\n\t\t\t\t$msg = \"Unknown token '{$tok-\u003evalue}' at offset {$err-\u003eposition}\";\n\t\t\t} else if (Parser::ERROR_NON_ASSOCIATIVE == $err-\u003eid) {\n\t\t\t\t$tok = $err-\u003etoken;\n\t\t\t\t$msg = \"Token '{$tok-\u003eid}' at offset {$lex-\u003emarker} is not associative\";\n\t\t\t} else if (Parser::ERROR_SYNTAX == $err-\u003eid) {\n\t\t\t\t$tok = $err-\u003etoken;\n\t\t\t\t$msg = \"Syntax error at offset {$lex-\u003emarker}\";\n\t\t\t} else {\n\t\t\t\t$msg = \"Parse error\";\n\t\t\t}\n\t\t\tthrow new ParserException($msg);\n\t\t\tbreak;\n\t\tcase Parser::ACTION_SHIFT:\n\t\tcase Parser::ACTION_GOTO:\n\t\tcase Parser::ACTION_ACCEPT:\n\t\t\tcontinue;\n\t\t\tbreak;\n\t\tcase Parser::ACTION_REDUCE:\n\t\t\tswitch ($p-\u003ereduceId) {\n\t\t\t\tcase $prod_int_0:\n\t\t\t\t\t/* INTEGER */\n\t\t\t\t\techo $p-\u003esigil(), PHP_EOL;\n\t\t\t\t\tbreak;\n\t\t\t\tcase $prod_int_1:\n\t\t\t\t\t/* RECORD COMMA INTEGER */\n\t\t\t\t\techo $p-\u003esigil(2), PHP_EOL;\n\t\t\t\t\tbreak;\n\t\t\t\tcase $prod_dec_0:\n\t\t\t\t\t/* '\\\"' DECIMAL '\\\"' */\n\t\t\t\t\techo $p-\u003esigil(1), PHP_EOL;\n\t\t\t\t\tbreak;\n\t\t\t\tcase $prod_dec_1:\n\t\t\t\t\t/* RECORD COMMA '\\\"' DECIMAL '\\\"' */\n\t\t\t\t\techo $p-\u003esigil(3), PHP_EOL;\n\t\t\t\t\tbreak;\n\t\t\t\tcase $prod_record_0:\n\t\t\t\tcase $prod_record_1:\n\t\t\t\t\techo \"=====\", PHP_EOL;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\t$p-\u003eadvance();\n} while (Parser::ACTION_ACCEPT != $p-\u003eaction);\n\n```\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweltling%2Fparle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fweltling%2Fparle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweltling%2Fparle/lists"}