Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

__label__ LABEL must precede all other declarations in a block #44

Closed
pbreuer opened this issue Dec 28, 2017 · 2 comments
Closed

__label__ LABEL must precede all other declarations in a block #44

pbreuer opened this issue Dec 28, 2017 · 2 comments

Comments

@pbreuer
Copy link

pbreuer commented Dec 28, 2017

I had occasion to need local label declarations a la gcc, and noticed that the parser (sorry, tell me how to tell what version I have and I'll tell you) only accepts _ _ label _ _ LABEL if it's at the very start of a block. Anything before it, declaration or otherwise, and one gets "user error" from the parser.

So I fixed it. I'm just mailing this before I forget in the hope that you can use the fix, better it, or say it's already been fixed in the latest version.

You need to look at Parser.y where the original definition of compound statement is
...
compound_statement
: '{' enter_scope block_item_list leave_scope '}'
{% withNodeInfo $1 $ CCompound [] (reverse $3) }
| '{' enter_scope label_declarations block_item_list leave_scope '}'
{% withNodeInfo $1 $ CCompound (reverse $3) (reverse $4) }
...
I've bold-faced where the label declaration stuff is, and as you can see it's set to be before the block_item stuff, which is either declaration of statement, repeated. So there is no mistake. It's set up as I described.

Now it's notionally easy to fix this. Just broaden your definition of block items in the AST to admit label declarations as an extra kind of item, and practically that's hey presto and done. You'd have to modify the definition of CCompound in the AST to match, to make it take just block item list as an argument, and not label declarations and block items.

But that's got way to many ramifications for me to countenance, as the AST is exported and so you are practically stuck with it, silly as it is in places! (what's with not really parsing declarators at all, just delivering what is practically a stream of tokens in the AST? But I digress ...). Other people may rely on the AST staying the way it is.

OK, no problem, we can loosen the parse to allow mixed label declarations and the existing block items, just as they are, and trivially pick the two apart out of the mixed list for the existing CCompound constructor to use. That's what I'll do.

So start by erasing that second alternative from block parse, the one that fixed label declarations as having to come first:
...
RM | '{' enter_scope label_declarations block_item_list leave_scope '}'
RM {% withNodeInfo $1 $ CCompound (reverse $3) (reverse $4) }
...
Now improve block_item to allow a label declaration by adding a new alternative, last:
...
ADD | "label" identifier_list ';' { Right $2 }
...
You'll notice I made it return a "Right", so the type has become an Either:
...
RM block_item :: { CBlockItem }
ADD block_item :: { Either CBlockItem (Reversed [Ident])}
...
One has to go through the existing block item parse alternatives and add a "Left" to what they return. Now we're good to go back to the amputated compound parse and fish out the bits from the mixed list of Lefts and Rights that it will now receive.
...
RM {% withNodeInfo $1 $ CCompound [] (reverse $3) }
ADD {% withNodeInfo $1 $ CCompound (rights $ reverse $3) (lefts $ reverse $3)
...
Here rights picks out the Right elements and lefts picks out the Left elements from the mixed list $3 that's been received from the block_item_list parse. Those are defined in the post-logue. I am sure you can write those!

You can better this by removing some of the Reverse/reverse constructs. I couldn't be bothered, as I was hacking to make it work, not make it beautiful. I'll append my diff file.
diffs.txt

Happy hunting!

@lambdageek
Copy link

lambdageek commented Jan 8, 2018

@pbreuer two notes

  1. GCC documentation on "local labels" says

    Local label declarations must come at the beginning of the block, before any ordinary declarations or statements.

  2. In your patch, you can use Data.Either.partitionEither :: [Either a b] -> ([a], [b]) instead of defining your own lefts, rights.

@visq
Copy link
Owner

visq commented Jun 4, 2018

@lambdageek, thanks for analysis.
As language-c behaves just as expected in (1), closing this issue.

@visq visq closed this as completed Jun 4, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants