I didn’t know you can use curly brackets after a ‘case’ instruction.
What seems kind of wrong to me is the code at case 6. It starts with an instruction without curly brackets around it (if…) and after it there are curly brackets. That seems wrong to me.
The curly braces are just grouping symbols. The state assignments and corresponding break statements must be kept together. In the case of the if statement in state 6 it would normally be formatted as one statement without curly braces at all. Like this:
case 6:
if (v1<k2)
{
state=5;
break;
}
state=0;
break;
default:
state=1;
break;
Sorry, that’s just bad practice. You should not drop through a case like that because it can cause unexpected errors. It would be better to put the conditional in the default clause or to return the default value in an else clause in the code you already have. One of the things C-like languages have improved over C is the rule that you must always break out of a case clause. They got it right.
Also, putting the break inside the braces can cause odd behaviour because any code outside the braces might get executed if you change your scoped code. Best to put the break outside.
Also, this looks like C/C++, so it doesn’t matter what basic does, you need to follow good C/C++ otherwise your transpiled code will have bugs. It already does, because you fall through a break clause and will get undefeated behaviours if that code changes or you add an extra case below it.
In non-structured code, fall-through cases are used extensively. If you want pretty, prim and proper C++ code, never look at the output of my transpiler. It will give you a heart attack every time.
That is a cop out. Honestly, generated code is not required to be terrible code. I’ve written a number of code generators and generally the ones with less bugs are the ones that don’t cut corners for no good reason. Your original bug was there because you were trying to cut a corner…
@SamuraiCrow I re-read your code (replying on an iPad, missed subtle nuance) and this would be way safer and much better code (braces or no braces in the if/else):
case 6:
if (v1<k2)
{
state=5;
}
else
{
state=0;
}
break;
default:
state=1;
break;
I mean, you might argue no one will ever use the code directly, but if you ever want to debug this code, the code above really does make more sense and someone will thank you for that. I bet it makes no difference to the binary generated.
The BASIC code represented by my code is as follows:
WHILE v1<k2
REM body
WEND
END
The conditional branch of the while loop is moved down to the end internally by GCC using static single assign (SSA) architecture to avoid branchy code and inefficient branch predicition. The END statement that follows the loop is a separate command completely. Try looking at the output of GCC for other “simple” structured code after it’s been completely optimized and you’ll see how mangled it is internally by the compiler.
That may be the case, but isn’t your project about exporting the written yab code as c or c++? Then the written yab code has to be converted, or should that be done via the original structure yabasic? Is that then at all with the widget commands (window, views…)?
If it should be the case that the code written so far in yab cannot be converted and you have to learn yab again, I would be out.
It’s because there are other BASIC commands like GOSUB that have no direct equivalent in C or C++. If you have a label and need to jump to a subroutine that starts with that label but returns to every call-site regardless of where it was called from, it becomes necessary to implement your own call-stack. If you need an equivalent structured C++ function to do it, you’ll have to leave GOSUB and ON n GOSUB out of your transpiler because structured C++ can’t do it with a label. It has to be converted to ON n SUB to make it into structured YAB code only. The transpiler would be incomplete without the full instruction set.
I wanted my code to generate C++ or C regardless of whether the BASIC commands had an easy equivalent or not. I’m only using GCC as a backend compiler because it generates code for different processors regardless of what machine you are on.
I always thought that one writes standard programs with different structures with yab and converts them to c or c++. Since the programs always look the same or similar, I thought that wouldn’t be the biggest problem. So the GUI side, since Haiku API is used. The commands in the background are of course something else. But being able to convert the GUI to c or c++ would be a help for people who want to create fast GUIs and then continue working in c or c++.
Hmmm… Many GUI languages use XML as an intermediate step. Using Yab as that intermediate step would require an external linker to link the resultant object code to the rest of the program. YaBASIC was a bad choice to start with because it was interpreted and couldn’t be compiled easily. I’m taking the difficult approach of making a compiler with a C++ backend so that existing code written in YAB or any other BASIC could generate raw machine code. The only commands that can’t be done that way are the command to invoke the interpreter manually. The interpreter is not there any more once compiled.
In an effort to defuse a difficult discussion, I’ve renamed the thread. The purpose here is to compile YAB BASIC into executable code. If it uses C or C++ as a backend should be immaterial. If necessary I could use LLVM IR or GCC IR (whatever the replacement for Gimple is called) and bypass the whole high-level language backend issue.
I think producing intermediate code would be the most elegant. But since it is a hobby project you are the only one who decides which backend. Choose whatever makes the most fun and/or is the easiest for your coding skills.
Sure they do - gosub is just calling a function. Gosub in basic is just a thin layer over an unconditional jmp/ret in a lot of processors assembly language. Imagine this made up pseudo assembler
global v = 10 ; set up a global value
something:
; a while equivilent
cmp v, #0
je ended
cmp v, #5 ; compare v to literal 5
je it_is_5 ; jump if v == 5
dec v,1 ; decrement v by 1
jmp something ; loop again (yeah, infinite loop)
it_is_5:
; do something
ret ; return from jump
ended:
end ; stop execution
in basic I giess this might be:
dim v = 10
while v > 0
if v = 5 gosub it_is_5
v = v -1
wend
label it_is_5:
rem do something
return
and c would be
int v = 10;
void it_is_5(); // forward declaration - C scope is one pass so poor.
int main()
{
while ( v > 0)
{
if(v ==5)
{
it_is_5();
}
v--;
}
}
void it_is_5()
{
// do something
}
You are basically doing a 1:1 mapping. If your globals are global, it is fine. You can map everything in basic directly to C… I know this for a fact because I dod a LOY of VB.Net back int he day and I converted whatever I could to C# because basic is a horrible (no offence) language to actually program in.