I have today a problem with my flex/bison script. It doesn't detect the multiline comment.
%x COMMENT_MULTI
#\[ yy_push_state(COMMENT_MULTI);
<COMMENT_MULTI>"]#" yy_pop_state();
<COMMENT_MULTI>"\n" {
yylloc->lines(yyleng);
yylloc->step();
}
<COMMENT_MULTI>.?
Can you help me?
This is the solution I ended up using in my bison definition of C++ comments and block comments:
%x COMMENT
"//".*\n ;
"/*" BEGIN(COMMENT);
<COMMENT>"/*" printf("%s%d\n", "Warning: multiple comments opened at line: ", yylineno);
<COMMENT>"*/" BEGIN(INITIAL);
<COMMENT>"EOF" yyerror("Reached end of file while scanning comment");
<COMMENT>.|"\n" ;
/*DECLARING A SPECIFIC STATE FOR THE BLOCK COMMENT*/
%x BLOCK_COMMENT
%%
\/\* { // BEGINING OF A BLOCK COMMENT: ENTERS INTO 'BLOCK_COMMENT' STATE
BEGIN(BLOCK_COMMENT);
blockcomment_line_start = line;
blockcomment_col_start = frcol;
strncat(block_comment, yytext, sizeof(block_comment));
}
<BLOCK_COMMENT>\*\/ { // END OF BLOCK COMMENT
if(strlen(block_comment)+strlen(yytext) >= BLOCK_COMMENT_BUFFER-10){ //ADDS "(...)" AT THE END OF THE STRING IN CASE IT HAS BEEN TRUNCATED
block_comment[1013] = '\0';
strcat(block_comment," (...) ");
}
strncat(block_comment, yytext, sizeof(block_comment));
printf("#(%.3d,%.3d)\tBLOCK COMMENT\t- %s\n", blockcomment_line_start, blockcomment_col_start, block_comment);
BEGIN(INITIAL); //COMES BACK TO THE INITIAL STATE
}
<BLOCK_COMMENT>\n {
line++; // STILL HAS TO INCREMENT THE LINE NUMBER WHEN THERE'S A LINE BREAK INSIDE THE COMMENT
//strcat(block_comment, "\\n");
strncat(block_comment, "\\n", sizeof(block_comment));
}
<BLOCK_COMMENT>. { // IGNORE ALL OTHER CHARACTERS WHILE IN 'BLOCK_COMMENT' STATE
//strcat(block_comment, yytext);
strncat(block_comment, yytext, sizeof(block_comment));
}
<BLOCK_COMMENT><<EOF>> {
printf("ERROR! THE BLOCK COMMENT OPENED IN #(%d,%d) HASN'T BEEN CLOSED! \t\n", blockcomment_line_start, blockcomment_col_start);
return;
}
Related
Problem
I am trying to convert a string to a C string. In doing so, I need to replace " with \". I use the following code to do this:
QString Converter::plain2C(const QString &in) {
QString out;
// Split input in each line
QStringList list = in.split(QChar('\n'));
for (int i = 0; list.length() > i; i++) { // Go throught each line of the input
QString line = list[i]; // Thats the line
line.replace(QChar('\\'), QLatin1String("\\\\")); // replace \ with \\
line.replace(QChar('"'), QLatin1String("\\\"")); // replace " with \"
// For printf()
if(escapePercent)
line.replace(QChar('%'), QLatin1String("%%"));
// If option "Split output into multiple lines" is active add a " to the output
if (multiLine)
out.append(QChar('"'));
// append the line to the output
out.append(line);
// append a "\n" to the output because we are at the end of a line
if (list.length() -1 > i)
out.append(QLatin1String("\\n"));
// If option "Split output into multiple lines" is active add a " and \n to the output
if (multiLine) {
out.append(QChar('"'));
out.append(QChar('\n'));
}
}
if (!multiLine) {
out.prepend(QChar('"'));
out.append(QChar('"'));
}
return out;
}
However, " is still there without a \ before.
Information
Qt Version 5.15.3
C++17
Edit
The application is used to enter a normal string copied from the Internet and get as a result a string that can be copied into a C/C++ program.
More code
void Converter::run()
{
if (_from != From::NotSupportet &&
_to != To::toInvalid) {
QString out;
// More code obove and below
else if (_from == From::Plain) {
switch (_to) {
case To::toCString:
out = plain2C(_in);
break;
// Emits the ready string which is applied direct to a QPlainTextEdit
emit htmlReady(out);
}
}
Edit 2
Added more comments to the code
It works now. The problem was the line above:
line.replace(QChar('\'), QLatin1String("\\\\")); // replace \ with \\
The problem was that the comment ended with 2 \. That somehow disabled the next line or something like that.
Anyway, this is the working code:
QString Converter::plain2C(const QString &in) {
QString out;
// Split input in each line
QStringList list = in.split(QChar('\n'));
for (int i = 0; list.length() > i; i++) { // Go throught each line of the input
QString line = list[i]; // Thats the line
line.replace(QChar('\\'), QLatin1String("\\\\")); // replace "\" with "\\"
line.replace(QChar('"'), QLatin1String("\\\"")); // replace " with \"
// For printf()
if(escapePercent)
line.replace(QChar('%'), QLatin1String("%%"));
// If option "Split output into multiple lines" is active add a " to the output
if (multiLine)
out.append(QChar('"'));
// append the line to the output
out.append(line);
// append a "\n" to the output because we are at the end of a line
if (list.length() -1 > i)
out.append(QLatin1String("\\n"));
// If option "Split output into multiple lines" is active add a " and \n to the output
if (multiLine) {
out.append(QChar('"'));
out.append(QChar('\n'));
}
}
if (!multiLine) {
out.prepend(QChar('"'));
out.append(QChar('"'));
}
return out;
}
I am using ifstream to open a file and read line by line and print to console.
Now, I also want to make sure that if the file gets updated, it reflects. My code should handle that.
I tried setting fseek to end of the file and then looking for new entries by using peek. However, that did not work.
Here's some code I used
bool ifRead = true;
while (1)
{
if (ifRead)
{
if (!file2read.eof())
{
//valid file. not end of file.
while (getline(file2read, line))
printf("Line: %s \n", line.c_str());
}
else
{
file2read.seekg(0, file2read.end);
ifRead = false;
}
}
else
{
//I thought this would check if new content is added.
//in which case, "peek" will return a non-EOF value. else it will always be EOF.
if (file2read.peek() != EOF)
ifRead = true;
}
}
}
Any suggestions on what could be wrong or how I could do this.
Write a parser (both Yacc and Lex files) that uses the following productions and actions:
S -> cSS {print “x”}
S -> a {print “y”}
S -> b {print “z”}
Indicate the string that it will print when the input is cacba.
I am getting this error: when I give input to it, it says valid input and also says syntax error.
My Scanner Code is this
%{
#include "prac.h"
%}
%%
[c] {return C; }
[a] {return A; }
[b] {return B; }
[ \t] ;
\n { return 0; }
. { return yytext[0]; }
%%
int yywrap(void) {
return 1;
}
And my yacc code is this:
%{
#include <stdio.h>
%}
%token A B C
%%
statement: S {printf("Valid Input"); }
;
S: C S S {printf("Print x\n");}
| A {printf("Print y\n");}
| B {printf("Print z\n");}
;
%%
int main()
{
return yyparse();
}
yyerror(char *s)
{
printf("\n%s\n",s);
printf("Invalid Input");
fprintf(stderr,"At line %d %s ",s,yylineno);
}
How can I fix this?
(Comments converted to an answer)
#ChrisDodd wrote:
Best guess -- you're running on windows, so you're getting a \r (carriage return) character before the newline which is causing your error. Try adding \r to the [ \t] pattern to ignore it.
#Cyclone wrote:
Change your fprintf() statement to fprintf(stderr, "At line %d %s", yylineno, s); not that it will solve your problem.
The OP wrote:
You mean I should add \r into \t so the new regex for it will be [\r\t] Am I right ?
#rici wrote:
#chris suggests [ \r\t]. If you have Windows somewhere in the loop, I agree.
I'm trying to parse C files and add debugs at exit points of the functions using clang.
I can add debugs just before return, or exit of function using following code
if (isa<ReturnStmt>(s)) {
ReturnStmt *ReturnStatement = cast<ReturnStmt>(s);
TheRewriter.InsertText(ReturnStatement->getLocStart(), "{printf(\"[%s:%d] OUT \\n\", __FUNCTION__, __LINE__);\n", true, true);
}
But it doesn't work for functions like this:
//before preprocessing
int foo(int a)
{
if(a)
return 1;
else
return a;
}
//after
int foo(int a)
{
if(a)
{printf("[%s:%d] OUT \n", __FUNCTION__, __LINE__);
return 1;
else
{printf("[%s:%d] OUT \n", __FUNCTION__, __LINE__);
return a;
}
Unfortunately, simple getLocEnd doesn't work.
TheRewriter.InsertText(ReturnStatement->getLocEnd(), "}", true, true);
it puts "}" just after "return".
if(a)
{printf("[%s:%d] OUT \n", __FUNCTION__, __LINE__);
return }1;
Please, help me to detect end of Return Statement location, to put closing "}" or maybe it's less difficult to put ReturnStatement into some Compound Statement or so.
I also tried find end of Return Statement like this:
ReturnStatement->getLocStart().getLocWithOffset(strlen(retvalue) + 1);
but I can get return value in a string view only for ImplicitCastExpr.
Thanks.
It's a known bug with no simple solution.
here we have an answer. I found it here:
https://github.com/loarabia/Clang-tutorial/blob/master/CIrewriter.cpp
all you need is :
// Note Stmt::getLocEnd() returns the source location prior to the
// token at the end of the line. For instance, for:
// var = 123;
// ^---- getLocEnd() points here.
SourceLocation END = stmt->getLocEnd();
// MeasureTokenLength gets us past the last token, and adding 1 gets
// us past the ';'.
int offset = Lexer::MeasureTokenLength(END,
TheRewriter.getSourceMgr(),
TheRewriter.getLangOpts()) + 1;
SourceLocation END1 = END.getLocWithOffset(offset);
TheRewriter.InsertText(END1, "\n}", true, true);
I'm sorry, it would be extremely difficult to make a fully reproducible version of the error --- so please bare with my schematic code.
This program retrieves information from a web page, processes it, and saves output to an ASCII file. I also have a 'log' file (FILE *theLog---contained within a Manager object) for reporting errors, etc.
Some background methods:
// Prints string to log file
void Manager::logEntry(const string lstr) {
if( theLog != NULL ) { fprintf(theLog, "%s", lstr.c_str()); }
}
// Checks if file with given name already exists
bool fileExists(const string fname) {
FILE *temp;
if( temp = fopen(fname.c_str(), "r") ) {
fclose(temp);
return true;
} else { return false; }
}
// Initialize file for writing (some components omitted)...
bool initFile(FILE *&oFile, const string fname) {
if(oFile = fopen(fname.c_str(), "w") ) { return true; }
else { return false; }
}
The stuff causing trouble:
// Gets data from URL, saves to file 'dataFileName', input control flag 'foreCon'
// stu is some object that has string which i want
bool saveData(Manager *man, Stuff *stu, string dataFileName, const int foreCon) {
char logStr[CHARLIMIT_LARGE]; // CHARLIMIT_LARGE = 2048
sprintf(logStr, "Saving Data...\n");
man->logEntry( string(logStr) ); // This appears fine in 'theLog' correctly
string data = stu->getDataPrefixStr() + getDataFromURL() + "\n"; // fills 'data' with stuff
data += stu->getDataSuffixStr();
if( fileExists(dataFileName) ) {
sprintf(logStr, "save file '%s' already exists.", dataFileName.c_str() );
man->logEntry( string(logStr) );
if( foreCon == -1 ) {
sprintf(logStr, "foreCon = %d, ... exiting.", foreCon); // LINE 'A' : THIS LINE ENDS UP IN OUTPUT FILE
tCase->logEntry( string(logStr) );
return false;
} else {
sprintf(logStr, "foreCon = %d, overwriting file.", foreCon); // LINE 'B' : THIS LINE ENDS UP IN LOG FILE
tCase->logEntry( string(logStr) );
}
}
// Initialize output file
FILE *outFile;
if( !initFile(outFile, dataFileName) ) {
sprintf(logStr, "couldn't initFile '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return false;
}
fprintf(outFile, "%s", data.c_str()); // print data to output file
if( fclose(outFile) != EOF) {
sprintf(logStr, "saved to '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return true;
}
return false;
}
If the file already exists, AND 'int foreCon = -1' then the code should print out line 'A' to the logFile. If the file exists and foreCon != -1, the old file is overwritten with data. If the file doesn't exist, it is created, and the data is written to it.
The result however, is that a broken up version of line 'A' appears in the data file AND line 'B' is printed in the log file!!!!
What the data file looks like:
.. exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
The second line and onward look correct, but there is an extra line that contains part of line 'A'.
Now, the REALLY WEIRD PART. If I comment out everything in the if( foreCon == -1) { ... } block, then the data file looks like:
%d, ... exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
There is still an extra line, but it is the LITERAL CODE copied into the data file.
I think there is a poltergeist in my code. I don't understand how any of this could happen.
Edit: I've tried printing to console the data string, and it gives the same messed up values: i.e. %d, ... exiting.20130127 161456 - so it must be something about the string instead of the FILE *
Answer based on your latest comment:
getDataPrefixStr() ends up returning a string which starts with
something like string retStr = COMCHAR + " file created on ..."; such
that const char COMCHAR = '#';. Could the COMCHAR be the problem??
You can't add characters and string literals (which are arrays of char, not strings) like that.
You're adding 35 (the ASCII for "#") to the address of " file created on ... ", i.e. getDataPrefixStr() is whatever starts 35 characters from the start of that string. Since all literal strings are stored together in the same data area, you'll get strings from the program in the output.
Instead, you cold do
const string COMCHAR = "*";
string retStr = COMCHAR + " file created on ...";
It could be that logStr is too short and that it is causing data to be overwritten in other buffers (did you double check CHARLIMIT_LARGE?). You can diagnose this by commenting all writes to logStr (sprintf) and see if data is still corrupted. In general, your code is vulnerable to this if a user can set dataFileName (to be a very long string); use snprintf or ostringstream instead.
Otherwise, I would guess that either stu->getDataPrefixStr() or getDataFromURL() are returning corrupted results or return type char* instead of string. Try printing these values to the console directly to see if they are corrupted or not. If they return a char*, then data = stu->getDataPrefixStr() + getDataFromURL() will have undefined behavior.
if( temp = fopen(fname.c_str(), 'r') ) {
should be
if( temp = fopen(fname.c_str(), "r") ) {