Build a program with one simple GOTO

25

3

The XKCD GOTO comic

Your task is to build the largest program you can that uses exactly one GOTO, without which the entire program (or at least a huge chunk of it) must be completely restructured. The score is counted as the number of statements in your code that change places or are newly introduced (removing statements doesn't add to your score) when the code is restructured without the GOTO (others are allowed to challenge your restructuring by presenting a more elegant one). As this is code bowling, highest score wins.

Note: I do not claim any liability for velociraptor attacks by attempting this challenge.

Joe Z.

Posted 2013-02-23T20:09:44.580

Reputation: 30 589

2The one single goto seems problematic. Every C code I can think of that uses a single goto can be trivially changed to use structured constructs. Multiple gotos however... – Pubby – 2013-02-26T01:42:28.637

@Pubby's claim seems to hold against the current two solutions. Replacing goto with switch seems possible for both. – ugoren – 2013-02-26T07:44:04.827

@Pubby How many goto's would you need to create a workable solution? If the problem as currently stated is impossible, I can create an alternative problem. – Joe Z. – 2013-02-26T14:30:23.977

I think you're allowed to embed the cartoon, as long as there's a link too. – luser droog – 2013-02-28T04:07:43.867

1

It doesn't qualify, but I really did this.

– luser droog – 2013-02-28T04:10:26.797

Use ASM where you can't even remove the GOTO – l4m2 – 2018-04-05T07:26:15.163

Answers

11

C fizzbuzz

This solution runs around the idea of interrupts and label variables (gcc only, sorry). The program sets up a timer which periodically calls main, where we goto whichever place the last execution of our interrupt handler (main) told us we should.

I've never used timers or label variables before, so I think there is much to bowl here.

#include <sys/time.h>
#include <signal.h>
#include <stdio.h>

int main(int argc)
{
    static int run = 1;
    static int* gotoloc = &&init;
    static int num = 0;
    static int limit = 50;

    goto *gotoloc;
init:
    signal(SIGVTALRM, (void (*)(int)) main);
    gotoloc = &&loop;

    struct itimerval it_val;

    it_val.it_value.tv_sec = 0;
    it_val.it_value.tv_usec = 100000;
    it_val.it_interval.tv_sec = 0;
    it_val.it_interval.tv_usec = 100000;
    setitimer(ITIMER_VIRTUAL, &it_val, NULL);

    while(run);

loop:
    num = num + 1;
    run = num < limit;
    gotoloc = &&notfizz + (&&fizz - &&notfizz) * !(num % 3);
    return 1;

fizz:
    printf("fizz");
    gotoloc = &&notbuzz + (&&buzz - &&notbuzz) * !(num % 5);
    return 1;

notfizz:
    gotoloc = &&notfizzbuzz + (&&buzz - &&notfizzbuzz) * !(num % 5);
    return 1;

buzz:
    printf("buzz\n");
    gotoloc = &&loop;
    return 1;

notbuzz:
    printf("\n");
    gotoloc = &&loop;
    return 1;

notfizzbuzz:
    printf("%d\n", num);
    gotoloc = &&loop;
    return 1;
}

shiona

Posted 2013-02-23T20:09:44.580

Reputation: 2 889

run should be declared volatile, otherwise while(run) can be "optimized" to while(1). Or instead, just goto somewhere that calls exit. – ugoren – 2013-02-26T07:41:29.023

@ugoren Good point. I turned on optimizations (O1, O2 and Os) and all those broke the program. Unfortunately just adding 'volatile' in front of run, gotoloc and num did not fix it. It might be gcc is not built for optimizing this kind of code. – shiona – 2013-02-26T07:55:02.843

Defining volatile int num outside of main should do it. With static, gcc thinks it knows who can mess with it. – ugoren – 2013-02-26T12:12:24.703

unfortunately I can't create gotoloc outside the main, or I could, but I would have to set it to zero outside and then only reset in in the beginning of main if it's zero. And the appeal stats to fade. So I think it's best to say that I'm using C a bad way, gcc rightfully doesn't optimize it correctly so don't try. – shiona – 2013-02-26T16:26:15.840

5

Perl

I'm not very good at bowling, but I suspect this may interest the OP. This is a Sieve of Eratosthenes using a variable goto. Were this to be 'refactored', I doubt any of it would be reusable, other than perhaps the first few lines. When the sieve ends, all remaining 1s in the @primes array correspond to prime values.

For added fun, no ands, ors, ternaries, conditionals or comparison operators of any kind are used.

@primes[2..1e4]=(1)x9999;
$a=2;
Y:
  $b=$a*~-$a;
X:
  $primes[$b+=$a+=$c=$a/100%2+$b/1e4%2]=0;
  goto"$c"^h;
Z:

primo

Posted 2013-02-23T20:09:44.580

Reputation: 30 891

In case there's any confusion as to why I'm posting this here, in a separate question (now deleted), the OP stated that, "this was the question he actually wanted to ask", but wasn't sure if it was possible.

– primo – 2013-03-15T04:20:00.067

In case there's any confusion as to what question I posted, it was a question about building code using only GOTO's, rather than just one. – Joe Z. – 2013-03-15T12:47:47.650

1@JoeZeng I originally had three, but I reduced it to one so that it would be a valid solution to this problem as well. – primo – 2013-03-15T13:24:12.127

3

C

My usage of macros perhaps doesn't make it "one GOTO".
And it's quite short, so "completely restructured" isn't much.
But here's my attempt anyway.

Reads a number from standard input, prints it modulu 3.

int main() {
    char s[100], *p, r=0;
    void *pl[] = { &&a, &&b, &&c, &&d, &&e, &&f, &&g, &&h, &&i, &&j, &&a, &&b, &&x, &&y, &&z }, *p1;
    p = gets(s);
    #define N(n) (pl+n)[!*p*60+*p-48];p++;goto *p1
    a: p1=N(0);
    b: p1=N(1);
    c: p1=N(2);
    d: p1=N(0);
    e: p1=N(1);
    f: p1=N(2);
    g: p1=N(0);
    h: p1=N(1);
    i: p1=N(2);
    j: p1=N(0);
    z: r++;
    y: r++;
    x: printf("%d\n", r);

    return 0;
}

ugoren

Posted 2013-02-23T20:09:44.580

Reputation: 16 527

1Yeah, using macros like that isn't "one GOTO". But even then, you'd need to provide the restructuring of the program without using a GOTO. Removing statements doesn't add to your score. – Joe Z. – 2013-02-25T20:58:56.783

Printing a number modulo 3 would be easy by just using a printf and scanf. Your solution's score would most likely be about 2 or 3. – Joe Z. – 2013-02-25T21:02:33.887

You can easily write another program that prints n%3. But it won't use this program's logic, so I don't think it would be a restructuring of this program. – ugoren – 2013-02-25T21:33:34.127

1Fair point. I can't think of why anybody would ever want to program something that prints n%3 in that way, though. It should be a program that becomes convoluted when the GOTO is removed, not when it is introduced. – Joe Z. – 2013-02-26T01:26:24.500

2"Why?" is irrelevant for this site - it's full of stupid ways to do stupid things. If you remove goto, the program won't work. But what did you expect - that the program would become convoluted by the removal alone? – ugoren – 2013-02-26T07:33:50.137

1By the removal and subsequent restructuring, yes. A simple example might be the use of goto to break out of multiple nested loops. – Joe Z. – 2013-02-26T19:17:21.213