{"id":413285,"date":"2024-06-29T23:01:58","date_gmt":"2024-06-29T23:01:58","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=413285"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=413285","title":{"rendered":"<span>Lexical Analysis in 11l<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">This article discusses the lexical analyzer, which is an integral part of any compiler.<\/p>\n<p>  The task of the lexical analyzer is to split the source code of the program into tokens.<\/p>\n<p>  So for example the code  <\/p>\n<pre><code class=\"python\">print(1 + 2) <\/code><\/pre>\n<p>will be tokenized as<br \/>  <code>print<\/code>, <code>(<\/code>, <code>1<\/code>, <code>+<\/code>, <code>2<\/code> and <code>)<\/code><br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h3>Significance of indentation<\/h3>\n<p>  Historically, compilers for most programming languages <abbr title=\"as there are no whitespace tokens\">strip away<\/abbr> all whitespace characters such as space, tab, and newline.<br \/>  What does this mean? It means the compiler sees the source code like this:  <\/p>\n<pre><code class=\"cpp\">if (foo)    if (bar)       m1(); else    m2(); <\/code><\/pre>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2193<br \/>  <code>if<\/code>, <code>(<\/code>, <code>foo<\/code>, <code>)<\/code>, <code>if<\/code>, <code>(<\/code>, <code>bar<\/code>, <code>)<\/code>, <code>m1<\/code>, <code>(<\/code>, <code>)<\/code>, <code>;<\/code>, <code>else<\/code>, <code>m2<\/code>, <code>(<\/code>, <code>)<\/code>, <code>;<\/code><\/p>\n<p>  This code is taken from <a href=\"https:\/\/github.com\/rsdn\/nemerle\/wiki\/The-basics-(tutorial)#Rewriting_Line_Counter_without_the_loop\" rel=\"nofollow noopener noreferrer\">the Nemerle programming language documentation<\/a>. It contains a so-called dangling else bug: when looking at this code, you might think that the \u201celse\u201d branch refers to the condition \u201cfoo\u201d, whereas in programming languages with C-like syntax (including C++, C#, Java and others) the \u201celse\u201d branch refers to the condition \u201cbar\u201d.<br \/>  As a solution to this problem, the developers of the Nemerle language introduced a rule that an \u201cif\u201d statement must always have an \u201celse\u201d branch, and if the \u201celse\u201d branch is not required, then the \u201cwhen\u201d statement should be used instead of \u201cif\u201d.<br \/>  In many new programming languages, such as Swift, Rust, and Go, the use of curly braces is mandatory even if the body of the \u201cif\u201d <font color=\"#BFBFBF\">[<\/font><font color=\"gray\">or other control statement<\/font><font color=\"#BFBFBF\">]<\/font> is only one line. When curly braces are used, the problem disappears:  <\/p>\n<pre><code class=\"cpp\">if (foo) {    if (bar) {       m1();    } } else {    m2(); } <\/code><\/pre>\n<p>  Some coding standards, for example those <a href=\"https:\/\/docs.oracle.com\/cd\/E12517_01\/back_office\/pdf\/141\/html\/pos_impg2\/developmentstandards.htm\" title=\"&lt;- google:\u2018oracle coding standard\u2019\" rel=\"nofollow noopener noreferrer\">from Oracle<\/a>, <a href=\"https:\/\/stanford.edu\/class\/archive\/cs\/cs106b\/cs106b.1158\/styleguide.shtml\" title=\"&lt;- https:\/\/tproger.ru\/translations\/stanford-cpp-style-guide\/ &lt;- google:\u2018c++ code style\u2019\" rel=\"nofollow noopener noreferrer\">from Stanford University<\/a> or <a href=\"https:\/\/wiki.sei.cmu.edu\/confluence\/display\/c\/EXP19-C.+Use+braces+for+the+body+of+an+if,+for,+or+while+statement\" rel=\"nofollow noopener noreferrer\">Carnegie Mellon University<\/a>, require the bodies of \u201cif\u201d and \u201celse\u201d statements to be enclosed in curly braces, to avoid the possibility of this bug:  <\/p>\n<pre><code class=\"cpp\">int login;  if (invalid_login())     login = 0; else     printf(\"Login is valid\\n\");     login = 1; <\/code><\/pre>\n<p>Here the line <code>login = 1;<\/code> will be executed in any case, no matter what value is returned by the <code>invalid_login<\/code> function.<\/p>\n<p>  But in both of the above cases, the problem is not at all that \u201cif\u201d <font color=\"#BFBFBF\">[<\/font><font color=\"gray\">allowing an \u201celse\u201d branch to be either absent or present<\/font><font color=\"#BFBFBF\">]<\/font> expresses the wrong logic, or even that the curly braces were forgotten: it is\u2026 the discrepancy between the way this code is perceived by the human programmer and by the compiler. A human being perceives block boundaries visually, using indentation as a guide; but the compiler makes use of symbols <font color=\"#BFBFBF\">[<\/font><font color=\"gray\">which a human hardly notices<\/font><font color=\"#BFBFBF\">]<\/font>. What is more, the compiler <font color=\"#BFBFBF\">[<\/font><font color=\"gray\">for C\/C++, C#, Java, Nemerle, etc.<\/font><font color=\"#BFBFBF\">]<\/font> treats all whitespace characters in the same way, and, thus, completely ignores the indentation. This is where <b>the root of the problem lies: the compiler and the human see code like this differently<\/b>.<\/p>\n<p>  And to solve this problem, the compiler must somehow take indentation into account <font color=\"#BFBFBF\">[<\/font><font color=\"gray\">so that the code examples given earlier either work as the programmer expects, or give an error at the compilation stage (or at least a <a href=\"https:\/\/developers.redhat.com\/blog\/2016\/02\/26\/gcc-6-wmisleading-indentation-vs-goto-fail\" title=\"&lt;- google:\u2018Wmisleading-indentation\u2019\" rel=\"nofollow noopener noreferrer\">warning<\/a>)<\/font><font color=\"#BFBFBF\">]<\/font>.<\/p>\n<p>  For this reason, it was decided to provide the new programming language 11l with a lexical analyzer that takes indentation into account.<\/p>\n<p>  Now let&#8217;s look at the implementation process. A brief description of the algorithm for parsing indentation is given in the <a href=\"https:\/\/docs.python.org\/reference\/lexical_analysis.html#indentation\" rel=\"nofollow noopener noreferrer\">Python programming language documentation<\/a>. In short, the algorithm works like this: at the beginning of each line, the indentation level is compared to the value on the top of a special stack. If it is larger, then it is pushed onto the stack and the lexer generates an INDENT token. If it is smaller, then all values exceeding the current line indentation level are removed from the stack and a DEDENT token is generated for each value removed. Further, at the end of the source file, a DEDENT is generated for each value remaining on the stack.<\/p>\n<p>  In addition to the fact that the lexical analyzer of the 11l language takes indentation into account, like the lexical analyzer of the Python language, the new language adds support for curly braces, which makes it possible to write code on one line or without indentation:  <\/p>\n<div class=\"scrollable-table\">\n<table>\n<tr>\n<td>With indentation:  <\/p>\n<pre><code class=\"plaintext\">fn sum(a, b)    return a + b <\/code><\/pre>\n<p>On one line:  <\/p>\n<pre><code class=\"plaintext\">fn sum(a, b) {return a + b} <\/code><\/pre>\n<p>Without indentation:  <\/p>\n<pre><code class=\"plaintext\">fn sum(a, b) { return a + b } <\/code><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<\/div>\n<p>In addition, code can be written using both indention and curly braces.  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Here is how it works (in brief)<\/b>                         <\/p>\n<div class=\"spoiler_text\">The indentation levels stack (<code>indentation_levels<\/code>) in 11l, in contrast to the lexical analyzer of the Python language, stores not just the indentation level but also a flag that is set to true whenever a new block of code is formed by the symbol <code>{<\/code>, rather than by increasing the indentation level. The indentation level is then set to <code>-1<\/code>.<br \/>  The <code>{<\/code> character is immediately followed by a new, arbitrary {i.e. lowering the indentation level is allowed} indentation level {its level is set instead of <code>-1<\/code>}, which remains in effect up to the matching <code>}<\/code> character.<br \/>  Here is a <a href=\"https:\/\/github.com\/11l-lang\/_11l_to_cpp\/blob\/529675344a73eac5cb313b5e22ab11191f2a1493\/tokenizer.py#L212\" rel=\"nofollow noopener noreferrer\">link<\/a> to the corresponding source code.  <\/div>\n<\/p><\/div>\n<p>This solution is the most versatile, and will suit both those who prefer using curly braces and those who prefer indentation.<br \/>  All popular <a href=\"https:\/\/en.wikipedia.org\/wiki\/Indentation_style\" rel=\"nofollow noopener noreferrer\">indentation styles<\/a> are supported:  <\/p>\n<div class=\"scrollable-table\">\n<table>\n<tr>\n<th>Allman<\/th>\n<th>K&amp;R<\/th>\n<th>GNU<\/th>\n<\/tr>\n<tr>\n<td>\n<pre><code class=\"plaintext\">if x == y {     something()     somethingelse() } <\/code><\/pre>\n<\/td>\n<td>\n<pre><code class=\"plaintext\">if x == y {     something()     somethingelse() } <\/code><\/pre>\n<\/td>\n<td>\n<pre><code class=\"plaintext\">if x == y   {     something ()     somethingelse ()   } <\/code><\/pre>\n<\/td>\n<\/tr>\n<tr>\n<th>Whitesmiths<\/th>\n<th>Ratliff<\/th>\n<\/tr>\n<tr>\n<td>\n<pre><code class=\"plaintext\">if x == y     {     something()     somethingelse()     } <\/code><\/pre>\n<\/td>\n<td>\n<pre><code class=\"plaintext\">if x == y {     something()     somethingelse()     } <\/code><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<\/div>\n<p>  <\/p>\n<h3>Automatic line joining<\/h3>\n<p>  In addition to splitting the source code of a program into tokens, the lexical analyzer is also charged with determining statement boundaries. <font color=\"#BFBFBF\">[<\/font><font color=\"gray\">Although in some programming languages (like <a href=\"https:\/\/temperlang.dev\/design-sketches\/parsing-program-structure.html#syntactic-asi\" rel=\"nofollow noopener noreferrer\">JavaScript or Kotlin<\/a>) assistance from the parser is required.<\/font><font color=\"#BFBFBF\">]<\/font><\/p>\n<p>  Traditionally, a semicolon is used in C-like programming languages (C++, C#, Java, D) as a statement terminator. However, most new programming languages (e.g. Swift, Go, Kotlin, CoffeeScript, Nim, Julia, Crystal, and others) allow the semicolon to be omitted, by using the newline character as the end of a statement. <font color=\"#BFBFBF\">[<\/font><font color=\"gray\"><a href=\"https:\/\/elizarov.medium.com\/the-end-of-the-semicolon-era-60ab95e669ab\" rel=\"nofollow noopener noreferrer\">I am not the only one to have noticed this trend.<\/a><\/font><font color=\"#BFBFBF\">]<\/font><\/p>\n<p>  But the question then arises: when do two consecutive lines of source code represent parts of the single statement, and when are they two different statements? And different programming languages solve this problem in different ways.<\/p>\n<p>  Python <a href=\"https:\/\/docs.python.org\/3\/reference\/lexical_analysis.html#implicit-line-joining\" rel=\"nofollow noopener noreferrer\">uses<\/a> one simple rule for implicit line joining: if a line contains an unclosed parenthesis, square bracket, or curly brace, then it concatenates with following lines until all matching parentheses\/brackets\/braces are closed.<\/p>\n<p>  Go <a href=\"https:\/\/golang.org\/doc\/effective_go#semicolons\" rel=\"nofollow noopener noreferrer\">uses<\/a> the rule: if the newline comes after a token that could end a statement, then the statement is ended. However, this rule imposes significant restrictions on coding style.<br \/>  For example, in an \u201cif\u201d statement, the curly brace that opens a block must be on the same line \u2014 moving it down to the next line is not allowed. The \u201celse\u201d statement <a href=\"https:\/\/stackoverflow.com\/questions\/26371645\/unexpected-semicolon-or-newline-before-else-even-though-there-is-neither-before\" title=\"&lt;- google:\u2018go lang semicolons problem\u2019\" rel=\"nofollow noopener noreferrer\">must<\/a> also appear on the same line as the closing curly brace.  <\/p>\n<div class=\"scrollable-table\">\n<table>\n<tr>\n<th>Right<\/th>\n<th>Wrong<\/th>\n<\/tr>\n<tr>\n<td>\n<pre><code class=\"go\">if i &lt; f() {     g() }  <\/code><\/pre>\n<\/td>\n<td>\n<pre><code class=\"go\">if i &lt; f() {     g() } <\/code><\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<pre><code class=\"go\">if x &lt; 0 {     return -1 } else {     return 1 }  <\/code><\/pre>\n<\/td>\n<td>\n<pre><code class=\"go\">if x &lt; 0 {     return -1 } else {     return 1 } <\/code><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<\/div>\n<p>JavaScript uses a rather complex <a href=\"http:\/\/www.ecma-international.org\/ecma-262\/6.0\/index.html#sec-automatic-semicolon-insertion\" rel=\"nofollow noopener noreferrer\">system of rules<\/a> to carry out automatic semicolon insertion.  <\/p>\n<pre><code class=\"javascript\">a = 1 b = 2 <\/code><\/pre>\n<p>In this example, a semicolon will be automatically inserted at the end of the first line, since <code>a = 1 b = 2<\/code> <a href=\"https:\/\/slides.com\/evanyou\/semicolons\/#\/14\" rel=\"nofollow noopener noreferrer\">is not a valid statement<\/a>.<br \/>  However, in some cases a semicolon is not inserted, leading the code to function incorrectly.<\/p>\n<p>  For example, the following two lines of JavaScript code will be mistakenly joined into one.  <\/p>\n<pre><code class=\"javascript\">a = b + c [d, e] = [e, d] <\/code><\/pre>\n<p>  And in this example, on the contrary, a semicolon will be erroneously inserted immediately after <code>return<\/code>.  <\/p>\n<pre><code class=\"javascript\">return   \"something\"; <\/code><\/pre>\n<p>That is, instead of returning a string <code>\"something\"<\/code>, the value <code>undefined<\/code> will be returned.<\/p>\n<p>  In most programming languages that allow semicolons to be omitted (for example, Python, Go, Kotlin, Ruby, Julia, and Nim), this code will not work:  <\/p>\n<pre><code class=\"plaintext\">r = 1   + 2 <\/code><\/pre>\n<p>Moreover, in Python, Go and Nim an error message will be displayed, while in Kotlin, Ruby and Julia the value of the variable <code>r<\/code> will be set to <code>1<\/code>.<\/p>\n<p>  To solve this problem, 11l uses the following 3 simple rules that are easily understood by both the programmer and the lexical analyzer:  <\/p>\n<ol>\n<li>If a line ends with a binary operator, then it is joined with the next line.<\/li>\n<li>If a line begins with a binary operator, then it is joined with the previous line.<br \/> \n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">(It is necessary to check that it is not a unary operator!)<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">a = b ++i \/\/ the plus character at the beginning of this line should not be mistaken for the binary operator `+` <\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<li>And also, just as in Python, a newline within expressions in parentheses or square brackets is ignored.<\/li>\n<\/ol>\n<p>  <\/p>\n<pre><code class=\"plaintext\">\/\/ 1. if condition1 &amp; \/\/ this line will be joined with the next one,    condition2   \\\\ since it ends with the binary operator `&amp;`     some_func()  \/\/ 2. some_variable = 2               + 3 \/\/ this line will be joined with the previous one,                   \\\\ since it starts with the binary operator `+`  \/\/ 3. some_func(    \/\/ since this line includes an unclosed parenthesis, all    argument1, \\\\ subsequent lines will be joined until    argument2) \\\\ the parenthesis is closed <\/code><\/pre>\n<p>  <\/p>\n<h3>Semicolons<\/h3>\n<p>  While it is not necessary to use a semicolon to mark the end of statements in 11l, semicolons can be used to place multiple statements on one line:  <\/p>\n<pre><code class=\"plaintext\">a = 1; b = 2; c = 3 <\/code><\/pre>\n<p>  But, for example, in Python it is not obvious what this line of code corresponds to:  <\/p>\n<pre><code class=\"python\">if b: print(1); print(2) <\/code><\/pre>\n<p>  <\/p>\n<div class=\"scrollable-table\">\n<table>\n<tr>\n<td>This code in Python:<\/td>\n<td>\n<pre><code class=\"python\">if b:     print(1)     print(2) <\/code><\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>Or this:<\/td>\n<td>\n<pre><code class=\"python\">if b:     print(1) print(2) <\/code><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<\/div>\n<div class=\"scrollable-table\">\n<table>\n<tr>\n<td>This code in 11l:<\/td>\n<td>\n<pre><code class=\"plaintext\">if b {print(1); print(2)} <\/code><\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>Or this:<\/td>\n<td>\n<pre><code class=\"plaintext\">if b {print(1)}; print(2) <\/code><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<\/div>\n<p>Python&#8217;s behavior in this case is logical in principle, but not obvious.<br \/>  The behavior of 11l, by contrast, is both logical and obvious.<\/p>\n<p>  Furthermore, it is impossible to write a one-line function like this in Python:  <\/p>\n<pre><code class=\"python\">def f(x): if x: print(x) <\/code><\/pre>\n<p>But in 11l, it is possible:  <\/p>\n<pre><code class=\"plaintext\">fn f(x) {if x {print(x)}} <\/code><\/pre>\n<p>  <\/p>\n<h3>Always room for improvement<\/h3>\n<p>  In my <sub>anything but<\/sub> humble opinion, 11l implements the most advanced lexical analyzer of all currently existing programming languages. However, it can still be improved.<\/p>\n<p>  For example, the third automatic line joining rule could be dropped, to support code like this:  <\/p>\n<pre><code class=\"plaintext\">set_timeout(             1.0,             fn ()                alert(\u2018!\u2019)             ,             0            ) <\/code><\/pre>\n<p>In this case, the third rule must be replaced with the following two rules:  <\/p>\n<ul>\n<li>If a line ends with an opening parenthesis (<code>(<\/code>) or square bracket (<code>[<\/code>), or a comma (<code>,<\/code>), then it is joined with the next line.<\/li>\n<li>If a line begins with a closing parenthesis (<code>)<\/code>) or square bracket (<code>]<\/code>), then it is joined with the previous line.<\/li>\n<\/ul>\n<p>  But since at the moment 11l parser does not support constructs of this kind {in particular, anonymous functions are not supported <font color=\"#BFBFBF\">[<\/font><font color=\"gray\">instead, you can use &#171;arrow&#187; functions (for example, <code>(x, y) -> x + y<\/code>)<\/font><font color=\"#BFBFBF\">]<\/font>}, their implementation at the level of the lexical analyzer would make no practical sense.<\/p>\n<p>  In conclusion, I will provide links to the source code for the 11l lexical analyzer, which is available in three languages: <a href=\"https:\/\/github.com\/11l-lang\/_11l_to_cpp\/blob\/master\/tests\/python_to_cpp\/_11l_to_cpp\/tokenizer.py\" rel=\"nofollow noopener noreferrer\">Python<\/a>, <a href=\"https:\/\/github.com\/11l-lang\/_11l_to_cpp\/blob\/master\/tests\/python_to_cpp\/_11l_to_cpp\/tokenizer.11l\" rel=\"nofollow noopener noreferrer\">11l<\/a> and <a href=\"https:\/\/github.com\/11l-lang\/_11l_to_cpp\/blob\/master\/tests\/python_to_cpp\/_11l_to_cpp\/tokenizer.hpp\" rel=\"nofollow noopener noreferrer\">C++<\/a>.<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/663872\/\"> https:\/\/habr.com\/ru\/articles\/663872\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">This article discusses the lexical analyzer, which is an integral part of any compiler.<\/p>\n<p>  The task of the lexical analyzer is to split the source code of the program into tokens.<\/p>\n<p>  So for example the code  <\/p>\n<pre><code class=\"python\">print(1 + 2) <\/code><\/pre>\n<p>will be tokenized as<br \/>  <code>print<\/code>, <code>(<\/code>, <code>1<\/code>, <code>+<\/code>, <code>2<\/code> and <code>)<\/code>  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-413285","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/413285","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=413285"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/413285\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=413285"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=413285"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=413285"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}