{"id":33237125,"url":"https://github.com/mrossini-ethz/parseq","last_synced_at":"2026-01-22T19:32:44.471Z","repository":{"id":74666378,"uuid":"65886722","full_name":"mrossini-ethz/parseq","owner":"mrossini-ethz","description":"Parseq is a library for Common Lisp used for parsing sequences such as strings and lists using parsing expression grammars.","archived":false,"fork":false,"pushed_at":"2023-08-13T20:14:33.000Z","size":349,"stargazers_count":27,"open_issues_count":3,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-06-21T18:12:48.647Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrossini-ethz.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","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}},"created_at":"2016-08-17T07:40:33.000Z","updated_at":"2024-05-28T16:19:57.000Z","dependencies_parsed_at":"2024-01-05T22:24:25.813Z","dependency_job_id":null,"html_url":"https://github.com/mrossini-ethz/parseq","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/mrossini-ethz/parseq","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrossini-ethz%2Fparseq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrossini-ethz%2Fparseq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrossini-ethz%2Fparseq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrossini-ethz%2Fparseq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrossini-ethz","download_url":"https://codeload.github.com/mrossini-ethz/parseq/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrossini-ethz%2Fparseq/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27758422,"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-12-16T02:00:10.477Z","response_time":57,"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":[],"created_at":"2025-11-16T19:00:28.322Z","updated_at":"2025-12-16T02:01:56.438Z","avatar_url":"https://github.com/mrossini-ethz.png","language":"Common Lisp","readme":"# PARSEQ\n\n## Description\nParseq (pronounced [parsec](https://en.wikipedia.org/wiki/Parsec)) is a parsing library for common lisp.\nIt can be used for parsing lisp's sequences types: strings, vectors (e.g. binary data) and lists.\nFurthermore, parseq is able to parse nested structures such as trees (e.g. lists of lists, lists of vectors, vectors of strings).\n\nParseq uses [Bryan Ford's](https://bford.info/) [parsing expression grammars](https://en.wikipedia.org/wiki/Parsing_expression_grammar) ([PEG](https://bford.info/pub/lang/peg/))\nthat can be defined through a simple interface.\nExtensions to the standard parsing expressions are available.\nParsing expressions can be parameterised and made context aware.\nAdditionally, the definition of each parsing expression allows the arbitrary transformation of the parsing tree.\n\nThe library is inspired by [Esrap](https://nikodemus.github.io/esrap/) and uses a very similar interface.\nNo code is shared between the two projects, however.\nThe features of Esrap are are mostly included in parseq and complemented with additional, orthogonal features.\nAny resemblance to [esrap-liquid](https://github.com/mabragor/esrap-liquid) is merely coincidental.\n\nThe library is still under development.\nThis means that some features are not yet implemented and that the interface and behaviour may change in the future.\nSee the warnings [below](#warnings).\n\n### Features\nParseq provides the following features:\n\n * Parses strings, vectors (e.g. binary data) and lists\n * Allows parsing of sequences within sequences (e.g. trees, strings within lists, ...)\n * Simple interface, very similar to [Esrap](https://nikodemus.github.io/esrap/)\n * Provides many specific and non-specific terminal symbols\n * Implements the standard [PEG expressions](https://bford.info/pub/lang/peg/) as well as useful extensions\n * [Packrat parsing](https://github.com/mrossini-ethz/parseq/wiki/Packrat-Parsing) can be enabled for individual PEG rules\n * Parsing expression rules are compiled\n * Parse tree transformations can be defined together with each PEG rule\n * Grammars can be made context aware:\n   * Run parse results of a PEG rule through lisp code to influence parsing success\n   * Share data between parse rules\n * Parsing rules can be parameterised\n * Uses separate namespace(s) for parse rules\n * Tracing of grammar rules\n * Meaningful parse error messages\n\n## Basic usage\n\nFirst, define a set of grammar rules:\n```\n(defrule foo () \"foo\")\n(defrule bar () \"bar\")\n(defrule foobar () (and foo bar))\n```\nThe first argument to `(defrule ...)` is the nonterminal symbol that will represent the rule.\nThese symbols use a different namespace from everything else.\nThe second argument is a list of parameters that the rule takes (none in this example).\nThe third argument specifies the definition of the nonterminal symbol.\nAfter the third argument, multiple [processing options](#processing-options) can be listed.\n\nIn this example, the nonterminal `foo` requires the parsing of the string `\"foo\"`.\nThe rule `foobar` combines the two rules `foo` and `bar` to match the string `\"foobar\"`, the list `(\"foo\" \"bar\")` or the vector `#(\"foo\" \"bar\")`.\nThe above example could alternatively be stated as\n```\n(defrule foobar () (and \"foo\" \"bar\"))\n```\nthus not requiring the rules `foo` and `bar`.\n\nParsing is initiated by calling\n```\n(parseq 'foobar sequence)\n```\nwhich will return the list `(\"foo\" \"bar\")` as well as `T` if `sequence` is one of `\"foobar\"`, `(\"foo\" \"bar\")` and `#(\"foo\" \"bar\")`.\nIf parsing is not successful, `NIL` is returned.\nThe first argument to `(parseq ...)` is a nonterminal symbol defined through `defrule`.\nNote that the symbol must be quoted.\nThe second argument is the sequence that should be parsed.\nThere are optional keyword parameters to `(parseq ...)`:\n\n  * `:start`: the position in the sequence at which parsing should start\n  * `:end`: the position in the sequence at which parsing should stop\n  * `:junk-allowed`: when set to `t`, will avoid a parsing error, if the end is not reached\n  * `:parse-error`: when set to `t`, a parsing error will signal a error\n\nThis concludes the basic usage of the library. Almost everything is done through `defrule` and `parseq`.\nThere are some extra arguments, however, that are explained below.\n\n## Installation\nParseq is available with [quicklisp](https://www.quicklisp.org/beta/).\nYou can run\n```\n(ql:quickload :parseq)\n```\nin the REPL to download, install and load it.\nTo access the symbols from the package without the `parseq:` prefix you can type\n```\n(use-package :parseq)\n```\n\nAlternatively, the system is can be downloaded/cloned from [GitHub](https://github.com/mrossini-ethz/parseq).\nThe `master` branch will always point to the latest release.\nIf the system can be found through [ASDF](https://common-lisp.net/project/asdf/), the system can be loaded by typing the following expressions in the REPL:\n```\n(require :asdf)                ; unless already loaded\n(asdf:load-system :parseq)\n(use-package :parseq)          ; optional\n```\n\n## Terminals\nTerminals (tokens) are the objects that actually appear in the parsed sequence.\nThe following types are item classes:\n\n * `symbol` matches any lisp symbol\n * `keyword` matches any lisp keyword\n * `form` matches literally everything\n * `char` matches any character\n * `stdchar` matches any standard character, see `(standard-char-p ...)`\n * `alpha` matches any alphabetic standard character\n * `digit` matches any numeric standard character\n * `alphanumeric` matches any alphanumeric standard character\n * `byte` matches any unsigned byte\n * `number` matches any number\n * `integer` matches any integer\n * `atom` matches any atom\n * `list` matches any list\n * `cons` matches any cons\n * `vector` matches any vector\n * `string` matches any string\n * `t` matches anything not `nil`\n * `nil` matches `nil` or an empty list\n\nLiteral values can be specified to match specific items or subsequences in the sequence being parsed:\n\n * `'foo` matches the symbol `foo`\n * `#\\f` matches the character 'f'\n * `\"foo\"` matches the subsequence \"foo\" in a string or the item `\"foo\"` in a list or vector\n * `#(1 2 3)` matches the the subsequence `#(1 2 3)` in a vector or the item `#(1 2 3)` in a list\n * `5` matches the number 5\n\nTerminal expressions allow for mor elaborate specifications:\n\n * `(char \"a-zA-D7-9.,;\u003c=\u003e-\")` matches any character from the characters or character ranges in the\n   given string\n\nMore terminals may be available in later versions of parseq.\n\n## Nonterminals\nNonterminal symbols represent parsing expressions that consist of terminals and/or other nonterminals.\nThey can be defined using the `defrule` macro.\n\n## Standard expressions\nThese are the standard combinations of a parsing expression grammar.\n\n### Sequence\n```\n(and subexpression ...)\n```\nThe expression succeeds for a sequence if all subexpressions succeed in the given order.\nIt produces a list of the subexpression results.\nOn success, the amount of input consumed is determined by the subexpressions.\n\n### Ordered choice\n```\n(or subexpression ...)\n```\nThe subexpressions are tried in the given order and the result of the first one that succeeds is accepted.\nIt produces the result of the succeeding subexpression.\nThe amount of input consumed depends on the subexpression.\nIf none of the subexpressions match, the expression fails.\n\n### Greedy repetition\n```\n(* subexpression)\n```\nTries subexpression consecutively as many times as possible.\nThis expression always succeeds because zero repetitions are allowed.\nA list of the succeeding matches is returned.\nThe amount of input consumed depends on the subexpression and the number of times it matches.\n\n### Greedy positive repetition\n```\n(+ subexpression)\n```\nLike `(* subexpression)`, but at least one repetition is required.\n\n### Optional\n```\n(? subexpression)\n```\nConsumes and returns whatever subexpression consumes if it succeeds.\nThis operation is greedy which means that if the subexpression matches, it will consume the corresponding input.\nIf the subexpression fails, no input is consumed and `NIL` returned.\n\n### Followed-by predicate\n```\n(\u0026 subexpression)\n```\nSucceeds, if subexpression succeeds, but consumes no input.\nThe result of the subexpression is returned.\n\n### Not-followed-by predicate\n```\n(! subexpression)\n```\nSucceeds if subexpression _does not_ succeed.\nThis expression consumes no input.\nWhen successful, the next sequence item is returned.\n\n## Extended expressions\nFor convenience, the standard expressions are extended by the following combination methods:\n\n### Repetition\n```\n(rep 5 subexpression)\n(rep (0 5) subexpression)\n(rep (2 5) subexpression)\n(rep (2 NIL) subexpression)\n```\nSucceeds, if subexpression matches exactly 5 times, up to 5 times, between 2 and 5 times, or at least 2 times, respectively.\nReturns a list of the successful results.\n\nThe following abbreviations are allowed for repetitions:\n\n| Abbreviation | Long notation | Meaning             |\n| ------------ |:-------------:| ------------------- |\n| `3`          | `(3 3)`       | Exactly 3 times     |\n| `(3)`        | `(0 3)`       | Up to 3 times       |\n| `*`          | `(0 NIL)`     | Any number of times |\n| `+`          | `(1 NIL)`     | At least once       |\n| `?`          | `(0 1)`       | Zero times or once  |\n\n### Negation\n```\n(not subexpression)\n```\nSucceeds, if the subexpression _does not_ succeed.\nWhen that happens, the rule consumes _exactly one_ item in the sequence and returns it.\n\n### Sequence (unordered)\n```\n(and~ subexpression ...)\n```\nThe expression succeeds for a sequence if all subexpressions succeed, in any order.\nNote that the first subexpression in the list that matches a sequence item will be used.\nThe expression produces a list of the subexpression results (in the order in which they are listed in the rule definition) and consumes whatever the subexpressions consume.\n\nAn expression like `(and~ 'a 'b 'c 'd)` is actually equivalent to\n```\n(or (and 'a (or (and 'b (or (and 'c 'd) (and 'd 'c)))\n                (and 'c (or (and 'b 'd) (and 'd 'b)))\n                (and 'd (or (and 'b 'c) (and 'c 'b)))))\n    (and 'b (or (and 'a (or (and 'c 'd) (and 'd 'c)))\n                (and 'c (or (and 'a 'd) (and 'd 'a)))\n                (and 'd (or (and 'a 'c) (and 'c 'a)))))\n    (and 'c (or (and 'a (or (and 'b 'd) (and 'd 'b)))\n                (and 'b (or (and 'a 'd) (and 'd 'a)))\n                (and 'd (or (and 'a 'b) (and 'b 'a)))))\n    (and 'd (or (and 'a (or (and 'b 'c) (and 'c 'b)))\n                (and 'b (or (and 'a 'c) (and 'c 'a)))\n                (and 'c (or (and 'a 'b) (and 'b 'a))))))\n```\n\nThere is a variant of `and~` that is more flexible:\n```\n(and~~ (1 2 (1) (2 3) (4 nil) ...) subexpr-1 subexpr-2 subexpr-3 subexpr-4 subexpr-5 ...)\n```\nThe first argument to `and~~` specifies how may times each subexpression is allowed to be repeated.\n(See the `rep` operator above for a list of abbreviations.)\nIn this example, the first subexpression is required exactly once, the second one exactly twice, the third zero times or once, the fourth between 2 and 3 times and the fifth at least 4 times.\nDuring parsing, the prioritisation of the subexpressions that are still applicable is from left to right.\nThe result is a list of lists:\nThe list is ordered in the same way that subexpressions are given in the rule definition.\nThe *n*-th list within the list contains the results of the *n*-th subexpression in the order in which they are found in the parsed expression.\n\n### Nesting\n```\n(list subexpr-1 subexpr-2 ...)\n(string subexpr-1 subexpr-2 ...)\n(vector subexpr-1 subexpr-2 ...)\n```\nSucceeds if the current item in the sequence is a list/string/vector and its content matches the subexpressions in sequence.\nReturns a list enclosing the subexpression results.\n\n## Rule parameters\nOften, rules are similar to each other. For example\n```\n(defrule html-a () \"\u003ca\u003e\")\n(defrule html-b () \"\u003cb\u003e\")\n(defrule html-span () \u003cspan\u003e\")\n```\nshare the same pattern.\nIn parseq, this can be generalised with\n```\n(defrule html-tag (name) (and \"\u003c\" name \"\u003e\")\n```\nand used in parsing expressions as `(html-tag \"a\")` instead of having to define each rule separately.\nThe parameters can also be used in the processing options (see below).\nNote, however, that since the rule parameter is unknown at compile time, a runtime dispatch will need to be performed on the parameter type.\nIn the current implementation, only literal terminals and nonterminals are supported as part of the parsing expression.\nThis will likely change in the future.\n\nIt is possible to pass multiple paramters, keywords etc.\nThe full syntax of lambda lists is allowed.\n\n## Processing options\nThere are several options that can be specified for each rule definition.\nThe options can have several effects which are described below.\n\n### Transformation of parse results\nThe result from a parsing rule can be processed.\nExample:\n```\n(defrule abcde () (and (and 'a 'b) 'c (and 'd 'e)))\n(parseq 'abcde '(a b c d e))\n```\nwould normally return `((a b) c (d e))`.\nTo process the result, options can be specified in the call to `defrule`.\nFor example, if you want the resulting list flattened, the rule can be altered to\n```\n(defrule abcde () (and (and 'a 'b) 'c (and 'd 'e)) (:flatten))\n```\nsuch that parsing `(a b c d e)` yields `(a b c d e)` instead of `((a b) c (d e))`.\n\nYou can specify how processing of the parsing result is done through multiple options (see below).\nAdditional options (such as `:test`) do not affect the parse result, but have other effects.\nNote that the options are processed in sequence and the output of the previous option is input into the next option:\n```\n(defrule int+int^2 () (and number number) (:lambda (x y) (+ x y)) (:lambda (x) (expt x 2)))\n```\nThis would return `25` when parsing the list `(2 3)`.\n\n#### Constant result\n```\n(:constant 1)\n```\nThis options returns `1` (or whatever you specify) if the rule succeeds, irrespective of the parsing result.\n\n#### Lambda / Destructure\n```\n(:lambda (a b (c d) \u0026rest z) ...)\n(:destructure (a b (c d) \u0026rest z) ...)\n```\nDestructures the parsing result according to the specified lambda list and binds the given variables.\nThe following forms can be used to process the result in whatever way.\nThe new parsing result is given by what the last form returns.\nNote that `:lambda` and `:destructure` are actually synonyms.\n\n#### Choose\n```\n(:choose 0 2 '(3 1))\n```\nPicks items from the parsing result using the given indices and returns them.\nFor the parsing result `(15 #\\: 24 (#\\: 57))` (which might be the parsing result of a time string), the above processing option would return `(15 24 57)`.\nNon-existent items will result in `NIL` being returned for them.\n\n#### Function\n```\n(:function #'+)\n```\nThe parsing result is handed over to the function specified (here: `+`).\nNote that the lambda list of the given function has to match the items in the parsing result.\nThe new parsing result is whatever the function returns.\n\n#### Identity\n```\n(:identity t)\n```\nReturns the parsing result if the argument is not `NIL` and `NIL` otherwise.\n\n#### Flatten\n```\n(:flatten)\n```\nFlattens the parsing result, i.e. `(a (b c (d) e) (f g))` becomes `(a b c d e f g)`.\n\n#### String\n```\n(:string)\n```\nFlattens the parsing result and concatenates the list items to into a string, i.e. `(#\\a (\"bc\" (#\\d) 'e) (#\\f #x67))` becomes `\"abcdEfg\"`.\nThe items that can be concatenated are strings, characters, unsigned bytes and symbols.\n\n#### Vector\n```\n(:vector)\n```\nFlattens the parsing result and converts the resulting list into a vector, i.e. `(a (b c (d) e) (f g))` becomes `#(a b c d e f g)`.\n\n### Parse result testing\nThese options do not affect the parse result, but can make the rule fail depending on their input.\nIf a rule fails because of such an option, the processing of subsequent options is skipped.\n\n#### Test\n```\n(:test (x) (and (numberp x) (\u003e x 10)))\n```\nLike `:lambda` or `:destructure`, except that the return value of the function body is used as a predicate to determine whether the rule succeeds or not.\nTherefore, if the body of the test returns NIL, the rule fails.\nOtherwise, the unaltered result is returned.\nNote that the input to the test (function arguments) depends on the preceding processing options.\n\nIn the above example, the rule fails if the parse result is not an number greater than `10`.\n\nThe following rule matches any symbol except `baz`:\n```\n(defrule not-baz () symbol (:not (x) (eql x 'baz)))\n```\nThis is not possible with `(not 'baz)` because that would allow terminals other than symbols, e.g. `5` (which is not a symbol).\n\n#### Reverse test\n```\n(:not (x) (and (numberp x) (\u003e x 10)))\n```\nSame as `:test`, but logically inverted.\nIn this example, the rule fails _if_ the parse result is an number greater than `10`.\n\n### Variables\nRules can bind variables that can be accessed/modified by subexpressions.\n\n#### Variable binding\n```\n(:let a b (c 10))\n```\nBinds the specified variables (dynamically).\nSubexpressions (and subexpressions of subexpressions, etc) of the rule have access to these variables and can even modify them.\nIn order to access the variables, the subexpressions have to declare them using `:external` (see below).\nIf a subexpression binds the same variable with another `:let`, the previous binding is shadowed until the subexpression returns.\nFor an example of variable usage, see the section 'Using context' below.\n\n#### External bindings\n```\n(:external a b c)\n```\nDeclares the specified variables.\nIf the rule is called by a superior rule that binds these variables (using `:let`, see above), this rule can use and modify the variables.\nIt is an error if a rule using external variables is called when the variables are unbound (i.e. the rule must be called as a subexpression to a rule defining the variables).\n\n### Packrat parsing\nPackrat parsing can be enabled for a rule by using the `(:packrat t)` option.\nSee the [wiki page](https://github.com/mrossini-ethz/parseq/wiki/Packrat-Parsing) for more information.\n\n## Using context\nParsing in parseq can be made context aware using two methods.\n\n### Context through tests\nA single rule can verify one part of its result against another.\nFor instance, if a tag is a name followed by a type and a value, then the rule\n```\n(defrule tag () (and string symbol form) (:test (name type value) (eql (type-of value) type)))\n```\nwill check whether the value is indeed of the specified type. Otherwise the rule will fail.\n\n### Context through variables\nIt is possible to make rules depend on the results of other rules.\nThis can be achieved through external variable bindings that are introduced with `(:let ...)` and used with `(:external ...)`.\n\nSuppose the binary format of a file specifies that a string is stored as a byte indicating the length of the string followed by that number of characters.\nA set of rules for parsing this could be:\n```\n(defrule string () (and length chars) (:let len))\n(defrule length () byte (:external len) (:lambda (x) (setf len x)))\n(defrule chars () (rep len byte) (:external len))\n```\nExternal variables can also be used from within `(:test ...)` or `(:not ...)` or even the parse expression.\n\n## Rule tracing\nRules can be traced by calling\n```\n(trace-rule 'nonterminal-symbol)\n```\nwhich will print the information to standard output.\nWith the keyword argument `:recursive t`, all rules called from within the given rule will be traced as well.\nTracing can be turned off by calling\n```\n(untrace-rule 'nonterminal-symbol)\n```\n\n## Namespaces\nYou can use local namespaces for nonterminal symbols:\n```\n(with-local-rules\n  (defrule ...)\n  (defrule ...)\n  (parseq ...))\n```\nWithin the body of `with-local-rules` new rules can be defined that will be invisible outside.\nAlso, outside rules will be invisible within the body.\n\nInstead of `with-local-rules` the macro `with-saved-rules` can be used:\n```\n(defrule a ...)\n(defrule b ...)\n(defrule ab () (and a b))\n(with-saved-rules\n  (defrule b ...)\n  (parseq 'ab ...))\n(parseq 'ab ...)\n```\nWithin its body, rules from outside are still defined and can be redefined without affecting the outside.\nThe rules from outside are saved before entering the body and restored when the body returns.\n\n## Example code\nThere is a collection of real world examples inside the repository [here](https://github.com/mrossini-ethz/parseq/tree/master/examples).\nIt is a good place to start if you want to learn about parseq.\nAlso check out the library [physical-quantities](https://github.com/mrossini-ethz/physical-quantities) that uses parseq under the hood.\n\n## Upcoming features\nThese features _may_ be implemented in the future:\n\n * Support for rule parameters in parsing expressions other than literal terminals and nonterminals.\n * Short forms for combined nonterminals, e.g.\n   * `(? (and ...))`\n   * `(? (or ...))`\n   or multiple arguments to `(? ...)` signifying either a sequence or a choice.\n * Support for streams (how?)\n * Speed and efficiency\n * Custom terminals\n * Custom non-terminal expressions\n * Custom sequences, i.e. parse _anything_\n\n## Warnings\nPlease heed the following warnings:\n\n * The interface and behaviour of parseq are not yet frozen.\n   New versions may break programs using the library.\n * The library should work with SBCL, CMUCL, ECL and CLISP.\n   Other lisp implementations are untested.\n * Parseq comes with no warranty whatsoever.\n\n## Licence\nParseq is distributed with the GNU General Public License, version 2:\n\nCopyright (C) 2017 Marco Rossini\n\nThis program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\nYou can also find the full licence [online](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).\n\n## Questions/Bugs/Help/Requests/Feedback etc.\n\nIf you have questions regarding parseq, found any bugs, would like to offer help, have a feature request, give feedback etc., feel free to contact me through GitHub.\n","funding_links":[],"categories":["Online editors ##"],"sub_categories":["Third-party APIs"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrossini-ethz%2Fparseq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrossini-ethz%2Fparseq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrossini-ethz%2Fparseq/lists"}