{"id":17685634,"url":"https://github.com/ghaiklor/pascal-interpreter","last_synced_at":"2025-04-14T19:33:55.724Z","repository":{"id":22187231,"uuid":"95539079","full_name":"ghaiklor/pascal-interpreter","owner":"ghaiklor","description":"A simple interpreter for a large subset of Pascal language written for educational purposes","archived":false,"fork":false,"pushed_at":"2025-02-19T14:26:39.000Z","size":788,"stargazers_count":35,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T07:51:14.868Z","etag":null,"topics":["ast","ast-node","ast-nodes","grammar-rules","interpreter","lexer","lexical-analysis","parse","parser","pascal","pascal-interpreter","pascal-language","scanner","semantic-analysis","symbol-table","syntax-analysis","tokenizer","visitor"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/ghaiklor.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-06-27T09:04:23.000Z","updated_at":"2024-12-01T13:07:38.000Z","dependencies_parsed_at":"2022-08-07T10:01:37.200Z","dependency_job_id":"1cf462e8-24ff-4398-98f4-dc088812fe3c","html_url":"https://github.com/ghaiklor/pascal-interpreter","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/ghaiklor%2Fpascal-interpreter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghaiklor%2Fpascal-interpreter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghaiklor%2Fpascal-interpreter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghaiklor%2Fpascal-interpreter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ghaiklor","download_url":"https://codeload.github.com/ghaiklor/pascal-interpreter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246285645,"owners_count":20752947,"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":["ast","ast-node","ast-nodes","grammar-rules","interpreter","lexer","lexical-analysis","parse","parser","pascal","pascal-interpreter","pascal-language","scanner","semantic-analysis","symbol-table","syntax-analysis","tokenizer","visitor"],"created_at":"2024-10-24T10:28:30.548Z","updated_at":"2025-03-30T06:31:14.440Z","avatar_url":"https://github.com/ghaiklor.png","language":"JavaScript","readme":"# Pascal Interpreter\n\n[![Build Status](https://travis-ci.org/ghaiklor/pascal-interpreter.svg?branch=master)](https://travis-ci.org/ghaiklor/pascal-interpreter)\n[![Coverage Status](https://coveralls.io/repos/github/ghaiklor/pascal-interpreter/badge.svg?branch=master)](https://coveralls.io/github/ghaiklor/pascal-interpreter?branch=master)\n[![Greenkeeper badge](https://badges.greenkeeper.io/ghaiklor/pascal-interpreter.svg)](https://greenkeeper.io/)\n\n_A simple interpreter for a large subset of Pascal language written for educational purposes_\n\n_This repository contains the code I wrote during these articles - [https://ruslanspivak.com/lsbasi-part1/](https://ruslanspivak.com/lsbasi-part1/)_\n\n## Demo\n\nFor demonstration purposes I wrote the following code in Pascal:\n\n```pascal\nPROGRAM myProgram;\nVAR\n  number : INTEGER;\n  a, b   : INTEGER;\n  y      : REAL;\n\nBEGIN {myProgram}\n  number := 2;\n  a := number;\n  b := 10 * a + 10 * a DIV 4;\n  y := 20 / 7 + 3.14;\nEND.  {myProgram}\n```\n\nSince, there are no I\\O implementation in Pascal, I'll show you a GIF where you can see scope of variables before and after interpretation of this program.\n\nHere is the copied output from my demo script (gif below):\n\n```\n----------------------------------\nProgram scope before interpreting:\nundefined\n----------------------------------\nProgram scope after interpreting:\n{ number: 2, a: 2, b: 25, y: 5.857142857142858 }\n----------------------------------\n```\n\n![Interpreter Demo](https://user-images.githubusercontent.com/3625244/28240074-1186c6d0-6983-11e7-97ab-974c81d07fb9.gif)\n\n## Known issues\n\n- Procedures declarations are supported by parser and AST, but interpreter doesn't support its execution (there is no implementation for this at all);\n- There are no builtin IO procedures, like writing into standard output and reading from standard input;\n\n## Phases\n\nThis interpreter has several phases to execute before interpreting the source code:\n\n- [Lexical Analysis](./src/lexer)\n- [Syntax Analysis](./src/parser)\n- [Semantic Analysis](./src/semantic)\n- [Interpretation](./src/interpreter)\n\nEach of these steps are explained a little bit below.\n\n### Lexical analysis\n\n\u003e Lexical analysis is the process of converting a sequence of characters (such as in a computer program or web page) into a sequence of tokens (strings with an assigned and thus identified meaning)\n\nImplementation of scanner here is based on simple lookahead pointer in input.\n\nScanner stores three properties: `input`, `position` and `currentChar`.\n\n- input stores the whole code of input source code;\n- position stores an integer which determines current position of a scanner in provided input;\n- currentChar stores a character stored by current position of a marker;\n\nEach time, when `advance()` called, it increments the value of `pointer` and read new character into `currentChar` property.\n\nEach time, when `getNextToken()` is called, it calls `advance()` as many times as soon the next valid token is meet the requirements.\n\nIn a result, scanner returns a stream of a tokens.\nIn our case, token is simply a structure with two fields: `type` and `value`.\n`type` recognizes a lexeme by its type, like NUMBER or SEMICOLON and `value` stores the original character sequence.\n\n### Syntax analysis\n\n\u003e Syntax analysis is the process of analysing a string of symbols, either in natural language or in computer languages, conforming to the rules of a formal grammar\n\nWe are recognizing a string of tokens (stream of tokens) here.\n\nParser implementation here has mapped all its methods onto formal grammar rules (productions).\nEach method has in its comments a production, that the method is trying to follow.\n\nI.e. take a look into _factor_ production:\n\n```js\n/**\n * factor: PLUS factor\n *       | MINUS factor\n *       | INTEGER_LITERAL\n *       | REAL_LITERAL\n *       | LEFT_PARENTHESIS expr RIGHT_PARENTHESIS\n *       | variable\n *\n * @returns {Node}\n */\nfactor() {\n  const token = this.currentToken;\n\n  if (token.is(Token.PLUS)) {\n    this.eat(Token.PLUS);\n    return AST.UnaryOperator.create(token, this.factor());\n  } else if (token.is(Token.MINUS)) {\n    this.eat(Token.MINUS);\n    return AST.UnaryOperator.create(token, this.factor());\n  } else if (token.is(Token.INTEGER_LITERAL)) {\n    this.eat(Token.INTEGER_LITERAL);\n    return AST.Number.create(token);\n  } else if (token.is(Token.REAL_LITERAL)) {\n    this.eat(Token.REAL_LITERAL);\n    return AST.Number.create(token);\n  } else if (token.is(Token.LEFT_PARENTHESIS)) {\n    this.eat(Token.LEFT_PARENTHESIS);\n    const node = this.expr();\n    this.eat(Token.RIGHT_PARENTHESIS);\n    return node;\n  }\n\n  return this.variable();\n}\n```\n\nComments above the method show a grammar rule.\nMethod implementation itself follows this grammar rule.\n\nEach terminal is a token, while each non-terminal is another method in a parser.\n\nAs a result, syntax analysis returns a generated AST of a Pascal program.\n\n### Semantic analysis\n\n\u003e Semantic analysis, also context sensitive analysis, is a process in compiler construction, usually after parsing, to gather necessary semantic information from the source code. It usually includes type checking, or makes sure a variable is declared before use which is impossible to describe in Extended Backus–Naur Form and thus not easily detected during parsing.\n\nThat's why semantic analysis is a separate phase of a compiler.\nParsing know nothing about context in which your source code will run.\n\nSemantic analyzer is implemented as AST visitor, which takes an AST from the parser and visits all the nodes.\n\nCurrent implementation of a semantic analysis is just about symbol tables and type checking.\nEach time when visitor visits a node with variable declaration, it creates a record about its scope, type and name in symbol table. Each time when a node is procedure declaration, it creates record about its scope, formal parameters list and a name in symbol table.\n\nAfterwards, semantic analyzer checks if you have any duplicate declarations or doesn't have those at all.\n\n### Interpretation\n\n\u003e An interpreter is a computer program that directly executes, i.e. performs, instructions written in a programming or scripting language, without previously compiling them into a machine language program\n\nIn our case, our \"computer program\" that directly executes the code is written in JavaScript and uses NodeJS runtime for these purposes.\n\nInterpreter implemented as AST visitor as well.\nAfter successful semantic analysis, AST goes into interpreter.\n\nInterpreter visits each AST node recursively and calls appropriate JavaScript runtime methods to execute the code.\n\nAs a result, we got our code written in Pascal run.\n\n## Roadmap\n\n### Lexer\n\n- Dictionary of tokens **[DONE]**\n- Structure with accessors which defines token **[DONE]**\n- Casting tokens into strings when printing **[DONE]**\n- Helper for checking token types via *is()* **[DONE]**\n- Lexical analyzer which returns next token each time you call *getNextToken()* **[DONE]**\n- Skip whitespaces at all **[DONE]**\n- Read digits as one token **[DONE]**\n- Read alphanumeric as IDENTIFIER tokens **[DONE]**\n- Add a dictionary of reserved words in a language with appropriate tokens in it **[DONE]**\n\n### Parser\n\n- Consuming (eating) tokens from a lexer **[DONE]**\n- Productions for mathematical expressions **[DONE]**\n- Associativity and precedence **[DONE]**\n- Support for parenthesis **[DONE]**\n- Support for variable assignments **[DONE]**\n- Support for compounds of statements **[DONE]**\n- Building an AST nodes **[DONE]**\n\n### AST\n\n- Basic AST Node class **[DONE]**\n- Number Node **[DONE]**\n- BinaryOperator Node **[DONE]**\n- UnaryOperator Node **[DONE]**\n- Assign Node **[DONE]**\n- Compound Node **[DONE]**\n- NoOperation Node **[DONE]**\n- Variable Node **[DONE]**\n\n### Interpreter\n\n- *visit()* that calls visitors for each AST node, based on its type **[DONE]**\n- Visitor for Number Node **[DONE]**\n- Visitor for UnaryOperator Node **[DONE]**\n- Visitor for BinaryOperator Node **[DONE]**\n- Visitor for NoOperation Node **[DONE]**\n- Visitor for Compound Node **[DONE]**\n- Visitor for Assign Node **[DONE]**\n- Visitor for Variable Node **[DONE]**\n\n## License\n\n[MIT](./LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghaiklor%2Fpascal-interpreter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fghaiklor%2Fpascal-interpreter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghaiklor%2Fpascal-interpreter/lists"}