{"id":16266872,"url":"https://github.com/jasonzhu1313/interactiveexpressionparser","last_synced_at":"2025-03-19T23:30:46.324Z","repository":{"id":119915326,"uuid":"112139533","full_name":"JasonZhu1313/InteractiveExpressionParser","owner":"JasonZhu1313","description":"This project focus on using functional programing to parse the expression, I use Haskell to develop an interactive expression parser using a lot of features of Haskell, you can use haskell compiler such as GHCI to run the program, Let's begin.","archived":false,"fork":false,"pushed_at":"2017-11-30T03:18:30.000Z","size":8,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-28T21:32:53.566Z","etag":null,"topics":["expression-evaluator","functional-programming","ghci","haskell","haskell-compiler","interactive","parse"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JasonZhu1313.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-11-27T02:52:45.000Z","updated_at":"2022-11-30T15:15:23.000Z","dependencies_parsed_at":"2023-11-19T19:01:25.003Z","dependency_job_id":null,"html_url":"https://github.com/JasonZhu1313/InteractiveExpressionParser","commit_stats":null,"previous_names":["jasonzhu1313/interactiveexpressionparser"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JasonZhu1313%2FInteractiveExpressionParser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JasonZhu1313%2FInteractiveExpressionParser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JasonZhu1313%2FInteractiveExpressionParser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JasonZhu1313%2FInteractiveExpressionParser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JasonZhu1313","download_url":"https://codeload.github.com/JasonZhu1313/InteractiveExpressionParser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244030752,"owners_count":20386533,"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":["expression-evaluator","functional-programming","ghci","haskell","haskell-compiler","interactive","parse"],"created_at":"2024-10-10T17:43:15.772Z","updated_at":"2025-03-19T23:30:46.047Z","avatar_url":"https://github.com/JasonZhu1313.png","language":"Haskell","readme":"# InteractiveExpressionParser\nThis project focus on using functional programing to parse the expression, I use Haskell to develop an interactive expression parser using a lot of features of Haskell, you can use haskell compiler such as GHCI to run the program, Let's begin.\n\n# Expression Tree\n\nIn Haskell, a famous data type called Maybe is used to represent “a value or nothing”. If an expression e has type Maybe a, then e is either Just a (just a value of type a) or Nothing, as demonstrated by the de nition below.\ndata Maybe a = Just a | Nothing\nMaybe describes values with a context of possible failure attached. For example, if a function returns Maybe Int, it means the function may fail when calculating the result integer. We will make use of Maybe to deal with expression trees.\nLet’s consider the following Expr data type for expression trees. data Binop = Add | Sub | Mul | Div | Mod\nderiving (Eq, Show)\ndata Expr\n= Bin Binop Expr Expr | Val Int\n| Var String deriving (Eq, Show)\nIt might be a little bit di erent from the expression tree you have seen, because we are going to reuse Binop later. Binop stands for binary operations, including addition Add, subtraction Sub, multiplication Mul, division Div, modulo Mod. Expr contains all binary operations over expressions, together with integer literal Val and variable Var.\nWe use an environment Env to determine the values for variables:\ntype Env = [(String, Int)]\nThe library function lookup could be used for searching in an environment.\nProblem 1. I implemented a function eval :: Env -\u003e Expr -\u003e Maybe Int to evaluate expression trees. eval should return Nothing if the divisor is 0 in the division and modulo cases. Also, if a variable cannot be found in the environment, Nothing should be returned.\n2\nrunning results:\n* Main\u003e eval [] (Bin Add (Val 2) (Val 3))\nJust 5\n* Main\u003e eval [(\"x\", 2)] (Bin Add (Var \"x\") (Val 3))\nJust 5\n* Main\u003e eval [(\"x\", 2)] (Bin Add (Var \"y\") (Val 3))\nNothing\n* Main\u003e eval [] (Bin Div (Val 4) (Val 2))\nJust 2\n* Main\u003e eval [] (Bin Mod (Val 4) (Val 0))\nNothing\n\n\n# Parsing Expressions\n\nThen let’s write a parser for those expression trees. You may want to review Tutorial 4 and the lecture slides when doing this I implemented a function pExpr :: Parser Expr for parsing Exprs. The grammar is provided as below:\nexpr := term op_term\nop_term := (′+′ | ′−′) term op_term | ε term := factor op_factor\nop_factor := (′∗′ | ′/′ | ′%′) factor op_factor | ε factor := ′(′ expr ′)′ | integer | identifier\nYou can assume the identi ers start with a lower case letter, and may contain any alphabetic or numeric characters after the  rst one.\nNotice:\n• Use the token function in Parsing.hs to remove leading and trailing spaces.\n• Your parser should re ect the left-associativity of the operators. See the second\nexample below.\nrunning results:\n* Main\u003e parse pExpr \"1 + 2\"\n[(Bin Add (Val 1) (Val 2),\"\")]\n* Main\u003e parse pExpr \"1 + 2 + 3\"\n[(Bin Add (Bin Add (Val 1) (Val 2)) (Val 3),\"\")]\n* Main\u003e parse pExpr \"1 + x\"\n[(Bin Add (Val 1) (Var \"x\"),\"\")]\n* Main\u003e parse pExpr \"1 + x * 3\"\n[(Bin Add (Val 1) (Bin Mul (Var \"x\") (Val 3)),\"\")]\n* Main\u003e parse pExpr \"1 + x * 3 / 5\"\n[(Bin Add (Val 1) (Bin Div (Bin Mul (Var \"x\") (Val 3)) (Val 5)),\"\")]\n\n\nI implemented a function runParser :: Parser a -\u003e String -\u003e Maybe a. runParser runs a given parser to parse the full string and returns the  rst result. Maybe implys the parser may fail.\nNotice:\n• Return Nothing when the result list is empty.\n• Return Nothing when the parser only consumes part of the input (the second\ncomponent of the pair is not empty, see the examples below).\nrunning results:\n* Main\u003e runParser (char 'a') \"a\"\nJust 'a'\n* Main\u003e runParser (char 'a') \"ab\"\nNothing\n* Main\u003e runParser pExpr \"1+2\"\nJust (Bin Add (Val 1) (Val 2))\n* Main\u003e runParser pExpr \"1++\"\nNothing\n\n#Compilation\nInstead of de ning eval directly, we can give expressions meaning by compiling expres- sions onto a simple stack machine.\nConsider that the stack machine supports the following instructions:\ndata Instr = IVal Int | IBin Binop | IVar String deriving (Eq, Show)\nInstructions contains integer literal IVal, variable Var, and binary operations IBin. The evaluation of instructions are based on a simple stack, which is modeled as a list of integers:\ntype Stack = [Int]\nInstruction IVal i will push i into the stack, and IVar x will push the value of variable x (if it is in the environment) into stack. IBin op will pop two values from the stack, and apply the binary operator to them, and then push the result into the stack.\nA program is a list of instructions.\ntype Prog = [Instr]\nI implemented a function runProg :: Prog -\u003e Env -\u003e Maybe Int. runProg runs a program with an empty stack at the beginning. It should end with exactly one number in the stack. In those cases, return Just value where value is the only number in the stack. Return Nothing if evaluation fails:\n• Not enough numbers to apply for binary operations.\n• A divisor is 0 in the division and modulo cases.\n• A variable cannot be found in the environment.\n• After evaluation, the stack has less or more than one number.\nrunning results:\n* Main\u003e runProg [IVal 1, IVal 2, IBin Add] []\nJust 3\n6\n* Main\u003e runProg [IVal 2, IVal 4, IBin Div] []\nJust 2\n* Main\u003e runProg [IVal 3, IBin Add] []\nNothing\n* Main\u003e runProg [IVal 2, IVal 4, IBin Mul, IVal 1] []\nNothing\n* Main\u003e runProg [IVal 2, IVar \"x\", IBin Sub] [(\"x\", 3)]\nJust 1\n\nI implemented a function compile :: Expr -\u003e Prog that compiles an expression into a program that can be run in the stack machine.\n* Main\u003e compile (Bin Sub (Val 2) (Val 1))\n[IVal 1,IVal 2,IBin Sub]\n* Main\u003e compile (Bin Sub (Val 2) (Var \"x\"))\n[IVar \"x\",IVal 2,IBin Sub]\n* Main\u003e compile (Bin Sub (Val 2) (Bin Add (Val 1) (Var \"x\")))\n[IVar \"x\",IVal 1,IBin Add,IVal 2,IBin Sub]\nWith all those functions de ned so far, you should be able to verity that the two ap- proaches always give the same result:\n• Direct evaluation over an expression\n• First translate the expression into a program on a simple stack machine, and then\nrun the program.\n* Main\u003e let Just x = runParser pExpr \"2-1\" *Main\u003e x\nBin Sub (Val 2) (Val 1)\n* Main\u003e eval [] x\nJust 1\n* Main\u003e compile x\n[IVal 1,IVal 2,IBin Sub]\n* Main\u003e runProg (compile x) []\nJust 1\n\n#Optimization\nThe compilation in practice can be very complicated. In order to produce e cient ma- chine programs, there are usually many optimization heuristics. One of the simplest heuristics is Constant folding, namely, calculation between constants is calculated di- rectly during compilation time instead of at runtime.\nI implemented a function optimize :: Expr -\u003e Maybe Expr that optimizes an expression according to the following rules:\n• Multiplication between any expression e and 0 is simpli ed to 0. • Addition between any expression e and 0 is simpli ed to e.\n• Subtraction an expression e by 0 simpli ed to e.\n• Division or Modulo by 0 returns Nothing.\n• Any evaluation between constants are calculated directly.\nrunning results:\n* Main\u003e optimize $ Bin Add (Var \"x\") (Bin Sub (Val 2) (Val 1))\nJust (Bin Add (Var \"x\") (Val 1))\n* Main\u003e optimize $ Bin Add (Val 3) (Bin Sub (Val 2) (Val 1))\nJust (Val 4)\n* Main\u003e optimize $ Bin Add (Val 3) (Bin Mul (Var \"x\") (Val 0))\nJust (Val 3)\n* Main\u003e optimize $ Bin Add (Var \"x\") (Val 0)\nJust (Var \"x\")\n* Main\u003e optimize $ Bin Add (Var \"x\") (Val 1)\nJust (Bin Add (Var \"x\") (Val 1))\n* Main\u003e optimize $ Bin Div (Val 3) (Val 0)\nNothing\n\n\n#REPL: Read-Eval-Print Loop\nRunning Example 1:\nMain\u003e main\n* \u003e no such command\nError\n* \u003e quit \n* Main\u003e\n\nRunning Example 2:\n* Main\u003e main\n* \u003e let a = 10 + 10 * 2\n* a = 30\n* \u003e let b = a * 2\n* b = 60\n* \u003e let b = 5 / 0\n* Error\n* \u003e let d = c Error\n* \u003e let b = 10 b = 10\n* \u003e let e = b + 5 e = 15\n* \u003e quit \n* Main\u003e\n\nRunning Example 3:\n*Main\u003e main\n* \u003e env\n* \u003e let a = 10 a = 10\n* \u003e let b = a / 2\n\n* b=5\n* \u003e env a = 10 b=5\n* \u003e let a = 5 + 1 * 2 a=7\n* \u003e env a=7 b=5\n* \u003e quit *Main\u003e\n\n* \u003e let a = 10 + 20\n* a = 30 \u003e var a\n* a = 30 \u003e var b\nError\n* \u003e let a = 3 * 4 a = 12\n* \u003e var a a = 12\n* \u003e quit *Main\u003e\n\n\nRunning Example:5\n* Main\u003e main \u003e let a = 10\n* \u003e var a a = 10\n* \u003e del a\nDeleted a\n*  \u003e var a Error\n* \u003e del b Error\n* \u003e let b = 10 b = 10\n* \u003e quit\n\n\nRunning Example 6:\n* Main\u003e main \u003e1+2+3+4\n* ans = 10 \u003e1+2*2\n* ans = 5\n* \u003e let a = 10\n* 13\n* a = 10 \u003ea-1-2\n* ans = 7 \u003e5/0\nError\n\u003e b+1 Error\n\u003e let b = 2 b=2\n\u003e a*b ans = 20\n\u003e quit\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasonzhu1313%2Finteractiveexpressionparser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjasonzhu1313%2Finteractiveexpressionparser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasonzhu1313%2Finteractiveexpressionparser/lists"}