{"id":50988351,"url":"https://github.com/cantrepro/cparse","last_synced_at":"2026-07-07T22:00:51.274Z","repository":{"id":63178543,"uuid":"564014607","full_name":"cantrepro/cparse","owner":"cantrepro","description":"cparse is an LR(1) and LALR(1) parser generator","archived":false,"fork":false,"pushed_at":"2026-06-13T09:17:28.000Z","size":98,"stargazers_count":66,"open_issues_count":2,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-07-05T11:21:12.066Z","etag":null,"topics":["c","compiler","compiler-construction","compiler-frontend","compilers","lalr","lalr-parser","lalr-parser-generator","lalr1","lr1","lr1-parser","parser","parser-combinator","parser-combinators","parser-framework","parser-generator","parser-library","parsing"],"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/cantrepro.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-11-09T20:10:43.000Z","updated_at":"2026-06-17T22:09:46.000Z","dependencies_parsed_at":"2025-08-13T06:41:50.190Z","dependency_job_id":"a45c3338-55ed-4a14-a2a5-96927ca2f846","html_url":"https://github.com/cantrepro/cparse","commit_stats":null,"previous_names":["h2337/cparse","hikmat2337/cparse","jafarlihi/cparse","cantrepro/cparse"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cantrepro/cparse","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantrepro%2Fcparse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantrepro%2Fcparse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantrepro%2Fcparse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantrepro%2Fcparse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cantrepro","download_url":"https://codeload.github.com/cantrepro/cparse/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantrepro%2Fcparse/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35243953,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"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":["c","compiler","compiler-construction","compiler-frontend","compilers","lalr","lalr-parser","lalr-parser-generator","lalr1","lr1","lr1-parser","parser","parser-combinator","parser-combinators","parser-framework","parser-generator","parser-library","parsing"],"created_at":"2026-06-19T23:00:32.324Z","updated_at":"2026-07-07T22:00:51.269Z","avatar_url":"https://github.com/cantrepro.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"\u003cimg align=\"right\" src=\"https://raw.githubusercontent.com/h2337/cparse/refs/heads/master/logo.svg\"\u003e\n\n# cparse\n\n`cparse` is an LR(1) and LALR(1) parser generator for C. It consumes a grammar written in an intuitive textual format and, together with the [`clex`](https://github.com/h2337/clex) lexer generator, lets you build parsers that can both validate and produce parse trees for input programs.\n\n## Highlights\n\n- Modernised LR(1) and LALR(1) construction written in portable C11.\n- Predictable performance via dynamic data structures instead of fixed-size arrays.\n- Index-based action/goto tables keyed by terminal/nonterminal IDs for O(1)\n  parse-time table lookups.\n- First/Follow set computation with useful diagnostics for malformed grammars.\n- Structured LR conflict diagnostics with state details, relevant items, and\n  competing actions.\n- Typed runtime status codes plus structured parser errors (position, expected\n  terminals, offending lexeme).\n- Parse trees carry source spans (byte offset + line/column) through terminal\n  and nonterminal nodes.\n- Ships with a tiny test suite (`make test`) and a static library build (`libcparse.a`).\n\n## Getting Started\n\n```bash\ngit clone https://github.com/h2337/cparse.git\ncd cparse\ngit submodule update --init --recursive\nmake test   # builds libcparse.a, the test binary, and runs the tests\n```\n\nThis project depends only on a C11 compiler. The bundled `clex` submodule is used for lexical analysis in the examples and tests.\n\n## Quick Example\n\n```c\n#include \"cparse.h\"\n#include \"clex/clex.h\"\n\n// Token kinds supplied to clex\nenum {\n  TOK_RETURN,\n  TOK_IDENTIFIER,\n  TOK_SEMICOLON,\n};\n\nstatic const char *token_names[] = {\n  [TOK_RETURN] = \"RETURN\",\n  [TOK_IDENTIFIER] = \"IDENTIFIER\",\n  [TOK_SEMICOLON] = \"SEMICOL\",\n};\n\nint main(void) {\n  clexLexer *lexer = clexInit();\n  if (clexRegisterKind(lexer, \"return\", TOK_RETURN) != CLEX_STATUS_OK ||\n      clexRegisterKind(lexer, \"[a-zA-Z_]([a-zA-Z_]|[0-9])*\", TOK_IDENTIFIER) !=\n          CLEX_STATUS_OK ||\n      clexRegisterKind(lexer, \";\", TOK_SEMICOLON) != CLEX_STATUS_OK) {\n    return 1;\n  }\n\n  const char *grammar_src =\n      \"S -\u003e A IDENTIFIER SEMICOL\\n\"\n      \"A -\u003e RETURN\";\n\n  Grammar *grammar = cparseGrammar(grammar_src);\n  LALR1Parser *parser =\n      cparseCreateLALR1Parser(grammar, lexer, token_names,\n                              sizeof(token_names) / sizeof(token_names[0]));\n\n  if (cparseAccept(parser, \"return answer;\") == CPARSE_STATUS_OK) {\n    ParseTreeNode *root = NULL;\n    if (cparse(parser, \"return answer;\", \u0026root) == CPARSE_STATUS_OK) {\n      /* ... consume parse tree ... */\n    }\n    cparseFreeParseTree(root);\n  } else {\n    const cparseError *err = cparseGetLastError(parser);\n    /* inspect err-\u003eposition, err-\u003eexpected_tokens, err-\u003eoffending_lexeme */\n  }\n\n  cparseFreeParser(parser);\n  cparseFreeGrammar(grammar);\n  clexLexerDestroy(lexer);\n  return 0;\n}\n```\n\n## Runtime API\n\n| Function | Description |\n|----------|-------------|\n| `Grammar *cparseGrammar(const char *grammar_source)` | Parse a grammar description into an internal representation. |\n| `LR1Parser *cparseCreateLR1Parser(Grammar *, clexLexer *, const char *const *token_names, size_t token_name_count)` | Build an LR(1) parser (the lexer remains owned by the caller). |\n| `LALR1Parser *cparseCreateLALR1Parser(Grammar *, clexLexer *, const char *const *token_names, size_t token_name_count)` | Build an LALR(1) parser by merging LR(1) states (caller retains lexer ownership). |\n| `cparseStatus cparseAccept(LR1Parser *, const char *input)` | Validate input. Returns `CPARSE_STATUS_OK` on success. |\n| `cparseStatus cparse(LR1Parser *, const char *input, ParseTreeNode **out_tree)` | Parse input and write the tree to `out_tree` on success. |\n| `const cparseError *cparseGetLastError(const LR1Parser *)` | Retrieve structured parser error details after a non-OK status. |\n| `void cparseFreeParseTree(ParseTreeNode *)` | Recursively release a parse tree allocated by `cparse`. |\n| `void cparseFreeParser(LR1Parser *)` | Release parser state (works for LALR parsers as well). |\n| `void cparseFreeGrammar(Grammar *)` | Release grammar data structures. |\n\nA parse tree node stores:\n- the grammar symbol in `value`\n- the matched token (for terminals) in `token` (including source span)\n- an aggregate source span for the node in `span`\n- child nodes in `children`\n\n## Building\n\n- `make` or `make tests` builds `libcparse.a`, the supporting objects, and the `tests` binary.\n- `make test` runs the regression tests.\n- `make examples` builds the sample programs under `examples/`.\n- `make clean` removes build artefacts.\n\nYou can link `libcparse.a` into your own project together with `clex/clex.o` and `clex/fa.o`, or embed the sources directly.\n\n## Examples\n\nThe `examples/` directory contains small, self-contained programs that exercise the library. After running `make examples` you can try the expression parser:\n\n```bash\n./examples/expr_parser \"8 + 5 * 2\"\n```\n\nThe example registers a handful of tokens, builds an LALR(1) grammar for arithmetic expressions, validates the input, and prints the resulting parse tree.\n\n## Grammar Format\n\nEach line describes a production:\n\n```\nNonTerminal -\u003e alternative1 | alternative2 | ...\n```\n\n- Tokens are whitespace separated.\n- Use `epsilon` to denote an empty production.\n- Lines beginning with `#` are treated as comments.\n\nFor example:\n\n```\nS -\u003e A IDENTIFIER SEMICOL\nA -\u003e RETURN | epsilon\n```\n\n## Development Notes\n\n- The implementation avoids fixed limits and lazy `strtok()` parsing, making it suitable for larger grammars.\n- First and Follow sets are computed iteratively; unexpected productions emit diagnostics on `stderr`.\n- LR conflicts print structured diagnostics to `stderr` (state, terminal,\n  existing/incoming action, and relevant LR items) to shorten grammar-debug\n  loops.\n- The repository includes a tiny test harness in `tests.c`. Extend it with grammar-specific checks as needed.\n- Parsers borrow the `clexLexer` you pass; create it up front, register token kinds, and destroy it once you are done with parsing.\n\n## License\n\nDistributed under the terms of the MIT License. See [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcantrepro%2Fcparse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcantrepro%2Fcparse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcantrepro%2Fcparse/lists"}