Skip to content
phillbush edited this page Jan 27, 2021 · 9 revisions

HOC(1)

NAME

hoc - interpreter for floating point arithmetic language

SYNOPSIS

hoc [ file [ argument ... ]]

DESCRIPTION

Hoc interprets a simple language for floating point arithmetic, at about the level of BASIC. It has C-style control flow, function definition and the usual numerical built-in functions such as cosine and logarithm.

Hoc reads input from its standard input by default. If a filename is specified as argument, input is read from this file instead. If filename is - (a dash), input is read from standard input instead.

Hoc provides no interactive command line editing features. For using those features, use a shell wrapper, such as rlwrap(1).

Hoc input consists of expressions, statements, and function/procedure definitions . Expressions are evaluated and their results printed (except assignment expressions, whose result are not printed). Statements, typically control flow statements, produce no output unless they explicitly call print or printf. Function definitions produce no output. Blank lines and comments (contained between # and the next newline) are ignored.

Expressions

An expression can be a number constant, a string literal, a variable name, a function call, a reading expression, or a compound expression (made of expressions and operators). An expression can be surrounded by parentheses (in order to change the precedence of its operators, for example). A sequence of expressions can be written delimited with a , (comma). Every expression has a numeric or string value; if a string value is used where a numeric value is expected, this string is first converted to number using atof(3). A sequence of expressions always has the value of the last expression. logical expressions have value 1.0 (true) and 0.0 (false). As in C, any nonzero value is taken to be true.

Number constants can be expressed in the decimal notation (12.345), or in the decimal scientific notation (12.345e-67). The number format is that recognized by atof(3) and scanf(3).

String literals are strings of characters surrounded by double quotes. Backslash escapes are used to include a special character in a string. The following is a list of supported backslash escapes and the character they represent.

  • \

    Literal backslash.

  • "

    Double quote.

  • '

    Single quote.

  • \a

    Alert (bell).

  • \b

    Backspace.

  • \f

    Form feed.

  • \n

    Newline (line feed).

  • \r

    Carriage return.

  • \t

    Horizontal tab.

  • \v

    Vertical tab.

Variable names consist of alpha-numeric characters and the symbol _ (underscore), but cannot begin with a number, and cannot have the same name as a statment keyword or a function. There is an exception to this rule: the special variable . (period), which cannot be assigned to and always evaluates to the last printed value. Variables can be assigned with one of the assignment operators, but cannot be used in a non-assignment expression unless previously defined.

Function calls consist of a function name followed by a comma-delimited list of arguments in parentheses (fun(a, b, c)). All function arguments are passed by value, including strings. A function can be nullary (have no argument), unary (have one arguments), binary (have two arguments), etc. A nullary function must be followed by an empty list of arguments (such as fun()). Some functions, called built-in functions, are already defined in hoc; they are listed bellow.

  • deg()

    Returns the constant value of pi.

  • e()

    Returns the constant value of the base of natural logarithms.

  • gamma()

    Returns the constant value of the Euler-Mascheroni constant.

  • phi()

    Returns the constant value of the golden ratio.

  • pi()

    Returns the constant value of pi.

  • rand()

    Returns a random value between 0 and 1.

  • abs(x)

    Returns the absolute value of x.

  • atan(x)

    Returns the arctangent of x.

  • cos(x)

    Returns the cosine of x.

  • exp(x)

    Returns the exponential of x.

  • int(x)

    Returns the integer part of x, truncated towards zero.

  • log(x)

    Returns the natural logarithm of x.

  • log10(x)

    Returns the logarithm base 10 of x.

  • sin(x)

    Returns the sin of x.

  • sprintf(fmt, ...)

    Returns a string resulting from formatting expressions given as argument, according to the printf(1) format fmt.

  • sqrt(x)

    Returns the square root of x.

  • atan2(y, x)

    Returns the angle whose tangent is y/x.

Operators can be used to create a new expression from existing ones. An operator can be unary (use a single expression) or binary (use two expressions). The operators, in decreasing order of precedence, are listed below; operators listed together have the same precedence. All operators expect a numeric value and will convert strings to numbers as needed. All operators are binary and associate from left to right, unless explicitly stated otherwise.

  • $

    (unary, right associative) Access command-line arguments. $1 is the first command-line argument, $2 is the second, and so on. $0 is the name of the input file. If a value greater than the number of command-line argument is used, returns 0.0 instead.

  • ^

    (right associative) Exponentiation.

  • ! - + -- ++

    (unary, right associative) Logical negation, unary minus, unary plus, decrement operator, and increment operator. The decrement and increment operators have the prefix and postfix form.

  • * / %

    Multiplication, division, and modulus.

  • + -

    Addition and subtraction.

  • < >= < <=

    Relational operators (greater than, greater than or equal, less than, and less than or equal).

  • == !=

    Equality operators (equal to, and not equal to). As is always the case with floating point numbers, equality comparisons are inherently suspect.

  • &&

    Logical AND.

  • ||

    Logical OR.

  • = += -= *= /= %=

    (right associative) Assignment operators. They all return the result of the assignment.

  • ,

    Comma (used to group expressions).

Reading expressions are used to read a value from the standard input into a variable. There are two reading expressions, introduced by the keywords read and getline, and followed by the name of a variable. The return value of a read expression is 1.0 (true) if a value was read, and 0.0 (false) if it encountered end-of-file or an error.

  • read VAR

    Read a number from the stadard input into the variable VAR.

  • getline VAR

    Read a string from the stadard input into the variable VAR.

Statements

A statement can be an expression, a compound statement, a print statement, a procedure call, a printf statement, a control flow statement, or a procedure or function definition statement. A statement must be terminated by a newline or a semi-colon. A compound statement is a list of statements enclosed in curly braces (this list can be empty). A procedure call is like a function call, but for procedures.

A print statement consists of the word print followed by a comma-delimited list of expressions. A print statement prints the value of each expression separated by a space and ending with a newline. A print statement does not cause the . (period) variable to be updated.

A printf statement consists of a word printf followed by a comma-delimited list of expressions. The first expression (called format) must be a format string as specified in printf(1), and the following expressions must match in number the number of format specifications in the format. A printf statement does not cause the . (period) variable to be updated.

The following is a list of control flow statements.

  • break

    A break statement may appear only within an iteration statement and causes the innermost enclosing loop statement to end.

  • continue

    A continue statement may appear only within a loop statement and causes control to pass to the loop-continuation portion of the innermost enclosing loop statement.

  • do STMT while (EXPR)

    A do-while statement is a loop statement that runs STMT first, and then passes control to STMT repeatedly so long as EXPR evaluates to nonzero (true).

  • for (EXPR1; EXPR2; EXPR3) STMT

    A for statement is a loop statement that evaluates EXPR1, and then passes control to STMT repeatedly so long as EXPR2 evaluates to nonzero (true); EXPR3 is evaluated after each iteration. EXPR1 can be omitted, in which case no expression is evaluated before the loop begins. EXPR2 can be omitted, in which case the loops runs ad infinitum. EXPR3 can be omitted, in which case no expression is evaluated after each iteration. In any case, if any expression is omitted, all semi-colons must be present.

  • if (EXPR) STMT

    An if statement is a selection statement that causes the control to pass to the statement STMT if the expression EXPR is nonzero.

  • if (EXPR1) STMT1 else (EXPR2) STMT2

    An if-else statement is a selection statement that causes the control to pass to the statement STMT1 if the expression EXPR1 is nonzero, or to STMT2 if EXPR1 is zero and EXPR2 is nonzero.

  • return

    A return statement that does not return a value may appear only within a procedure statement and causes the procedure to return.

  • return EXPR

    A return statement that returns a value may appear only within a function statement and causes the function to return with the value of the expression EXPR.

  • while (EXPR) STMT

    A while statement is a loop statement that passes control to STMT repeatedly so long as EXPR evaluates to nonzero (true).

Function and procedure definition

A function or procedure definition is a special statement used to define a function or a procedure. Functions and procedures are distinct in hoc, although they are defined by the same mechanism. This distinction is simply for run-time error checking: it is an error for a procedure to return a value, and for a function not to return one. A function or procedure definition must not occur inside another statement. Function calls are expressions; procedure calls are statements;

The syntax of function and procedure definitions is explained below.

  • func NAME(PARAMS) STMT

    Defines the function NAME, with the parameters PARAM, as the statement STMT. NAME must be a valid name for a variable that is not used by an variable or another function. PARAM must be a comma-delimited list of variable names that are local to the function. STMT must be a statement in which a return statement occurs.

  • proc NAME(PARAMS) STMT

    Defines the procedure NAME, with the parameters PARAM, as the statement STMT. NAME must be a valid name for a variable that is not used by an variable or another function. PARAM must be a comma-delimited list of variable names that are local to the function. STMT must be a statement.

Both functions and procedures define a list of local variables (their parameters). Those variables cannot be accessed outside the function or parameter; and are different from the ones with the same name in the global scope. As in awk(1), a function or procedure can be called with less arguments than the number of parameters it has. In this case, the remaining parameters are local variables initialized to 0.0.

EXIT STATUS

  • 0

    Success.

  • >0

    Error occurred.

EXAMPLES

The code below is an example of input for hoc.

func gcd(a, b, tmp) {
	tmp = abs(a) % abs(b)
	if (tmp == 0)
		return abs(b)
	return gcd(b, tmp)
}
for (i = 1; i < 12; i++)
	printf "gcd(%d, 12) = %d\n", i, gcd(i, 12)

The following is the output the program above.

gcd(1, 12) = 1
gcd(2, 12) = 2
gcd(3, 12) = 3
gcd(4, 12) = 4
gcd(5, 12) = 1
gcd(6, 12) = 6
gcd(7, 12) = 1
gcd(8, 12) = 4
gcd(9, 12) = 3
gcd(10, 12) = 2
gcd(11, 12) = 1

SEE ALSO

bc(1), dc(1)

Brian W. Kernighan, and Rob Pike, The UNIX Programming Environment , Prentice Hall, 1984.

HISTORY

A hoc utility first appeared in the book The UNIX Programming Environment by Brian Kernighan and Rob Pike.

The following is a list of extensions of this implementation, that do not appear in the book, or appear in the book as an exercise.

  • The modulus and unary plus operators.
  • The . (period) variable, which evaluates to the last printed value.
  • Semicolons as statement terminators.
  • The rand() and the atan(y,x) built-in functions.
  • The assignment operators += , -= , *= , /= , and %= .
  • The increment and decrement operators ++ and --.
  • Short-circuit evaluation of the logical operators && and || (in the book, both sides of the operator are always evaluated, as it had no left-to-right evaluation or early termination).
  • The for control-flow statement, with expressions that can be omitted.
  • The break and continue control-flow statements.
  • Named formal parameters instead of $1, etc.
  • Local variables (the same way awk(1) does).
  • The print and printf statements; and the sprintf built-in function.
  • Do-while statements.
  • Access to command-line arguments.
  • Support for comments.
  • Support for expression list (list of expressions separated by comma).
  • Support for assigning strings to variables.
  • Support for converting strings to numbers.
  • Support for escaping line breaks.

BUGS

Different from the book, this implementation does not have constant values, such as PI. There are, instead, correspondent nullary functions, such as pi().

Different from the book, in which the print statement produces no newline at the end, the print statement of this implementation works like the one in awk(1), that is, it produces a newline at the end. For producing no newline, use the printf statement instead.