5
$\begingroup$

I am designing a simple compiler for my university project. In my programming language, the break keyword is allowed.

I want to know whether break keyword occurs outside a loop should be a syntax error or semantic error. I want to know what is the best approach.

If it is a syntax error I can do it in the grammar file. But if it is a semantic one then I can do it in a pass. But I don't know which one is the better approach.

$\endgroup$
12
$\begingroup$

Both work, so how you do it is up to you. But there are a couple of reasons to consider doing it during a post-parse analysis:

  1. While it is certainly possible to define two different types of block, one in which break is legal and the other one in which it isn't, the result is a lot of duplication in the grammar, and a certain complication because you have to allow break inside blocks which are themselves contained inside a looping construct. If you allow compound statements without explicit blocks, like if (condition) break;, then you also need to define different if statements, etc. This rapidly gets out of hand unless you have a tagged formalism like that used in ECMAScript.

  2. Detecting the error in a post-parse scan will allow you to produce better error messages. Rather than just presenting the user with some kind of syntax error message (which might be "unexpected token 'break'"), you can actually provide a meaningful error message like "'break' statement cannot be used outside of a loop."

$\endgroup$
6
  • 1
    $\begingroup$ Short and sweet, thanks a lot!!! $\endgroup$ – Buddhika Chathuranga Mar 7 at 16:57
  • $\begingroup$ Syntax vs semantics, where to draw the line. My old lecturer quoted some PL guy saying 'all is semantics'. But that's a bit abstract, to answer your question directly, what @rici said. I am doing a biggish language and at the start pushed far too much of it into the BNF/parser. It caused additional work and ambiguity bugs, so instead I started to parse a little loosely then do a post-parse AST walk and validate() on each node. Working well for me. $\endgroup$ – user3779002 Mar 7 at 22:18
  • 1
    $\begingroup$ The obvious solution is just to make the break statement valid everywhere. (except in the outermost block of a function). There is no problem defining sensible semantics for what it does. It is problematic in the outer block of a function, because it seems like a synonym for "return" but the syntax can't easily specify a value to return. $\endgroup$ – alephzero Mar 8 at 3:17
  • $\begingroup$ @alephzero Assuming the language allows it, you'd probably make break in an outer block the same as hitting the end of the function without an explicit return. And if that's not allowed, a top-level break would throw a similar error as a return-less function. $\endgroup$ – TripeHound Mar 8 at 6:56
  • $\begingroup$ @alephzero "break" in the outer block of a function should obviously break the loop that this function was called from (a very useful behavior that fold/map usually don't support which is a shame). $\endgroup$ – Joker_vD Mar 8 at 7:36
0
$\begingroup$

You could do this purely in syntax - you’d have a grammar with two non-terminals for “statement that can contain a break” and one for “statement that may not contain a break”. You duplicate the size of the grammar, making it a right pain.

When you parse a break statement you need semantics anyway to determine what exactly it breaks from, since you may have nested loops and switch statements. Detecting that it has nothing to break from is a tiny part of that, so semantically it’s quite simple. You will save yourself some headache by doing this check in your semantics.

Of course you will use the syntax to prevent things like “x = break + 1;”.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.