Decoded: expr (coreutils)

[Back to Project Main Page]

Note: This page explores the design of command-line utilities. It is not a user guide.
[GNU Manual] [POSIX requirement] [Linux man] [FreeBSD man]

Logical flow of expr command (coreutils)

Summary

expr - evaluate expressions

[Source] [Code Walkthrough]

Lines of code: 1118
Principal syscall: None
Support syscalls: None
Options: 2 (--help and --version)

Descended from expr introduced in Version 7 UNIX (1979)
Added to Shellutils in November 1992 [First version]
Number of revisions: 173

The expr performs minimal parsing since the execution step is already a custom parser and expression evaluator. The utility makes use of the GNU Multiple Precision Library (GMP) during evaluation of numerical values

Helpers:
  • docolon() - Procedure for string and pattern matching
  • eval() - Handles the '|' binary operator
  • eval1() - Handles the '&' binary operator
  • eval2() - Handles comparison binary operators
  • eval3() - Handles addition and subtraction binary operators
  • eval4() - Handles multiplication, division, and modulus
  • eval5() - Handles colon matching (wrapper for docolon()
  • eval6() - Handles keyword operations
  • eval7() - Handles atomic operands and recursive expressions
  • freev() - Frees a value (VALUE type)
  • getsize() - Checks the size of an input number
  • int_value() - Gets a VALUE type for an input integer
  • looks_like_integer() - Tests an input string as a possible integer value
  • nextarg() - Advances argument pointer to the next argument
  • mbs_logical_cspn() - Seaches a string for a matching substring
  • mbs_logical_substr() - Gets a substring using an input position and length
  • mbs_offset_to_chars() - Gets the number of logical characters in a string
  • nomoreargs() - Checks if arguments are exhausted
  • null() - Tests if an input value is null or zero
  • printv() - Prints a value (VALUE type)
  • require_more_args() - Tests for and throws error for missing arguments
  • str_value() - Gets a VALUE type for an input string
  • toarith() - Forces an input value to an integer
  • tostring() - Forces an input value to a string
  • trace() - Evaluation trace (may be excluded)
Helpers for GMP operations:
  • mpz_add() - mpz_t type addition
  • mpz_fits_ulong_p() - Tests if an mpz_t will fit in to an unsigned int
  • mpz_get_ui() - Casts mpz_t to unsigned int
  • mpz_get_str() - Returns a pointer to a string from an mpz_t
  • mpz_mul() - mpz_t type multiplication
  • mpz_out_str() - Outputs a string using an mpz_t type
  • mpz_sign() - Test the sign of an mpz_t type
  • mpz_sub() - mpz_t type subtraction
  • mpz_tdiv_r() - Returns the remainder of a division
  • mpz_tdiv_q() - Returns the result of a division
External non-standard helpers:
  • die() - Exit with mandatory non-zero error and message to stderr
  • error() - Outputs error message to standard error with possible process termination

Setup

expr

defines a VALUE structure to manage the variety of atomic types that an expression may evaluate to. The key idea is that the values are either integers or strings. The former is stored using a GMP type while the latter is a generic pointer.

main() introduces one variable, v of type VALUE that holds the final return value of the operation


Parsing

The parsing stage for expr is nearly nonexistent since checking the command line is part of execution. The only serious check is the number of arguments - there must be at least one argument (an expression to evaluate)


Execution

The expr utility is conceptually simple. It attempts recursive evalution of expressions with 8 levels of operator precendence and left-associative behavior. Evaluating expressions may lead to more expression (subexpressions). There will be at least an lvalue, possibly an operator and rvalue if the lvalue isn't terminal. The process flow is thus:

  • Get the next expression
  • Evaluate the lvalue with the next level of precedence
  • Evaluate the operator
  • Evaluate the rvalue
  • Repeat until we run out of expressions

Failure cases:

  • Integer overflow
  • Mismatched argument types/counts
  • Arguments out of range
  • Regular expression failure
  • Unbalanced parenthese
  • String comparison failures
  • Non-integer arguments
  • Division by zero

All failures at this stage output an error message to STDERR and return without displaying usage help


[Back to Project Main Page]