Math Expression Parser Series Conclusion

Published: Friday, March 31, 2023
Updated: Monday, April 17, 2023

Greetings, friends! This is my final article in the math expression parser series. What a journey it's been! We've created a math expression parser in so many different ways and learned a lot about parsing. Let's review everything we've learned so far!

Summary of the Math Expression Parser Series

Welcome to the conclusion of the math expression parser series, friend! If you've stuck with me and read all 20 articles, I am certain your computer science skills have increased to a power level of over 9000!

As promised in Part 1 of this tutorial series, I have now taught SEVEN different ways of building math expression parsers:

  1. Reverse Polish Notation (RPN) Evaluator
  2. Shunting Yard Algorithm
  3. LR Parser Generator
  4. LL Parser Generator
  5. PEG Parser Generator
  6. Recursive Descent Parser
  7. Pratt Parser

Say goodbye to the evil eval function! You now have seven different options to choose from when building a math expression parser, and they're all much safer than using the eval function.

We learned how to make math expression parsers by hand and automatically through parser generators. While learning how to use the Syntax parser generator, we discovered how to read and create grammar files. These grammar files help us understand the "blueprint" or structure of a language. By passing the grammar files into a parser generator, we could create a math expression parser automatically.

Then, we learned how to use the Peggy parser generator and learned how to create a parsing expression grammar (PEG) with a syntax that is more representative of a recursive descent parser. We then applied our grammar skills to the construction of a grammar "blueprint" while building a recursive descent parser from scratch.

After dealing with the pains of exponentiation and unary operations, we learned that Pratt parsers exist and are considered one of the best ways to make a math expression parser or even an entire programming language.

In this tutorial series, we created multiple math expression parsers that all understand the following:

  1. Decimal Values
  2. Addition
  3. Subtraction
  4. Multiplication
  5. Division
  6. Parentheses
  7. Unary Operations (for negative numbers)
  8. Trigonometric functions (sin, cos, and tan)

We also created two versions of each parser:

  1. On-demand (or on the fly) parsers
  2. Abstract syntax tree (AST) parsers

The "on-demand" parsers will skip the AST step and directly perform an action or produce a result. For example, we built a math expression parser using the Pratt parsing algorithm to evaluate math expressions as soon as we had enough tokens to figure out which math expression to perform. We then built a Pratt parser that produced an AST as an intermediate step. For completeness, we even built an AST evaluator for each math expression parser, so we understood how a user might consume our ASTs.

Finally, we learned how to support variables in a math expression parser by building a custom programming language called "Tiny Math Language" or TML for short. We learned how to build a parser for "on-demand" parsing of TML code, and we learned how to create a TML interpreter that could execute .tml files containing our custom programming language syntax. We then built a parser to product an AST from a TML program. Then, we learned how to test and evaluate our AST, which differed from previous tutorials due to the addition of "statements".

Why We Parse

Parsing is an invaluable skill to have as a software engineer. We learned how to parse math expressions in order to take that small step into the world of programming language development and compiler theory. Understanding how compilers and interpreters work starts with parser development. There are so many programming languages out there with their own syntax, runtimes, style, and community. When people create new languages, they strive to find simpler solutions to problems and improve the developer experience (DX).

There are many libraries/frameworks out there in the JavaScript community. Here's a list of some of the most popular ones as of the time of this writing:

What do these all have in common? Parsers! Each framework starts with a parser! The developer envisions a new kind of syntax that might be fun or easier to work with. Then, they create a parser to parse tokens in that syntax.

How does Vue.js parse .vue files? How does React work with JSX? How does Svelte understand {#if expression} and {/if}? How does Babel know how to transpile new JavaScript into old JavaScript? They all have parsers.

Syntax Highlighting

One of my favorite applications of parsers is syntax highlighting. When I write code snippets in my tutorials, I use a syntax highlighter called Prism. For example, here's an example of JavaScript code.

js
Copied! ⭐️
const message = 'Parsers are amazing!';
console.log(message);

Here's an example using Rust:

rust
Copied! ⭐️
fn main() {
  println!("Parsers are awesome!");
}

Parsers make syntax highlighters possible. When you code using an online editor, you're most likely using either CodeMirror (used by CodePen) or Monaco (which powers the code editor in VS Code). These tools provide an interface for helping people create their own grammars to perform syntax highlighting on their own languages.

As of CodeMirror 6, we can make a Lezer grammar for syntax highlighting in the CodeMirror editor. For VS Code and the Monaco editor, we can build TextMate grammars for custom syntax highlighting.

The parser knowledge we gained in this tutorial series can help us syntax highlight anything! 🌈

Thank You!

Congrats, friend! You finally did it! You've reached the end of this 20-part tutorial series! 🥳🎉🎊

All of the finished code can be found on my GitHub page. To everyone who read this entire series, I want to express my deepest gratitude! 💚

Making a tutorial series with so many examples and so much depth takes a long time. I can see in my analytics that people are reading my website from so many different countries. It feels nice knowing so many people from different places found my website to learn about math expression parsers.

If you're feeling cherishable and moved by my hard work and dedication, I do have a donation page 😅. Every donation empowers me to continue blogging and create a new tutorial series. I love taking obscure or difficult topics and simplifying them down into an easy-to-understand way. I'll tear down those walls of complexity that block people from learning something fun!

Until next time, friends! Enjoy life and happy coding! ⭐