{"id":20191432,"url":"https://github.com/htfy96/htscheme","last_synced_at":"2025-10-29T12:06:27.191Z","repository":{"id":86701972,"uuid":"38605306","full_name":"htfy96/htscheme","owner":"htfy96","description":"Tiny Scheme Interpreter ","archived":false,"fork":false,"pushed_at":"2016-04-12T12:53:52.000Z","size":32610,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"submit","last_synced_at":"2025-01-13T18:52:46.573Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/htfy96.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":"2015-07-06T07:56:29.000Z","updated_at":"2020-08-14T10:45:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"d76c09f3-b150-4bbd-ae19-ba2f10e387a0","html_url":"https://github.com/htfy96/htscheme","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htfy96%2Fhtscheme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htfy96%2Fhtscheme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htfy96%2Fhtscheme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htfy96%2Fhtscheme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/htfy96","download_url":"https://codeload.github.com/htfy96/htscheme/tar.gz/refs/heads/submit","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241629736,"owners_count":19993707,"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":[],"created_at":"2024-11-14T03:49:05.116Z","updated_at":"2025-10-29T12:06:27.185Z","avatar_url":"https://github.com/htfy96.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"#htScheme\nA structured and plugin-based scheme interpreter implementation.\n\n##How to use\n\n### Prerequisites\n - A modern C++ compiler supporting c++11 feature.\n (gcc4.9.2, gcc5.1, clang3.6 have been tested on Linux)\n\n - GNU Make\n (Make v4.0 has been tested on Linux)\n\n\n###Make\nEnter the `scheme` directory and  run the following commands to generate various targets:\n\n|\t\t**Command**\t\t|\t\t**Function**\t\t                                |\n|:---------------------:|:---------------------------------------------------------:|\n|`make`=`make all`      |Call everything below except `dep` and `clean`             |\n|`make cli`             |Generate `cli` (the command-line interpreter frontend)     |\n|`make dep`             |Generate `dep.d` which contains the dependencies of files  | \n|`make clean`\t\t\t|Remove all files generated by `make`\t                    |\n|`make preprocessortest`|Generate `preprocessortest`\t\t\t\t                |\n|`make tokenizertest`\t|Generate `tokenizertest`\t\t\t\t\t                |\n|`make asttest`\t\t\t|Generate `asttest`\t\t\t\t\t\t\t                |\n|`make parserstest`\t\t|Generate `parserstest`\t\t\t\t\t\t                |\n|`make biginttest`\t\t|Generate `biginttest`\t\t\t\t\t\t                |\n|`make rationaltypetest`|Generate `rationaltypetest`                                |\n\nYou may notice that the compilation is rather slow, therefore you can add `-j4` to `make` command in order to parallel the compilation with four threads.\n\n##How to develop with htScheme\nhtScheme has been designed as an extensible architecture of scheme-like languages, thus new types of tokens as well as parsers could be easily added into this program.\n\n###Brief introduction to files\n\n####preprocessor.hpp/cpp\n```cpp\nclass SchemeUnit\n{\n    public:\n        SchemeUnit(std::istream\u0026 schemeStream);\n        std::vector\u003cstd::string\u003e lines;\n        void preprocess(std::istream\u0026 schemeStream);\n};\n```\nAccept a `std::istream` as the parameter, then read lines from it until `schemeStream.eof()` and remove the comments with the result stored in `lines`.\n\n####tokenizer.hpp/cpp\n```cpp\nclass Tokenizer\n{\n    public:\n        Tokenizer(const std::vector\u003cstd::string\u003e\u0026 lines);\n        void split(const std::vector\u003cstd::string\u003e\u0026 lines);\n        void parse(const std::list\u003cstd::string\u003e\u0026 rawTokens);\n        std::list\u003cstd::string\u003e rawTokens;\n        std::list\u003cToken\u003e tokens;\n        bool complete;\n};\n```\nAccept lines of program, Then `Tokenizer::Tokenizer` will call `Tokenizer:split` and `Tokernizer::parse` in order.\n\n`Tokenizer::split` splits `lines` into several small string pieces stored in `Tokenizer::rawTokens`. \nFor example, `(string-ith \"123 34\" 2)` will be split into \n```\n(\nstring-ith\n\"123 34\"\n2\n)\n```\n\n`Tokenizer::parse` convert `Tokenizer::rawTokens` to `Tokenizer::tokens`.\n\n`Token` is defined as followed in `types/all.hpp`:\n```cpp\nstruct Token\n{\n    TokenType tokenType; //enum TokenType {OpPlus, ...}\n    InfoTypes info; //typedef boost::variant\u003cInfoType1, ...\u003e InfoTypes\n    std::string raw; //raw token\n};\n```\n\nThere is an extra variable `Tokenizer::complete` in this class, which represents whether there is no incomplete brackets or quotaion marks. This could be useful in building command-line interpreter.\n`Tokenizer::complete` can be set by both `Tokenizer::split` and `Tokenizer::parse`.\n\n####ast.hpp/cpp\n```cpp\nclass AST\n{\n    public:\n        PASTNode astHead; //typedef std::shared_ptr\u003cASTNode\u003e PASTNode\n        void buildAST(const std::list\u003cToken\u003e \u0026tokens);\n        AST (const std::list\u003cToken\u003e \u0026tokens);\n        AST();\n        friend std::ostream\u0026 operator \u003c\u003c (std::ostream\u0026 o, const AST\u0026 ast);\n};\n```\nBuild an AST which could be accessed through `AST.astHead` with `std::list\u003cToken\u003e`.\n\nHere is the definition of `ASTNode`:\n```cpp\nstruct ASTNode\n{\n    NodeType type; //enum NodeType {Bracket, Simple};\n    Token token;\n    PASTNode parent;\n    std::list\u003cPASTNode\u003e ch;\n\n    ASTNode* add(const ASTNode\u0026 node); //ch.push_back(std::make_shared\u003cASTNode\u003e(ASTNode(node))\n    void remove(); //Recursively remove all its children then clear ch \n};\n```\n\nFor example, `(+ 2.7 (- 5.6 2.1) 3)` will be converted to the following AST:\n```\nType:0 Token.info:0 TokenType:0 //astHead\n+----Type:Bracket Token.info:0 TokenType:0\n          +---Type:Simple Token.info:0 TokenType:OpPlus\n          |---Type:Simple Token.info:2.7 TokenType:Float\n          |---Type:Bracket Token.info:0 TokenType:0\n          |      +---Type:Simple Token.info:0 TokenType:OpMinus\n          |      |---Type:Simple Token.info:5.6 TokenType:Float\n          |      |---Type:Simple Token.info:2.1 TokenType:Float\n          |---Type:Simple Token.info:3 TokenType:Float\n```\n\n####parsers.hpp\nThe main part of `parsers.hpp` is in `parsers/all.hpp`\n\n```cpp\nclass ParsersHelper\n{\n    ParsersHelper();\n    void parse(PASTNode astnode);\n};\n```\nProvide a smart pointer of `ASTNode` to an instance of `ParsersHelper::parse`, then `ParsersHelper` will call according `xxxASTParser::parse(PASTNode parent, ParsersHelper\u0026 helper)` to recursively calculate the result of a subtree of AST with its root as `astnode`. \nAfter `ParsersHelper::parse`, `astnode.type` will become `Simple`. \nIf `astnode` is already a `Simple` node, nothing will be done.\n\nThe parsed version of the above AST is (by calling `parse( **ast.headNode.ch.begin() )`:\n```\nType:1 Token.info:0 TokenType:0 //headNode\n+----Type:Simple Token.info:9.2 TokenType:Float\n```\n\n**Warning** --DO NOT-- directly call `helper.parse(*ch[xx])` in `xxxASTParser::parse(ASTNode\u0026 parent, ParsersHelper\u0026 helper)` ! Instead, you should copy construct a new `ParsersHelper` to parse its children.\n\n\n\n###Add your own Token Parser\n\n \u003e An token parser is a struct with static member functions which judge whether a string is a token of this type then convert it to InfoType\n\nIn this section, we will try to add a new `Rational` type of token.\n\n####Step1: Register the Rational Type\nOpen `types/arch.hpp`, add `Rational` to `enum TokenType{ ... , Rational }`\n\n####Step2: Register the Rational Parser\n - Open `types/all.hpp`, add `RationalParser` to `#define PARSERS_TUPLE (..., RationalParser)`\n\n - `#include \"rational.hpp\"`\n\n####Step3: Write the Header\n - Create `types/rational.hpp`, then include your declaration of your `RationalType` and `\"arch.hpp\"`\n - Use the macro in `arch.hpp` to generate the declaration of your `RationalParser` : \n ```\n PARSER_DECLARATION(RationalParser, Rational, RationalType)\n ```\n\n####Step4: Implement the Parser\n - Create `types/rational.cpp`, then `#include \"rational.hpp\" ` and implement your `RationalType` in it.\n - Implement `bool RationalParser::judge(const std::string\u0026 token)` which returns whether a token is a rational token \n and\n `RationalParser::InfoType RationalParser::get(const std::string\u0026 token)` which converts the token to `RationalParser::InfoType`(aka `RationalType`)\n - `const TokenType RationalParser::type = Rational;`\n\n###Add your own AST Parser\n\n \u003e An AST parser is a struct inheritating `ASTParser`, which judges whether it can parse a subtree of AST then parse it.\n\n \u003e Note: In token parser there is only static functions, but an AST parser will be instantiated before we use it, therefore\n \u003e it could include some data members (e.g a database)\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhtfy96%2Fhtscheme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhtfy96%2Fhtscheme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhtfy96%2Fhtscheme/lists"}