How to get yacc/bison and lex/flex to pause file scanning? - c++

Im trying to parse a file using Bison/Yacc but i want to pause the parsing for a while. The reason i want to do this is that i want to process a huge file sequentially and simulate a java iterator using hasNext() and next() methods.
A trivial example would be, splitting a file by line using yacc so i could call:
while(myYaccObj.hasNext())
{
std::string line = myYaccObj.next()
}
I cant find how to "pause" the file scanning. Is there a way to do that?

The easiest way is just to do the pause directly in you action code. For example, you could have a rule:
rule: whatever { Pause(); }
;
This would call your Pause function which could pause and/or do whatever you want. When you want to continue parsing, simply have the Pause function return.

In fact pausing for me means "keep the state and finish the yyparse" call. For example in my gramar I would do:
rule:
SaveLine;
Pause;
And then the control is returned to my code. I do what i have to do and then I call:
yyparse_resume();
and the parsing continues until another pause or EOF.

Related

write interpreter for file format (C++ Arduino)

So I have a .txt file (Excellon) which I want to interpret.
Example file:
M48
FMAT,2
ICI,OFF
METRIC,TZ,000.000
T1C1.016
%
G90
M71
T1
X36551Y-569519
X17780Y-589280
When I scan the file I seperate the statement (e.g. METRIC) and save this in a string. After this I want to execute code based on the value of this string.
What would be the best practice to execute commands on statement detection.
if(String == "METRIC")
{
execute code;
}
else if (String == "M48")
{
execute code;
}
etc.
Or something like this:
switch(String)
{
case: "M48"
execute code;
break;
case: "METRIC"
execute code;
break;
etc.
}
Or are both of these methods wrong and should I use a different method?
I found this: Switch or if statements in writing an interpreter in java they are talking about using a map should I also try this? If so could you provide a simple example because I don't really understand this method.
The proper answer will depend on many factors, but reading between the lines of your post, I am 98% sure that what you want is a simple tokenizer to enum:
enum class Token {
AAA,
BBB,
CCC
};
// Trivially implementable as a if() {} else if {} sequence,
// or as a trie search if you want to get fancy.
Token token_from_string(const std::string& str);
// and in the code.
Token tok = token_from_string(String);
switch(tok) {
case Token::AAA:
break;
case Token::BBB:
break;
case Token::CCC:
break;
}
And then, a good practice is to tokenize the string as soon as it comes out of the stream, and then operate on the token itself.
Q: What would be the best practice to execute commands on statement detection.
You want to change control flow, when a certain string is found.
A switch is saying "pick one of commands based on this variables value". You could also use if/else.
Q: If so could you provide a simple example because I don't really understand this method.
The Excellon file format isn't far away from CNC g-code.
This is an example for a switch from an EXCELLON to GCODE converter.
The trick would be to modify the output method generateFile, to not generate the G-code file using fprint's, but call your commands instead (probably move, lift, wait, etc.).
You could also start with a g-code parser and modify it to handle the excellon format.

How do use BLE scan_stop

im doing a program that allow my beacon and DK board to start scanning and stop scanning using BLE. I am able to start scanning, but i didn't know how to stop scanning. Can anyone advise me with this? The code provided is my scan_start. Thank you!
static void scan_start(void)
{
uint32_t err_code;
err_code = sd_ble_gap_scan_start(&m_scan_params);
APP_ERROR_CHECK(err_code);
err_code = bsp_indication_set(BSP_INDICATE_SCANNING);
APP_ERROR_CHECK(err_code);
}
Stopping scan_start depends on where you use this function. For example if you use scan_start in main function(before for loop), after a while, if there is no connection, it will enter sleep mode and stop scanning.
Otherwise if you want to control start_scanning time, you can define app_timer function. For example, you can define a timer or button handler that starts scanning when the button is pressed.
If you still can not find the answer you're looking for, there is another suggestion. You can use the stop_scanning function in the file "ble_gap.h" to stop scanning. Function like this;
SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void));
You can use like this;
(void) sd_ble_gap_scan_stop();
If there is any mistake please correct it. I hope that will be useful...

Put the code generated by flex to a normal C++ program

I create a simple file, using flex, it generate a file lex.yy.c, for now, I want to put it to C++ program.
%{
#include < stdio.h>
%}
%%
stop printf("Stop command received\n");
start printf("Start command received\n");
%%
When I type start or stop in command line, there is a output. What I want to do is to give the input by my C++ program, and the output of it should be sent to a variable in my program, is it possible? Thanks a lot!
I know the code I post is quite simple, but the result I imagine is:
create c file by flex and bison, and I use it as a header, so in the c++ program, I just need to call a function lex_yacc() to use it. ex. lex_yacc() is a calculator, so I sent an expression with evariables to this function, and it will return the result. I want to use this function in a C++ program, I am confused...Thanks a lot!
See the section about multiple input buffers in the manual. Especially the section about yy_scan_string and yy_scan_bytes.
For the "output", of course the is "output" when you give "stop" or "start" as input, you explicitly do that (i.e. the printf calls). You can put any code you want there.

Determing line number and file name of the perl file from within C++

I am working with Perl embedded in our application. We have installed quite a few C++ functions that are called from within Perl. One of them is a logging function. I would like to add the file name and line number of the Perl file that called this function to the log message.
I know on the Perl side I can use the "caller()" function to get this information, but this function is already used in hundreds of locations, so I would prefer to modify the C++ side, is this information passed to the C++ XSUB functions and if so how would I get at it?
Thanks.
This should work:
char *file;
I32 line;
file = OutCopFILE(PL_curcop);
line = CopLINE(PL_curcop);
Control ops (cops) are one of the two ops OP_NEXTSTATE and op_DBSTATE,
that (loosely speaking) are separate statements.
They hold information important for lexical state and error reporting.
At run time, PL_curcop is set to point to the most recently executed cop,
and thus can be used to determine our current state.
— cop.h
Can't you call perl builtins from XS? I confess I don't know.
If not, you could always do something like this:
sub logger { _real_logger(caller, #_) }
assuming logger is what your function is called (and you rename your C++ XS function to _real_logger. You could also do this, presumably, if you need to hide yourself in the call tree:
sub logger {
unshift #_, caller;
goto &_real_logger;
}
which is of course the normal form of goto used in AUTOLOAD.
These will add overhead, of course, but probably not a big deal for a logging function.

How to tell flex and bison to stop processing input?

What is the best way to flex and bison to stop processing when an error is encountered. If I call yyerror, it does not stop scanning and parsing my file. While the input is syntactically correct, there is an user error, such as they tried to load the same file twice. Once I am out of flex/bison, then my program will return an error to the user and the program should keep running. I assume that throwing a C++ exception would probably break something?
YYABORT is the standard way of getting out; it causes yyparse to return immediately with a failure (1). You can then throw an exception or do whatever you want. You'll need to reset flex's input if you want to parse something else, but if you do, you can just call yyparse again and parsing will start over from the beginning.
YYACCEPT stop parse and return 0.