{"id":32637352,"url":"https://github.com/foolnotion/pratt-parser-calculator","last_synced_at":"2025-10-31T01:56:23.263Z","repository":{"id":71450954,"uuid":"337496042","full_name":"foolnotion/pratt-parser-calculator","owner":"foolnotion","description":"Pratt operator precedence parser and expression calculator","archived":false,"fork":false,"pushed_at":"2024-06-01T12:53:44.000Z","size":159,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-06-01T14:28:24.520Z","etag":null,"topics":["cpp","cpp17","expression-evaluator","expression-parser","pratt-parser","precedence-parser"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/foolnotion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2021-02-09T18:18:23.000Z","updated_at":"2024-06-01T12:53:47.000Z","dependencies_parsed_at":"2024-04-13T00:26:53.704Z","dependency_job_id":"f4cae7e5-8a78-4033-a0dd-1c75d0096524","html_url":"https://github.com/foolnotion/pratt-parser-calculator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/foolnotion/pratt-parser-calculator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolnotion%2Fpratt-parser-calculator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolnotion%2Fpratt-parser-calculator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolnotion%2Fpratt-parser-calculator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolnotion%2Fpratt-parser-calculator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foolnotion","download_url":"https://codeload.github.com/foolnotion/pratt-parser-calculator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolnotion%2Fpratt-parser-calculator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281914557,"owners_count":26583083,"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","status":"online","status_checked_at":"2025-10-30T02:00:06.501Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["cpp","cpp17","expression-evaluator","expression-parser","pratt-parser","precedence-parser"],"created_at":"2025-10-31T01:56:20.474Z","updated_at":"2025-10-31T01:56:23.253Z","avatar_url":"https://github.com/foolnotion.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pratt parser and calculator\n\n[![Build Status](https://travis-ci.com/foolnotion/pratt-parser-calculator.svg?branch=main)](https://travis-ci.com/foolnotion/pratt-parser-calculator)\n\nThis is a simple operator precedence parser following the algorithm described by Pratt [[wikipedia](https://en.wikipedia.org/wiki/Operator-precedence_parser#cite_note-3)].\n\nIt supports a rather limited mathematical grammar but should be easily extensible. Its main distinctive feature is a modular design, which allows the user to supply the basic blocks for the parser to build the desired data structure (e.g., AST-like structures, S-expressions). This is done with the help of three functors:\n\n- NUD (null denotation): define the operation applied to a token when the _left_ expression is null (e.g. negation) returning a `value_t`\n- LED( left denotation): define the operation applied to a token when the _left_ expression exists (e.g. addition) returning a `value_t`\n- CONV (convert): define the conversion from a basic value (e.g. a number parsed from the input string) into a `value_t`\n\nThe `value_t` type represents the token payload and is defined using a template parameter.\n\nFor example, to convert an infix string into an S-expression, one would implement:\n\n```cpp\nstruct nud {\n    using token_t = token\u003cstd::string\u003e;\n    using value_t = typename token_t::value_t;\n\n    template \u003ctypename Parser\u003e\n    value_t operator()(Parser\u0026 parser, token_kind tok, token_t const\u0026 left)\n    {\n        auto bp = token_precedence[tok]; // binding power\n\n        switch (tok) {\n        case token_kind::constant: {\n            return left.value;\n        }\n\n        case token_kind::variable: {\n            return left.name;\n        }\n\n        case token_kind::sub:\n        case token_kind::exp:\n        case token_kind::log:\n        case token_kind::sin:\n        case token_kind::cos:\n        case token_kind::tan:\n        case token_kind::sqrt:\n        case token_kind::cbrt:\n        case token_kind::square: {\n            return \"(\" + std::string(pratt::token_name[tok]) + \" \" + parser.parse_bp(bp, token_kind::eof).value + \")\";\n        }\n\n        case token_kind::lparen: {\n            return parser.parse_bp(bp, token_kind::rparen).value;\n        }\n\n        default: {\n            throw std::runtime_error(\"nud: unsupported token \" + std::string(token_name[static_cast\u003cint\u003e(tok)]));\n        };\n        }\n    }\n};\n\nstruct led {\n    using token_t = token\u003cstd::string\u003e;\n    using value_t = token_t::value_t;\n\n    template \u003ctypename Parser\u003e\n    value_t operator()(Parser\u0026 parser, token_kind tok, token_t const\u0026 left, token_t const\u0026 right)\n    {\n        auto lhs = left.value;\n        auto rhs = right.value;\n\n        switch (tok) {\n        case token_kind::add:\n        case token_kind::sub:\n        case token_kind::mul:\n        case token_kind::div:\n        case token_kind::pow:\n            return \"(\" + std::string(pratt::token_name[tok]) + \" \" + lhs + \" \" + rhs + \")\";\n\n        default:\n            throw std::runtime_error(\"led: unsupported token \" + std::string(token_name[static_cast\u003cint\u003e(tok)]));\n        };\n    }\n};\n\nstruct conv {\n    auto operator()(double v) const noexcept -\u003e std::string \n    {\n        std::ostringstream buf;\n        buf \u003c\u003c v;\n        return buf.str();\n    }\n};\n```\n\nand then use the parser like this:\n```cpp\nusing NUD  = pratt::sexpr::nud;\nusing LED  = pratt::sexpr::led;\nusing CONV = pratt::sexpr::conv;\npratt::parser\u003cNUD, LED, CONV\u003e p(input, {});\nauto result = p.parse();\n```\n\nExamples of an expression calculator and an infix to prefix converter are found in the [src](https://github.com/foolnotion/pratt-parser-calculator/tree/main/src) folder. Note that the lexer is quite basic at the moment, so all symbols must be separate by spaces.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoolnotion%2Fpratt-parser-calculator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoolnotion%2Fpratt-parser-calculator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoolnotion%2Fpratt-parser-calculator/lists"}