{"id":4323,"date":"2026-03-06T19:07:43","date_gmt":"2026-03-06T16:07:43","guid":{"rendered":"https:\/\/demensdeum.com\/blog\/2026\/03\/06\/interpreter-in-practice\/"},"modified":"2026-03-06T19:41:37","modified_gmt":"2026-03-06T16:41:37","slug":"interpreter-in-practice","status":"publish","type":"post","link":"https:\/\/demensdeum.com\/blog\/2026\/03\/06\/interpreter-in-practice\/","title":{"rendered":"Pattern Interpreter in practice"},"content":{"rendered":"<p>In <a href=\"https:\/\/demensdeum.com\/blog\/2022\/06\/24\/pattern-interpreter\/\">last article<\/a> we looked at the theory of the Interpreter pattern, learned what an AST tree is and how to abstract terminal and non-terminal expressions. This time, let&#8217;s step away from the theory and see how this pattern is applied in serious commercial projects that we all use every day!<\/p>\n<p>Spoiler: <b>You may be using the Interpreter pattern right now, just by reading this text in your browser!<\/b><\/p>\n<p>One of the most striking and, perhaps, the most important examples of the use of this pattern in the industry is <b>JavaScript<\/b>. The language, which was originally created \u201con the knee,\u201d today works on billions of devices precisely thanks to the concept of interpretation.<\/p>\n<h2>10 days that changed the Internet<\/h2>\n<p>The history of JavaScript is full of legends. In 1995, Brendan Eich, while working at Netscape Communications, was given the task of creating a simple scripting language that could run directly in a browser (Netscape Navigator) to make web pages interactive. Management wanted something with a syntax similar to the then super popular Java, but intended not for professional engineers, but for web designers.<\/p>\n<p>Eich had only <b>10 days<\/b> to write the first prototype of the language, which was then called Mocha (then LiveScript, and only then JavaScript for marketing reasons). The rush was not accidental: Microsoft was hot on its heels, which at the same time was actively preparing its own scripting language <b>VBScript<\/b> for embedding in the Internet Explorer browser. Netscape urgently needed to release its response so as not to lose in the looming browser war.<\/p>\n<p>There was simply no time to write a complex compiler into machine code. The obvious and fastest solution for Eich was the architecture of the classic <b>Interpreter<\/b>.<\/p>\n<p>The first interpreter (SpiderMonkey) worked like this:<\/p>\n<ol>\n<li>It read the text source code of the script from the page.<\/li>\n<li>The lexical analyzer broke the text into tokens.<\/li>\n<li>The parser built an <b>Abstract Syntax Tree (AST)<\/b>. In terms of the Interpreter pattern, this tree consisted of <i>terminal expressions<\/i> (strings, numbers like 42) and <i>non-terminal<\/i> (function calls, statements like If, \u200b\u200bWhile).<\/li>\n<li>Then the virtual machine \u201ctraversed\u201d this tree step by step, executing the instructions embedded in it at each node (calling a method similar to Interpret()).<\/li>\n<\/ol>\n<h2>Context and Objects<\/h2>\n<p>Remember the Context object that we had to pass to the Interpret(Context context) method in the classic implementation? The interpreter needs it to store the current memory state.<\/p>\n<p>In the case of JavaScript, the role of this context at the top level is played by a <b>Global object<\/b> (for example, window in a browser). When your AST node tries to, say, write text to the screen via document.write(&#8220;Hello&#8221;), the interpreter accesses its context (the document object) and calls the desired internal browser API.<\/p>\n<p>It is thanks to the interpreter that JavaScript is able to interact so easily with the DOM (Document Object Model) &#8211; these are all just objects in a context that are accessed by tree nodes.<\/p>\n<h2>Evolution of the interpreter: JIT Compilation<\/h2>\n<p>Historically, JS in browsers has long remained a \u201cpure\u201d interpreter. And this had a big disadvantage &#8211; slow speed. Parsing the tree and slowly traversing each node each time the script was executed slowed down complex web applications.<\/p>\n<p>With the advent of Google&#8217;s <b>V8<\/b> engine (built into Chrome) in 2008, a revolution occurred. Engineers realized that one interpreter is not enough for the modern web. The engine has become more complex: it still builds the AST tree, but now uses <b>JIT (Just-In-Time) compilation<\/b>.<\/p>\n<p>Modern JS engines (V8, SpiderMonkey) work like a complex pipeline:<\/p>\n<ol>\n<li>The fast and dumb base interpreter starts executing your JS code instantly, without even waiting for it to compile (the classic pattern still works here).<\/li>\n<li>In parallel, the engine monitors \u201chot\u201d sections of code (loops or functions that are called thousands of times).<\/li>\n<li>These sections are compiled by the JIT compiler directly into optimized machine code, bypassing the slow interpreter.<\/li>\n<\/ol>\n<p>It was this combination of the instant start of the interpreter and the computing power of compilation that allowed JavaScript to take over the world, becoming the language of servers (Node.js) and mobile applications (React Native).<\/p>\n<h2>Interpreter in the gaming industry<\/h2>\n<p>Despite the dominance of C++ in heavy computing, the Interpreter pattern is an industry standard in game development for creating game logic. For what? So that game designers can make games without the risk of \u201cdropping\u201d the engine or the need to constantly recompile it.<\/p>\n<p>An excellent historical example is <b>UnrealScript<\/b> &#8211; the language in which the logic of the Unreal Tournament and Gears of War games was written in Unreal Engine 1, 2 and 3. The text was compiled into compact abstract machine bytecode, which was then step by step (interpreted) by the engine&#8217;s virtual machine.<\/p>\n<h3>Visual graph scripts (Blueprints)<\/h3>\n<p>Today, text has been replaced by visual programming &#8211; the <b>Blueprints<\/b> system in Unreal Engine 4 and 5.<\/p>\n<p>If you&#8217;ve ever opened a Blueprint in Unreal Engine, you&#8217;ve seen a lot of Nodes connected by wires. Architecturally, <b>the entire Blueprints graph is a huge Abstract Syntax Tree (AST)<\/b> drawn on the screen:<\/p>\n<ol>\n<li><b>Terminal Expressions:<\/b> Constant nodes. For example, a node that simply stores the number 42 or a string. They return a specific value when interpreted.<\/li>\n<li><b>Non-Terminal Expressions:<\/b> Compute nodes (Add) or flow control nodes (Branch). They have argument inputs, which the interpreter first evaluates recursively before producing the result as an output pin.<\/li>\n<\/ol>\n<p>And the role of context here is played by the memory of an instance of a specific game object (Actor). The Interpreter Machine safely \u201cwalks\u201d through this graph, requesting data and performing transitions.<\/p>\n<h2>Where else is the Interpreter used?<\/h2>\n<p>The interpreter pattern can be found in almost any complex system where dynamic instructions need to be executed. Here are just a few examples from commercial software:<\/p>\n<ul>\n<li><b>Interpreted programming languages \u200b\u200b(Python, Ruby, PHP).<\/b> Their entire runtime is based on the classic pattern. For example, the CPython reference implementation first parses your .py script into an AST, compiles it into bytecode, and then a huge virtual machine (compute loop) interprets that bytecode step by step.<\/li>\n<li><b>Java Virtual Machine (JVM).<\/b> Initially, Java code is compiled not into machine instructions, but into bytecode. When you run the application, the JVM acts as an interpreter (albeit with aggressive JIT compilation, just like in V8).<\/li>\n<li><b>Databases and SQL<\/b> When you issue an SQL query (SELECT * FROM users) in PostgreSQL or MySQL, the database engine acts as an interpreter. It performs lexical analysis, builds an AST query tree, generates an execution plan, and then literally \u201cinterprets\u201d this plan by iterating over the rows of the tables.<\/li>\n<li><b>Regular expressions (RegEx).<\/b> Any regular expression engine internally parses a string pattern (for example, ^\\d{3}-\\d{2}$) into a state graph (NFA\/DFA Automata), which the internal interpreter then passes through, matching each input character with the vertices of this graph.<\/li>\n<li><b>Unity Shader Graph<\/b> \/ <b>Unreal Material Editor<\/b> &#8211; interpret visual nodes into modular shader code (GLSL\/HLSL).<\/li>\n<li><b>Blender Geometry Nodes<\/b> &#8211; interpret mathematical and geometric operations to procedurally generate 3D models in real time.<\/li>\n<\/ul>\n<h2>Total<\/h2>\n<p>The Interpreter pattern has long gone beyond the scope of \u201cwriting your own calculator\u201d. This is the most powerful industry standard. From JavaScript engines that execute gigabytes of code behind the scenes of browsers every day, to game designers that allow you to build complex logic without knowledge of C++, interpreters remain one of the most important architectural concepts in modern IT development.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In last article we looked at the theory of the Interpreter pattern, learned what an AST tree is and how to abstract terminal and non-terminal expressions. This time, let&#8217;s step away from the theory and see how this pattern is applied in serious commercial projects that we all use every day! Spoiler: You may be<a class=\"more-link\" href=\"https:\/\/demensdeum.com\/blog\/2026\/03\/06\/interpreter-in-practice\/\">Continue reading <span class=\"screen-reader-text\">&#8220;Pattern Interpreter in practice&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[61,52],"tags":[],"class_list":["post-4323","post","type-post","status-publish","format-standard","hentry","category-techie","category-tutorials","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"en","enabled_languages":["en","ru","zh","de","fr","ja","pt","hi"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"ru":{"title":true,"content":true,"excerpt":false},"zh":{"title":true,"content":true,"excerpt":false},"de":{"title":true,"content":true,"excerpt":false},"fr":{"title":true,"content":true,"excerpt":false},"ja":{"title":true,"content":true,"excerpt":false},"pt":{"title":true,"content":true,"excerpt":false},"hi":{"title":false,"content":false,"excerpt":false}}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/posts\/4323","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/comments?post=4323"}],"version-history":[{"count":2,"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/posts\/4323\/revisions"}],"predecessor-version":[{"id":4325,"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/posts\/4323\/revisions\/4325"}],"wp:attachment":[{"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/media?parent=4323"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/categories?post=4323"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/wp-json\/wp\/v2\/tags?post=4323"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}