{"id":23,"date":"2022-10-12T13:52:24","date_gmt":"2022-10-12T13:52:24","guid":{"rendered":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/?p=23"},"modified":"2022-10-12T13:52:24","modified_gmt":"2022-10-12T13:52:24","slug":"an-ebnf-auto-completion-parser","status":"publish","type":"post","link":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/2022\/10\/12\/an-ebnf-auto-completion-parser\/","title":{"rendered":"An EBNF Auto-Completion Parser"},"content":{"rendered":"\n<p>After 3 months of programming I decided it was time to tackle my very own &#8220;first project&#8221; and boy was it terrible. My scope was a scientific calculator with a front facing GUI and after coding about 1500 lines of rubbish I made, for a lack of better words, something. It wasn&#8217;t total trash, but was no where near user ready, had no test, glitches were present, and it never parsed the users input meaning someone could enter &#8220;5 + + + 5 &#8211; &#8211; &#8211; 5 ++ &#8221; which as we can tell is NOT an equation.<\/p>\n\n\n\n<p>The Spring of 2022 I was taking 2 classes, 1 being a software engineering class where I could make basically any project I wanted, so I decided to take a second go at my calculator. The second was a language fundamental class where in the first few weeks we tackled EBNF grammar. EBNF, for those unaware, is a context free grammar within the family of metasyntax notations. What this means is that an EBNF defines the structure of a language. For example<\/p>\n\n\n\n<p>&lt;main&gt;       ::== a &lt;animal&gt; &lt;action&gt;<br>&lt;animal&gt;     ::== ?&lt;adjective&gt; dog | cat | bird<br>&lt;adjective&gt; ::== big | small<br>&lt;action&gt;      ::== sits | walks<\/p>\n\n\n\n<p>With our grammar here, we start with &lt;main&gt;, &#8220;a &lt;animal&gt; &lt;action&gt;&#8221;. Next we can pull the animal, lets say cat. &#8220;A cat &lt;action&gt;&#8221;. Finally we pull our action, &#8220;A cat sits&#8221;. EBNF allows flexibility, for example if we pick dog instead of cat we can have &#8220;A dog sits&#8221; or &#8220;A big dog sits&#8221;. <\/p>\n\n\n\n<p>EBNF is used to define a programming languages syntax as well, and when a user compiles or interprets their code one thing that happens is it gets parsed in comparison with the EBNF syntax. If there is an intrusion, such as<br>if (x == y) :<br>    if (and or) :<br>a compiling error occurs. Some languages EBNFs span only a few hundred lines, others a couple thousand. <a href=\"https:\/\/docs.python.org\/3\/reference\/grammar.html\">Pythons<\/a> for example is just over 600 lines.<\/p>\n\n\n\n<p>So, what is the significance of bringing this up? Well, as I said above, my first calculators iteration allowed users to enter &#8221; 5 ++&#8221;&#8230; but I wanted to build a defined EBNF that restricted the inputs users could enter. So, I did.<\/p>\n\n\n\n<p>_ exp ::=<br>    =<br>    exp &#8216;+&#8217; term<br>    exp &#8216;-&#8216; term<br>    term<br><br>_term ::=<br>    term &#8216;*&#8217; factor<br>    term &#8220;\/&#8221; factor<br>    term &#8216;\/\/&#8217; factor<br>    term &#8216;%&#8217; factor<br>    factor<br><br>_factor ::=<br>    &#8216;(&#8216; exp &#8216;)&#8217;<br>    power<br><br>_power ::=<br>    digit &#8216;**&#8217; factor<br>    function<br><br>_function ::=<br>    [digit | function] [abs | sqrt | 1\/x | n! | 10^y |x^y | log | neg]<br>    digit<br><br>_digit ::=<br>    int &#8216;.&#8217; int<br>    int<br><br>_int ::=<br>    int int<br>    [0 | 1 | .. | 9]<br><br>These 20 sum lines of code encompass all user inputs into the calculator. Turns out, building the EBNF parser was the easy part, live parsing became the issue. What I mean by this is say the user presses &#8220;5&#8221;. &#8220;5&#8221; is valid, so we will move on. Next they enter &#8220;+&#8221;. &#8220;5 +&#8221; is not a valid sentence structure according to our EBNF, as in the simplest form an expression needs to be an &#8216;expression + term&#8217;, where &#8220;5 +&#8221; is just an &#8216;expression +&#8217;. <\/p>\n\n\n\n<p>So I had to build around predictability. If a user presses a button that can lead to a correct EBNF syntax, but isn&#8217;t quite there yet, my program assumed the user was going in the right direction and held off on marking it as incorrect syntax. But what if the user then presses &#8220;=&#8221; to solve with a &#8220;5 +&#8221;? Does this break my program and give to much power to the user? Not really. To combat this awkwardness of incomplete equations that follow EBNF partially up to a point I implemented an auto-completion function that would autofill an equation in accordance to the EBNF. So &#8220;5 + =&#8221; would become &#8220;5 + 5 =&#8221;. The user loses freedom when they try to bend grammatical rules. <\/p>\n\n\n\n<p>So, you may ask &#8220;then what if the user enters &#8220;-&#8221; after their &#8220;5 +&#8221;. That&#8217;s simple, we change the most recent operator, &#8220;+&#8221;, to a &#8220;-&#8220;. &#8220;5 -&#8220;. What if the user enters a function, say square()? We copy the &#8216;=&#8217; pattern and autofill, square(5+5), and this is also true for incomplete parentheses. Say &#8216;(&#8216; is entered, followed by a &#8216;)&#8217;. Our program throws a 0 in there for &#8216;(0)&#8217;. Its all about making sure that whatever is inside our equation line is following our EBNF rules. Originally, on my first go, a lot of this was if elif else statements following a very linear path, meaning I was only tackling edge cases directly. With my new iteration, the one including the EBNF, I was able to create rules and laws about how things worked and I literally saw 100&#8217;s of hard coded solutions turn into a few small functions that tackled the syntax rather than the event.<\/p>\n\n\n\n<p>This of course is a very brief and simple run down as 1) I feel I lack the ability to explain exactly how everything works beyond a brief abstraction, 2) the technicality comes into play with code, and I don&#8217;t want to just throw all my code up here. If you&#8217;re interested in seeing my 600 lines of EBNF, you can view it on <a href=\"https:\/\/github.com\/Bakaler\/Scientific_Calculator\/blob\/main\/m006_EBNF.py\">Github<\/a>. The whole project is <a href=\"https:\/\/github.com\/Bakaler\/Scientific_Calculator\">here<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>After 3 months of programming I decided it was time to tackle my very own &#8220;first project&#8221; and boy was it terrible. My scope was a scientific calculator with a front facing GUI and after coding about 1500 lines of rubbish I made, for a lack of better words, something. It wasn&#8217;t total trash, but [&hellip;]<\/p>\n","protected":false},"author":12737,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-23","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/posts\/23","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/users\/12737"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/comments?post=23"}],"version-history":[{"count":1,"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/posts\/23\/revisions"}],"predecessor-version":[{"id":24,"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/posts\/23\/revisions\/24"}],"wp:attachment":[{"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/media?parent=23"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/categories?post=23"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/solutionscometomeat2am\/wp-json\/wp\/v2\/tags?post=23"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}