{"id":21361624,"url":"https://github.com/phillbush/hoc","last_synced_at":"2025-08-10T21:07:06.589Z","repository":{"id":133377543,"uuid":"326109880","full_name":"phillbush/hoc","owner":"phillbush","description":"high order calculator: an interpreter for a simple language for floating point arithmetic","archived":false,"fork":false,"pushed_at":"2021-10-16T16:57:50.000Z","size":217,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-15T11:11:47.439Z","etag":null,"topics":["c","hoc","lex","unix","yacc"],"latest_commit_sha":null,"homepage":"","language":"C","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/phillbush.png","metadata":{"files":{"readme":"README","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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-02T04:42:54.000Z","updated_at":"2025-03-03T06:41:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"50e08a97-169e-4f68-94f5-532dcb26d4a2","html_url":"https://github.com/phillbush/hoc","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/phillbush%2Fhoc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phillbush%2Fhoc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phillbush%2Fhoc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phillbush%2Fhoc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phillbush","download_url":"https://codeload.github.com/phillbush/hoc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249058376,"owners_count":21205909,"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":["c","hoc","lex","unix","yacc"],"created_at":"2024-11-22T06:10:41.127Z","updated_at":"2025-04-15T11:12:06.177Z","avatar_url":"https://github.com/phillbush.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"                                  hoc:\n                         High-Order Calculator\n\nThis is an implementation of a stage-6 hoc(1) with added features.\nHoc (High-Order Calculator) is an interpreter for a simple language\nused for floating point arithmetic with C-like syntax.\n\n§ FILES\n\n• README:       This file.\n• Makefile:     The makefile.\n• code.[hc]:    Routines for executing the machine instructions.\n• error.[hc]:   Routines for error printing.\n• main.c:       The main routine.\n• lex.l:        The lexical analyzer.\n• gramm.y:      The grammar.\n\n\n§ USAGE\n\n\t$ hoc [file [arguments ...]]\n\nHoc reads the file given as argument and interpret it.  If no file is\ngiven, or if file is “-”, hoc interprets the standard input; in this\ncase, I recommend running hoc with rlwrap(1), for a better interactive\nshell with history support.\n\n\n§ TODO\n\n• Add a facility to execute system commands from within hoc (and assign\n  their return value to variables) (exercise 8-7).\n• Add interrupt handling, so that a runaway computation can be stopped\n  without losing the state of variables already computed (exercise 8-16).\n• Add arrays to hoc.  Pass they by reference to function and procedures.\n  Return a pointer to them (exercise 8-20).\n• Add string concatenation.\n• Add option -e to read code from command-line.\n• Read environment variables by a getenv() built-in function.\n\n\n§ FEATURES\n\nExercise 8-2 (modulus and unary +).\nThis version of hoc(1) supports the modulus operator (%) and the unary\nplus operator (+).\n\nExercise 8-3 (printed value).\nThe previously printed value can be accessed using the special variable\n`.` (period).\n\nExercise 8-4 (semicolon).\nThis version of hoc(1) supports both semicolon and newlines as statement\nseparators.  (See the `term` production rule on gramm.y).\n\nExercise 8-5 (prohibit assignment to constants).\nIn this version of hoc(1), constants such as pi are implemented as\nnullary built-in functions.  So, instead of using `PI`, you must use\n`pi()`.  Since built-in functions cannot be assigned, this prohibit\nassignment to constants.\n\nExercise 8-6 (n-ary functions).\nThis version of hoc(1) supports built-in functions with variable arity.\nIt also has the built-in function rand(), which returns a floating point\nrandom variable uniformly distributed on the interval (0,1).\n\nExercise 8-8 (table of built-in functions).\nThis version of hoc(1) uses a table instead of a set of essentially\nidentical functions for implementing the built-in functions.\n\nExercise 8-10 (dynamic machine).\nThe sizes of `stack` and `prog` are dynamic, so hoc never runs out of\nspace as memory can be obtained by calling malloc(3).\n\nExercise 8-12 (debug).\nBy compiling with -DDEBUG=1, the machine instructions hoc generates are\nprinted in a readable form for debugging.\n\nExercise 8-13 (assignment operators, short-circuit).\nThis version of hoc(1) supports the assignment operators of C, such as\n+=, *=, etc, and the increment and decrement operators ++ and --.   It\nalso supports short-circuit evaluation of the \u0026\u0026 and || operators,  so\nthey guarantee left-to-right evaluation and early termination, as in C.\n\nExercise 8-14 (for loops).\nThis version of hoc(1) supports for loops, and break and continue\nstatements.  Each element of the for loop (pre-loop; condition;\npost-loop) can be omitted, as in C.  An omitted condition implies\nin an infinite loop.\n\nExercise 8-15 (comments).\nThis version of hoc(1) supports comments beginnign with “#”.\n\nExercise 8-18 (named formal parameters).\nThis version of hoc(1) supports named formal parameters in subroutines\nas an alternative to $1, etc.\n\nExercise 8-19 (local variables).\nThis version of hoc(1) supports local variables by the same inelegant\nway that awk(1) does.\n\nExercise 8-21 (string handling).\nThis version of hoc(1) supports generalized string handling, so that\nvariables can hold strings instead of numbers.  (I have to add a\nconcatenation operand though).  It also has facilities for output\nformatting (the printf statement).\n\nLex.\nThis version of hoc(1) uses lex(1) for implementing the lexical analyzer.\n\nExpression list.\nThis version of hoc(1) supports list of expressions separated by comma,\nfor example in the for condition `for (i = 0, j = 1; i \u003c 3; i++, j++)`.\nThe value of a expression list is that of the rightmost expression.\n\nprint, printf and sprintf().\nThe `print` statement in this version of hoc actually works like\nawk(1)'s `print` statement (separates each argument with a space,\nand prints a newline at the end).  As awk(1), this version of hoc(1)\nalso has a `printf` statement and a `sprintf()` built-in function.\n\ngetline\nThe `getline VAR` expression reads a line into the variable VAR.\n\ndo-while.\nThis version of hoc(1) supports do-while statements.\n\nAccess command-line arguments.\nThis version of hoc(1) can access command-line arguments with the '$'\noperator.  $1 is the first command-line argument, $2 is the second,\nand so on.  $0 is the name of the input file.\n\nEscape line break.\nThis version of hoc(1) can escape new lines by ending a line with a\nbackslash (\\).\n\n\n§ NON-FEATURES\n\nExercise 8-11 will not be implemented.  It requires using a switch on\nthe type operation instead of calling functions from a function pointer.\nUsing function pointer is more elegant and easier to maintain than using\nswitch cases.\n\nExercise 8-17 will not be implemented.\nIf you want editing features use a shell wrapper such as rlwrap(1).\n\nReading from multiple files will not be implemented.\nUse cat(1).\n\n\n§ HOW IT WORKS\n\nHoc compiles input into a stack machine.   As input is parsed, code\nis generated for a simple computer instead of immediately computing\nanswers. Once the end of a statement is reached, the generated code\nis executed (interpreted) to compute the desired result. The simple\ncomputer is a ‘stack machine’: when an operand is encountered, it's\npushed onto a stack  (more precisely,  code is generated to push it\nonto a stack).  Stack machines usually result in simple interpreters\n(it's just an array containing operators and operands).  The operators\nare the machine instructions; each is a function call with its\narguments, if any, following the instruction.\n\nBefore parsing and execution begins, the machine is initialized and the\nsymbol table is populated by init().  Calls to the function install()\ninstalls both keywords and built-in functions in the symbol table.\n\nThe main loop reverts the stack machine to its initial state and parses\nthe input, one statement at a time.  While the input is parsed, code is\ngenerated for later execution by calls to the function `code()`,  which\nsimply puts an `Inst` data  (see bellow) into the next free spot in the\nprogram memory (pointed by `prog.progp`).   Once a statement is parsed,\nthe generated code is printed if DEBUG is set and then executed.\n\nFor example, to handle the assignment `x = 2 * y`, the following code\nis generated.  When this code is executed, the expression is evaluated\nand the result is stored in x.  The final `pop` clears the value off\nthe stack because it is not needed any longer.\n\n\tOPERATION: constpush    Push a constant onto stack\n\tVALUE:     2            … the constant 2\n\n\tOPERATION: varpush      Push symbol table pointer onto stack\n\tSYMBOL:    y            … for the variable y\n\tOPERATION: eval         Evaluate (replace pointer by value)\n\n\tOPERATION: mul          Multiply top two items; product replaces them\n\n\tOPERATION: varpush      Push symbol table pointer onto stack\n\tSYMBOL:    x            … for the variable x\n\tOPERATION: assign       Store value in variable, pop pointer\n\n\tOPERATION: pop          Clear top value from stack\n\tOPERATION: STOP         End of instruction sequence\n\nThe machine itself is a list of entries of data of type `Inst`.   An\n`Inst` is a union of stuff that can go into the memory; such as pointer\nto routines like `mul` that perform an arithmetic operation; or pointer\nto a entry in the symbol table; or a floating point number (for constant\nvalues); or a pointer to another entry in the machine (used by control\nflow statements), a string, etc.\n\nExecution of the machine is simple.  Each cycle calls `execute()`,\nwhich executes the function pointed to by the instruction pointed\nto by the program counter `prog.pc`, and makes `prog.pc` point to\nthe next instruction so it's ready for the next instruction.   An\nNULL instruction terminates the execution. Some instructions also\nincrement `prog.pc` to step over any arguments that follows the\ninstruction.\n\nThe code generated for while and if needs particular study.  When the\nkeyword `while` is encountered, the operation whilecode() is generated,\nand its position in the machine is returned as the value of the while\nproduction.  At the same time, however, the two following positions in\nthe machine are also reserved, to be filled in later.   The next code\ngenerated is the expression that makes up the condition part of the\n`while`.  After the whole `while` statement has been recognized, the\ntwo extra positions reserved after the `whilecode` instruction are\nfilled with pointers to the locations of the loop body and the statement\nthat follows the loop.  Code generated for `for` and `if` works similar.\n\nYou can compile with -DDEBUG=1 for hoc to print the generated machine\ncode after it is generated.\n\nStrings used as values are allocated in two linked-lists of strings.\n`autostrings` contains strings that appears during evaluation as the\nresult of an expression.  Strings in `autostrings` are freed after each\nexecution.  `finalstrings` contain strings that are the value of a\nvariable, and thus should not be freed.\n\nDifferent from the book, where symbols are used for variables, keywords,\nbuilt-in functions, etc, in this implementation there is two different\nstructures, Name and Symbol.  The first is looked up while the input is\nbeing read, while Symbols are looked up during execution.\n\nNames for variable, functions and keywords are installed in a name\ntable.  There is a global name table, used for keywords, function\nnames and global variable names; and a name table for each function\ndefinition, used for local variables.\n\nWhen a variable is evaluated, it is looked up in a symbol table, which\nassociate names with values.  There is a global symbol table, for global\nvalues; and one symbol table for each function frame, containing\nautomatic values.\n\n\n§ SEE ALSO\n\nThe UNIX Programming Environment,\nby Brian W. Kernighan and Rob Pike,\nPrentice Hall, 1984.\nISBN: 0-13-937681-X.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphillbush%2Fhoc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphillbush%2Fhoc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphillbush%2Fhoc/lists"}