Breaking up from while loop in lex - c

so I have using lex tool in linux and fell into an embarrassing position position , I couldn't break from a while loop.
e.g : I wrote ;
while(1)
{
int x = yylex();
switch(x):
case(ID):printf("ID");
case(NUM):printf("NUM");
}
Now I am reading from a file using yyin ; the problem is that the while loop does not fail after reading the whole file and keeps asking for more inputs at the terminal . Therefore I could not invoke other functions after calling the while loop . I know I am missing something basic , it will be great if somebody can provide an insight into this problem .
P.S# Thanks all for your answers ; tension and lack of sleep before homework submission date ; btw - I figured my answer already .

I see some issues with the C code, independent of what's going on inside the yylex() function. You quote the code as:
while(1)
{
int x = yylex();
switch(x):
case(ID):printf("ID");
case(NUM):printf("NUM");
}
This clearly isn't the source you compiled because it is not acceptable as C. You need to replace the first colon (after switch(x)) with an open brace {, and you need another close brace } at the end, to yield:
while(1)
{
int x = yylex();
switch(x)
{
case(ID):printf("ID");
case(NUM):printf("NUM");
}
}
This is syntactically valid C code, but there are still problems:
There should probably be a break; after each case.
There should probably be a default: clause, which might be used to terminate the loop (but you can't use break to do that inside the scope of a switch).
The printf() statements should print a newline so that the data appears.
Since yylex() returns 0 when it reaches the end, you should probably revise the code so it is more like:
void function(void)
{
int x;
while ((x = yylex()) != 0)
{
switch (x)
{
case ID:
printf("ID\n");
break;
case NUM:
printf("NUM\n");
break;
default:
printf("Other: %d\n", x);
break;
}
}
}
This will at least show you what's going on, and does not have an infinite loop unless you've written your lex analyzer such that it does not terminate properly. I opted not to have the default case terminate the loop since the loop is bounded by yylex() returning 0 instead.
When you write while (1), you are writing an infinite loop. It is incumbent on you to consider whether the loop is really infinite or not. If it is not, then you should aim to be able to make a test at the top of the loop that controls whether there is another cycle to the loop or not.

yylex() returns 0 at the logical end of input. Try this:
int x = -1;
while(!(x == 0))
{
x = yylex();
switch(x):
{
case(0): printf("that's all, folks!"); break;
case(ID): printf("ID"); break;
case(NUM): printf("NUM"); break;
}
}

Well, while I'll admit I'm not familiar with what lex is, I do know quite a bit about the linux environment and the terminal, so...
Try typing 'Ctrl' and 'c' at the same time while in the terminal. If that doesn't work, use 'Ctrl' + 'z'. If you don't mind having the process stopped in the background until the computer turns off and it goes away entirely, after Ctrl + Z you don't need to do anything else. If Ctrl + C worked, then the program's ended and you're fine.
If, for whatever reason, neither work, if you know the name of the program you wrote, you can type into the terminal:
pkill -9 [insert name of program here]
...which will send an unignorable kill signal to the process, and return all its memory (RAM- it won't undo changes made to disk) to the parent process.
If you DON'T know the name of the program, but you think you'll probably be able to recognize it, you can try:
top
which will bring up all the currently running processes in the terminal. Once you locate the name of your still-running program, press q to exit top, and then type in the kill command above with the name you recognized in top. If you don't know the program's name, and Ctrl + Z worked, but you don't want the stopped job to keep hogging its memory until you've turned off the computer, you can type:
ps -a
while in the terminal session from which you ran (and stopped) the program, and the job which shows up labeled 'stopped' is, in all likelihood, yours. Again, using the pkill command above will kill it. If, for whatever reason, you know the process ID but not the name (I don't know why you would, but there you go...), you could use the command 'kill' instead of 'pkill' (instructions for how to use these commands are all over the internet so I won't mention them here. They also have helpful help manual pages which can be accessed via:
man [the name of the program you want help with; 'pkill' or 'kill', in this case.]

To add to David's answer, here's a different version:
do
{
int x = yylex();
if (!x)
break;
switch(x):
{
case(ID): printf("ID"); break;
case(NUM): printf("NUM"); break;
}
} while(1);
This was only to show that you can break out of a while(1). You keep the x in local scope, and you don't evaluate the first pass or switch unnecessarily. Of course someone will most likely pull out the trump card of "it isn't as readable"...

Related

User input to determine if main function restarts or ends

I'm working on a small project right now that allows a user to choose an array editing function from a switch statement. Unfortunately, I coded it poorly (I can't make the switch menu its own function at this point, it is part of main().) I only bring this up to prevent suggestions involving calling a menu function. I also cannot use main() recursion because I take user input for the array and do not want to replace the existing values.
The code below is supposed to take user input to decide whether to exit the program or to re-open the selection screen and
char restart = 'y';
do {
printf("Would you like to try a different function? (Y/N): ");
restart = getchar();
restart = getchar();
system("clear");
goto START; // "START" is the label for my main selection screen function.
} while ( restart == 'Y' || restart == 'y');
system("clear");
printf("Okay, thank you!\n\n");
for (i = 3; i > 0; i++) {
printf("Exiting in %d seconds...", &i);
sleep(1);
}
(At the end of main() I included an exit function.)
I have two questions:
How can I detect if the user inputs an invalid character? (Not n, N, y, Y) I was initially going to build this with if-else statements, but realized that was ineffective. However, now I no longer know how to work with the do-while loop to detect these inputs.
This code simply doesn't work. What'd I do wrong? When inputting y or Y, the loop never exits. Should I embed the do-while loop in a while loop utilizing breaks?
My only theories right now (as a baby C programmer) are that labels don't work with this method or that I have no real way to break from the loop.
Thank you!

Quit the whole program early in C?

Generally say I have some functions step1 step2 ... and they are called successively:
int main()
{
...
step1(); // something wrong detected and need to break out of the whole program
step2();
step3();
...
}
How can I break out from step1 and skip all the rest of code to terminate main() function?
Currently I can only think of setting a global variable like bool isErr as a flag so that
step1(); // error detected and isErr is set to 1 inside step1()
if (isErr)
return;
step2();
...
Are there better or more 'canonical' approaches?
BTW I've heard that goto is bad so I discard it :)
Use
exit(1);
The number indicates the exit status. 0 is no failure, everything larger then 0 indicates an error.
One option is to check return value of your step1() function and if it is error, just use for example return 1 in main. Using return (with appropriate status code) from main to finish the program is the preferred way in C++.
Other option is exit. The point is you can call it anywhere in the code. However, in C++ exit is not recommended that much. Regarding C, there is a question here which discusses whether using exit in C is a good idea or not.
You can use the exit() function to terminate the process at any point during step1(), step2()... anywhere actually.
exit will terminate the program from wherever you are, but in most cases this is a bad idea, checking the return value of a function and handling (e.g. exit in your case) is a cleaner way to do it (no need for globals)

Break statement not within loop or switch in C

I am getting this error in my C code. I don't know what I am doing wrong. If I comment this code my program works. This piece of code is inside int main().
if(argc!=2 && strcmp(argv[0],"selection-sort")==0 && strcmp(argv[1],"input.txt")==0 && strcmp(argv[2],"output.txt")==0)
{
printf("The command line arguments are correct.\n");
}
else
{
printf("The command line arguments are wrong.I am exiting.\n");
break;
}
The way it looks I think you're not in a loop but just checking args in main. You probably want something like return 1 or exit(1) instead of the break.
First of all make sure you are including the needed header files:
#include <stdio.h>
#include <stdlib.h>
The break command is used for exiting loops, you are not in a loop you are just in an else statement, you have nothing to break from. The code flow executes normally after passing that else statement. If you want to exit the program in that else statement you could do something like this:
else
{
printf("The command line arguments are wrong.I am exiting.\n");
return 1; //exit program with status 1 to indicate a non normal exit
}
Or if you want to continue the program after displaying that message you could just do this:
else printf("The command line arguments are wrong.I am exiting.\n");
//more code here
You only use break in loops like so:
while(foo) //while foo is true
{
break; //exit the loop
}
The error message in the title says it all: break can only be used to exit a loop or prevent a case from falling through. MSDN quote:
The break statement terminates the execution of the nearest enclosing
do, for, switch, or while statement in which it appears.
To leave a function use return.
Break is supposed to be used in loops.
Use a return statement, which causes execution to leave the current subroutine and resume at the point in the code immediately after where the subroutine was called (return address).
The other answers are correct, this is just a slight addition.
To return probably in this specific case you should include errno.h like this:
#include <errno.h>
And furthermore return like this:
return EINVAL;
Then you are signaling that the program is terminating due to an error and the return value specifically states that the error is invalid arguments.
'break' will only get you out of the innermost loop or switch. You can use 'return' to exit out of a function at any time.
"A break statement may appear only in an iteration statement or a switch statement, and terminates execution of the smallest enclosing such statement".
And it makes sense too - you can "escape" from a method with "return" , and you can skip code in other situations with an if/else. I don't know what a "break" outside a case would be expected to do.
'break' is really only a restricted form of 'goto' anyway. Ideally, you want a single point of exit from any block of code. You should really only use 'break' in a switch statement because that is the only way to make it work. In any other context, there are better ways to accomplish the same thing. The same applies to 'continue'.

allow user to start program again in c?

I have written a program in c. However once the program is finished it stops (duh). Is there a simple script that allows me to let the user start the program over again?
Why not use loop (for, while) in the main itself: ( if the program is simple!)
main()
{
while( Exit condition)
{
//logic
}
}
char cont_prog = 'n';
do {
/* main program in here */
printf("Do you want to start again? (y/n): ");
cont_prog = getchar();
} while (cont_prog == 'y' || cont_prog == 'Y');
Essentially, you want to put you main prog in a loop, asking the user if they want to continue. You have to deal with the user entering in too much data (they type, 'yes', for example) and your buffer being full next time through the loop.
If you really want to re-launch the program without exiting (though I can't see why):
Save argv (and I'll assume that argv[0] actually points to your executable, even though that is not guaranteed) if you want the same command line arguments.
Consider saving the environment, if you might change it, and also want it to be repeated.
man execv or execle. Just replace the currently running image with a new one that has the same command line
Frankly, looping would be easier, and can have the same semantics if you avoid global state, or arrange to be able to re-set it.
Sure, but how would you get the user to run that script? Wouldn't it be simpler to have the user simply re-run the program?
#include <stdlib.h>
#ifdef WIN32
#define EXECUTABLE ".exe"
#else
#define EXECUTABLE
#endif
int main(void) {
for (;;) system("executable_in_c" EXECUTABLE);
return 0;
}
Compile this program, rename your old executable to "executable_in_c[.exe]"; rename this one to the name of your old executable ... voila!

runtime error (SIGSEGV)

can anyone tell me whats wrong in the following program that accepts 1 or 2 digit integers untill it encounters the number 42 after which it prints the previously entered numbers??when i upload this to the sphere online judge site it says compilation successful but runtime error (SIGSEGV).
#include <stdio.h>
int main()
{
int i;
FILE *fp;
fp=fopen("\\db.txt","w+");
if(fp==NULL)
{
printf("file not exitsts and cant be created");
system("exit");
}
while(1)
{
scanf("%d",&i);
if(i==42)
break;
else
{
fprintf(fp,"%d\n",i);
}
}
fclose(fp);
fp=fopen("\\db.txt","r+");
if(fp==NULL)
{
printf("file not exitsts and cant be created");
system("exit");
}
fscanf(fp,"%d",&i);
printf("%d\n",i);
while((!feof(fp)))
{
fscanf(fp,"%d",&i);
if(!feof(fp))
printf("%d\n",i);
}
fclose(fp);
return 0;
}
It seems like you're trying to answer this: http://www.spoj.pl/problems/TEST/ . This problem certainly does not require you to read or write anything from a file, and their server may not allow you to open files on its disk. Even if it does, you're trying to use a windows-style path (with a backslash) on what may be a non-Windows server. And even if it does allow file creation and windows-style path separation, you are trying to create your file in the filesystem root directory, and they almost certainly do not allow file creation there.
Combined with the system("exit") issue that everyone pointed out where it doesn't actually exit the program, this will cause you to receive a NULL file pointer and crash when you try to use it.
Re-read the problem description - you're over-thinking it. It doesn't say anywhere that you have to wait until you get a 42 to print out the other numbers. All you have to do is print back what is entered until you get a 42. That should make the solution much simpler. It's not supposed to be even a mildly challenging problem; it's just supposed to familiarize you with their system.
I don't know what you think:
system("exit");
will do, but the way to exit a program in C is:
exit(1);
You should replace
system("exit");
with
exit(1);
or, because you're already in main:
return 1;
I suspect the SIGSEGV is caused because you cannot write to the file \\db.txt, but the program continues because system("exit") is not causing it to terminate.
On an semi-related note, SIGSEGV is usually a Unix signal, and path separators on Unix are / rather than \.
I don't know precisely the cause of the SEGV, but I guess it is because the input doesn't match what you expect. In any case, this line doesn't do what you think it does:
system("exit");
at which line do you receive the error?
is your empty #include intended? i think it should mean #include
have you got the error for every input or just for 42?
regards
SIGSEGV is an access violation error, which indicates a null pointer. Since system("exit") isn't doing anything, fp is getting set to null, and then when you try to use that pointer (for example with fprintf())... boom, your program crashes.
Replace system("exit") with return 1 (or whatever error code you desire), that should fix it.
$ gcc -Wall test.c -o test
test.c: In function ‘main’:
test.c:8: warning: implicit declaration of function ‘system’
$ ./test
1
2
3
10
42
1
2
3
10
But yes, I do agree that the system("exit") does not what you expect. What you are exiting from, with that call, is a subshell that is spawned by your program, and then goes on. From the system man page
The system() function hands the
argument command to the command
interpreter sh(1). The calling
process waits for the shell to finish
executing the command, ignoring SIGINT
and SIGQUIT, and blocking SIGCHLD.

Resources