Engee documentation
Notebook

Calculating arithmetic expressions

This example demonstrates how you can use the built-in Julia parser to analyze and calculate arithmetic expressions.

Introduction

The calculation of arithmetic expressions is the process by which the string representation of a mathematical expression is transformed into a data structure that can be interpreted and calculated. It is a key element of many software systems, such as calculators, compilers, and interpreters.

This process usually involves two main steps:

  1. Parsing - converting a string into abstract syntactic дерево (AST)
  2. Calculation - traversing the tree and performing mathematical operations

This approach is used in:

  • Compilers and interpreters of programming languages
  • Mathematical calculators
  • Computer algebra systems
  • Analysis of mathematical expressions in scientific computing

Working with an expression in Julia

Julia provides built-in functions for working with expressions and calculating them. Function Meta.parse() converts a string with a code into an object of the type Expr (expression), which is an abstract syntax tree.

In [ ]:
# Defining a string with an arithmetic expression
expr = "2 * (3 -1) + 2 * 5"
Out[0]:
"2 * (3 -1) + 2 * 5"
In [ ]:
# Converting a string to an expression (AST)
parsed = Meta.parse(expr) # Julia provides low-level access to the language parser for creating AST/Expr
Out[0]:
:(2 * (3 - 1) + 2 * 5)

After parsing, we get an object of the type Expr, which is an abstract syntax tree (AST). This is a tree structure where each node corresponds to an operation or operand.

In [ ]:
# Getting the object type
t = typeof(parsed)
Out[0]:
Expr

An object of the type Expr has fields:

  • :head — node type (for example, addition operation :+)
  • :args — node arguments (operands)
In [ ]:
# Viewing Expr type fields
fieldnames(t) # shows fields of the type
Out[0]:
(:head, :args)

The main field for us is args, which contains the arguments of the expression.
For our expression, the first argument is an operation symbol. :+, and the rest of the arguments are subexpressions.

In [ ]:
# Let's explore the internal structure of the 'Expr' object
parsed.args # Inspecting the contents of the 'Expr' type
Out[0]:
3-element Vector{Any}:
 :+
 :(2 * (3 - 1))
 :(2 * 5)

As you can see, expressions can be nested. The second argument of our expression is also an object of type Expr.

In [ ]:
# The 'Expr' types can be nested
typeof(parsed.args[2])
Out[0]:
Expr
In [ ]:
# Looking at the arguments of the nested expression
parsed.args[2].args
Out[0]:
3-element Vector{Any}:
  :*
 2
  :(3 - 1)

Going deeper down the tree, we reach the most basic elements — numbers and simple operations.

In [ ]:
# We continue to descend to the lowest level of the AST
parsed.args[2].args[3].args # It will be invested up to the lowest AST level.
Out[0]:
3-element Vector{Any}:
  :-
 3
 1

Finally, when the tree is built, we can calculate the result using the function eval().

In [ ]:
# Calculating the expression
eval(parsed)
Out[0]:
14

Additional examples

Let's demonstrate how the algorithm works on other expressions.:

In [ ]:
# A more complex expression with division
eval(Meta.parse("1 - 5 * 2 / 20 + 1"))
Out[0]:
1.5
In [ ]:
# An expression with multiple levels of parenthesis nesting
eval(Meta.parse("2 * (3 + ((5) / (7 - 11)))"))
Out[0]:
3.5

Conclusion

We have reviewed the implementation of the algorithm for calculating arithmetic expressions in Julia, using the built-in language features for parsing and calculating expressions.

We succeeded:

  1. Convert the string representation of a mathematical expression into an abstract syntax tree (AST)

  2. Investigate the structure of the resulting tree

  3. Perform the calculation of the expression, taking into account the priority of operations and parentheses.

This approach is useful for:

  • Creation of mathematical calculators
  • DSL (Domain-specific languages) development
  • Building compilers and interpreters
  • Analysis and processing of mathematical expressions in scientific applications

The example was developed using materials from Rosetta Code