Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to
LinuxQuestions.org , a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free.
Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please
contact us . If you need to reset your password,
click here .
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a
virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month.
Click here for more info.
03-25-2017, 01:58 AM
#1
Senior Member
Registered: Sep 2006
Posts: 1,416
Rep:
PNFPP: Help with Macros
I am almost done with PNFPP. One problem remains! I am having trouble getting macros with parameters to work. Please help. Here is my main code:
PNFPP.LPP
Code:
%{
/* Prologue */
#include <stdarg.h>
#include "pnfpp.tab.cpp"
char * _memblock_;
Array<String> out;
char outbuffer[256];
char linebuf[256];
%}
/* Flex Definitions */
%x escape_sequence
OPLT "<"
OPGT ">"
OPST "#"
OPTK "##"
OPPAREN "()"
TCHARACTER [^"\n]
STRING \"{TCHARACTER}*\"
TSTRING [^ \n\"]+
INCLUDE "#include "
IMPORT "#import "
DEFINE "#define"
MACRO "#macro"
ENDM "#endm"
UNDEF "#undef"
IFDEF "#ifdef"
IFNDEF "#ifndef"
ELSE "#else"
ENDIF "#endif"
PDATE "_DATE()"
PTIME "_TIME()"
PLINE "_LINE()"
PFILE "_FILE()"
PCDATE "_CDATE()"
PCTIME "_CTIME()"
COMMENT "' ".*
/* Flex Patterns Below %% */
%%
{OPLT} yylval = "0"; return OPLT;
{OPGT} yylval = "1"; return OPGT;
{OPST} yylval = "2"; return OPST;
{OPTK} yylval = "3"; return OPTK;
{OPPAREN} yylval = "4"; return OPPAREN;
"(" yylval = "6"; return LPAREN;
")" yylval = "7"; return RPAREN;
"," yylval = "8"; return COMMA;
{INCLUDE} yylval = "9"; return INCLUDE;
{IMPORT} yylval = "10"; return IMPORT;
{DEFINE} yylval = "11"; return DEFINE;
{MACRO} yylval = "12"; return MACRO;
{ENDM} yylval = "13"; return ENDM;
{UNDEF} yylval = "14"; return UNDEF;
{IFDEF} yylval = "15"; return IFDEF;
{IFNDEF} yylval = "16"; return IFNDEF;
{ELSE} yylval = "17"; return ELSE;
{ENDIF} yylval = "18"; return ENDIF;
{PDATE} yylval = "19"; return PDATE;
{PTIME} yylval = "20"; return PTIME;
{PLINE} yylval = "21"; return PLINE;
{PFILE} yylval = "22"; return PFILE;
{PCDATE} yylval = "23"; return PCDATE;
{PCTIME} yylval = "24"; return PCTIME;
{STRING} yylval = yytext; return STRING;
{TSTRING} strncpy(linebuf, yytext, sizeof(linebuf)); yylval = linebuf; return TSTRING;
{COMMENT} // Eat up...
[ ] conprint("%s", yytext);
[\n] lineno++; conprint("%s", yytext);
%%
/* Additional Code */
int main(int argc, char ** argv)
{
try
{
// Boiler plate code...
_memblock_ = new char[5000];
// main program...
Array<String> args;
for (unsigned long i = 0; i < argc; ++i)
{
if (i != 0)
args.insert();
args[i] = argv[i];
}
int ret = Main(args);
return ret;
}
catch (Exception e)
{
e.display();
exit(1);
}
catch (bad_alloc e)
{
delete _memblock_;
error(ERRORMSG, (char *)"Out of Memory.");
exit(1);
}
catch (...)
{
error(ERRORMSG, (char *)"Uncaught Exception.");
exit(1);
}
}
int Main(Array<String> args)
{
if (args.length() == 3)
{
FILE * input = fopen(args[1].getString().c_str(), "r");
if (!input)
{
yyerror("can't open file");
return -1;
}
yyin = input;
input_file = args[1];
output = fopen(args[2].getString().c_str(), "w+");
if (!output)
{
yyerror("can't open file for write");
return -1;
}
int ret = yyparse();
generate_defines();
generate_code();
return ret;
}
else
yyerror("can't find input file or output file.");
}
void yyerror(char const * c)
{
printf("%s", "* ERROR: ");
printf("%d: ", yylloc.first_line);
printf("@ '%s' yylval = '%s': ", yytext, yylval.getString().c_str());
printf("yychar = '%d': ", yychar);
printf("%s", c);
printf("%s", "\n");
}
int conprint(const char * format, ...)
{
va_list arg;
int done = 0;
va_start(arg, format);
out.insert();
done = vsnprintf(outbuffer, 256, format, arg);
String str = "";
if (outbuffer != NULL)
str += outbuffer;
out[outcount] = str;
++outcount;
va_end(arg);
return done;
}
void generate_code()
{
unsigned long len = out.length();
for (unsigned long i = 0; i < out.length(); ++i)
{
if (out[i].getString() == "")
out.remove(i);
}
for (unsigned long i = 0; i < out.length(); ++i)
{
fprintf(output, "%s", out[i].getString().c_str());
}
}
void generate_defines()
{
for (unsigned long i = 0; i < out.length(); ++i)
{
unsigned long index = out[i].getString().find("#define");
if (index == string::npos)
{
continue;
}
else
{
index += 7;
String str = out[i].getString().substr(index);
str = strip_quotes(str);
unsigned long index2 = str.getString().find('\"');
str = str.getString().substr(index2 + 1);
unsigned long index3 = str.getString().find('\"');
unsigned long len = index3 - index2;
str = str.getString().substr(index2, len);
bool found = false;
unsigned long index4 = 0;
for (unsigned long j = 0; j < definitions.length(); ++j)
{
if (definitions[j].name() == str)
{
found = true;
index4 = j;
}
}
if (found == true)
{
String name = definitions[index4].name();
String value = definitions[index4].value();
unsigned long line = definitions[index4].line();
for (unsigned long j = i; j < out.length(); ++j)
{
if (line > 0)
{
if (j >= line)
;
else
{
if (name == out[j])
out[j] = value;
}
}
else
{
if (name == out[j])
out[j] = value;
}
}
}
out.remove(i);
out.remove(i - 1);
}
}
}
PNFPP.YPP
Code:
%{
/* Prologue */
#include <desLib/desLib.hpp>
#include <process.h>
#include <cctype>
#include <ctime>
#define YYSTYPE String
class PNFPP_Def
{
protected:
String itsname;
String itsvalue;
unsigned long itsline;
public:
PNFPP_Def(String name = "", String value = "", unsigned long line = 0);
PNFPP_Def(int value);
PNFPP_Def(const PNFPP_Def & def);
~PNFPP_Def();
void name(String name);
String name();
void value(String value);
String value();
void line(unsigned long line);
unsigned long line();
PNFPP_Def & operator =(const PNFPP_Def & def);
};
PNFPP_Def::PNFPP_Def(String name, String value, unsigned long line)
{
itsname = name;
itsvalue = value;
itsline = line;
}
PNFPP_Def::PNFPP_Def(int value)
{
itsname = "";
itsvalue = "";
itsline = 0;
}
PNFPP_Def::~PNFPP_Def()
{
}
PNFPP_Def::PNFPP_Def(const PNFPP_Def & def)
{
itsname = def.itsname;
itsvalue = def.itsvalue;
itsline = def.itsline;
}
void PNFPP_Def::name(String name)
{
itsname = name;
}
String PNFPP_Def::name()
{
return itsname;
}
void PNFPP_Def::value(String value)
{
itsvalue = value;
}
String PNFPP_Def::value()
{
return itsvalue;
}
void PNFPP_Def::line(unsigned long line)
{
itsline = line;
}
unsigned long PNFPP_Def::line()
{
return itsline;
}
PNFPP_Def & PNFPP_Def::operator =(const PNFPP_Def & def)
{
if (this == &def)
return *this;
itsname = def.itsname;
itsvalue = def.itsvalue;
return *this;
}
class PNFPP_Macro
{
protected:
String itsname;
Array<String> itsparameters;
Array<String> itsvalues;
public:
PNFPP_Macro(String n = "");
PNFPP_Macro(int value);
PNFPP_Macro(const PNFPP_Macro & macro);
~PNFPP_Macro();
String name();
void name(String n);
Array<String> parameters();
void parameters(Array<String> p);
String parameter(unsigned long index);
void parameter(unsigned long index, String p);
Array<String> & values();
String value(unsigned long index);
void value(unsigned long index, String v);
};
PNFPP_Macro::PNFPP_Macro(String n)
{
itsname = n;
}
PNFPP_Macro::PNFPP_Macro(int value)
{
}
PNFPP_Macro::PNFPP_Macro(const PNFPP_Macro & macro)
{
itsname = macro.itsname;
itsvalues = macro.itsvalues;
itsparameters = macro.itsparameters;
}
PNFPP_Macro::~PNFPP_Macro()
{
}
String PNFPP_Macro::name()
{
return itsname;
}
void PNFPP_Macro::name(String n)
{
itsname = n;
}
Array<String> PNFPP_Macro::parameters()
{
return itsparameters;
}
void PNFPP_Macro::parameters(Array<String> p)
{
itsparameters = p;
}
String PNFPP_Macro::parameter(unsigned long index)
{
if (index >= itsparameters.length())
{
char * num = ltoa(index, num, 10);
throw Exception((String)"get: Macro index out of bounds. index = " + num, __FILE__, __LINE__);
}
return itsparameters[index];
}
void PNFPP_Macro::parameter(unsigned long index, String p)
{
if (index >= itsparameters.length())
{
char * num = ltoa(index, num, 10);
throw Exception((String)"put: Macro index out of bounds. index = " + num, __FILE__, __LINE__);
}
itsparameters[index] = p;
}
Array<String> & PNFPP_Macro::values()
{
return itsvalues;
}
String PNFPP_Macro::value(unsigned long index)
{
if (index >= itsvalues.length())
{
char * num = ltoa(index, num, 10);
throw Exception((String)"get: Macro index out of bounds. index = " + num, __FILE__, __LINE__);
}
return itsvalues[index];
}
void PNFPP_Macro::value(unsigned long index, String v)
{
if (index >= itsvalues.length())
{
char * num = ltoa(index, num, 10);
throw Exception((String)"put: Macro index out of bounds. index = " + num, __FILE__, __LINE__);
}
itsvalues[index] = v;
}
void yyerror(char const * c);
int yylex();
int Main(Array<String> args);
String strip_quotes(String str);
String remove_extension(String file);
String get_extension(String file);
String add_quotes(String str);
int conprint(const char * format, ...);
void generate_code();
void generate_defines();
String input_file = "";
FILE * output;
unsigned long outcount = 0;
Array<String> files;
Array<PNFPP_Def> definitions;
Array<PNFPP_Macro> macros;
unsigned long macroindex = 0;
unsigned long macrovalueindex = 0;
Array<String> macrobuffer;
Array< Array<String> > replacements;
Array< Array<String> > macrovalues;
unsigned long parametercounter = 0;
unsigned long lineno = 1;
%}
/* Bison Declarations */
%expect 2
%locations
%token OPLT
%token OPGT
%token OPST
%token OPTK
%token OPPAREN
%token LPAREN
%token RPAREN
%token COMMA
%token TSTRING
%token STRING
%token INCLUDE
%token IMPORT
%token DEFINE
%token MACRO
%token ENDM
%token UNDEF
%token IFDEF
%token IFNDEF
%token ELSE
%token ENDIF
%token PDATE
%token PTIME
%token PLINE
%token PFILE
%token PCDATE
%token PCTIME
%%
/* Grammar Rules */
input: // Empty
| line input
;
line: '\n'
| command
| string2
| error
{
yyerrok;
}
;
command: include_command
| import_command
| define_command
| macro_command
| if_command
| predefined_command
;
include_command: INCLUDE STRING
{
Array<String> args;
args[0] = (char *)"PNFPP";
args.insert();
args[1] = strip_quotes($2);
args.insert();
args[2] = remove_extension(strip_quotes($2)) + ".pnfpp";
args.insert();
args[args.length() - 1] = (char *)"";
char ** args2 = new char * [args.length()];
for (unsigned long i = 0; i < args.length(); ++i)
args2[i] = (char *)args[i].getString().c_str();
args2[args.length() - 1] = NULL;
int ret = _spawnvp(_P_WAIT, "PNFPP", args2);
delete args2;
if (ret == -1 && errno != 0)
{
ret = 1;
error(ERRORMSG, (char*)"Error running PNFPP program.");
}
if (ret == -1)
{
yyerror("File cannot include itself.");
exit(-1);
}
fin.open((remove_extension(strip_quotes($2)) + ".pnfpp").getString().c_str());
if (!fin)
yyerror("Can't open file.");
String str;
unsigned long i = 0;
do
{
if (i != 0)
conprint("\n");
fin >> str;
conprint("%s", str.getString().c_str());
++i;
} while (!fin.eof());
fin.close();
}
| INCLUDE OPLT STRING OPGT
{
String extension = get_extension(strip_quotes($3));
$3 = "..\\include\\" + remove_extension(strip_quotes($3));
Array<String> args;
args[0] = (char *)"PNFPP";
args.insert();
args[1] = $3 + extension;
args.insert();
args[2] = $3 + ".pnfpp";
args.insert();
args[args.length() - 1] = (char *)"";
char ** args2 = new char * [args.length()];
for (unsigned long i = 0; i < args.length(); ++i)
args2[i] = (char *)args[i].getString().c_str();
args2[args.length() - 1] = NULL;
int ret = _spawnvp(_P_WAIT, "PNFPP", args2);
delete args2;
if (ret == -1 && errno != 0)
{
ret = 1;
error(ERRORMSG, (char*)"Error running PNFPP program.");
}
if (ret == -1)
{
yyerror("File cannot include itself.");
exit(-1);
}
fin.open(($3 + ".pnfpp").getString().c_str());
if (!fin)
yyerror("Can't open file for fin.");
String str;
unsigned long i = 0;
do
{
if (i != 0)
conprint("\n");
fin >> str;
conprint("%s", str.getString().c_str());
++i;
} while (!fin.eof());
fin.close();
}
;
import_command: IMPORT STRING
{
bool found = false;
for (unsigned long i = 0; i < files.length(); ++i)
{
if (files[i] == $2)
found = true;
}
if (found == true)
;
else
{
Array<String> args;
args[0] = (char *)"PNFPP";
args.insert();
args[1] = strip_quotes($2);
args.insert();
args[2] = remove_extension(strip_quotes($2)) + ".pnfpp";
args.insert();
args[args.length() - 1] = (char *)"";
char ** args2 = new char * [args.length()];
for (unsigned long i = 0; i < args.length(); ++i)
args2[i] = (char *)args[i].getString().c_str();
args2[args.length() - 1] = NULL;
int ret = _spawnvp(_P_WAIT, "PNFPP", args2);
delete args2;
if (ret == -1 && errno != 0)
{
ret = 1;
error(ERRORMSG, (char*)"Error running PNFPP program.");
}
if (ret == -1)
{
yyerror("File cannot include itself.");
exit(-1);
}
fin.open((remove_extension(strip_quotes($2)) + ".pnfpp").getString().c_str());
if (!fin)
yyerror("Can't open file.");
String str;
unsigned long i = 0;
do
{
if (i != 0)
conprint("\n");
fin >> str;
conprint("%s", str.getString().c_str());
++i;
} while (!fin.eof());
if (files.length() > 1)
files.insert();
files[files.length() - 1] = $2;
}
}
| IMPORT OPLT STRING OPGT
{
String extension = get_extension(strip_quotes($3));
$3 = "..\\include\\" + remove_extension(strip_quotes($3));
bool found = false;
for (unsigned long i = 0; i < files.length(); ++i)
{
if (files[i] == $3)
found = true;
}
if (found == true)
;
else
{
Array<String> args;
args[0] = (char *)"PNFPP";
args.insert();
args[1] = $3 + extension;
args.insert();
args[2] = $3 + ".pnfpp";
args.insert();
args[args.length() - 1] = (char *)"";
char ** args2 = new char * [args.length()];
for (unsigned long i = 0; i < args.length(); ++i)
args2[i] = (char *)args[i].getString().c_str();
args2[args.length() - 1] = NULL;
int ret = _spawnvp(_P_WAIT, "PNFPP", args2);
delete args2;
if (ret == -1 && errno != 0)
{
ret = 1;
error(ERRORMSG, (char*)"Error running PNFPP program.");
}
if (ret == -1)
{
yyerror("File cannot include itself.");
exit(-1);
}
fin.open(($3 + ".pnfpp").getString().c_str());
if (!fin)
yyerror("Can't open file.");
String str;
unsigned long i = 0;
do
{
if (i != 0)
conprint("\n");
fin >> str;
conprint("%s", str.getString().c_str());
++i;
} while (!fin.eof());
if (files.length() > 1)
files.insert();
files[files.length() - 1] = $3;
}
}
;
define_command: DEFINE STRING string
{
bool found = false;
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (definitions[i].name() == strip_quotes($2))
{
if (definitions[i].value() != strip_quotes($3))
definitions[i].value(strip_quotes($3));
found = true;
}
}
if (found == false)
{
definitions[definitions.length() - 1].name(strip_quotes($2));
definitions[definitions.length() - 1].value(strip_quotes($3));
definitions.insert();
}
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (strip_quotes($3) == definitions[i].name())
definitions[definitions.length() - 2].value(definitions[i].value());
}
conprint("#define %s %s", $2.getString().c_str(), $3.getString().c_str());
}
| DEFINE STRING string_cmd OPTK string_cmd
{
String tokenized = add_quotes($3 + $5);
bool found = false;
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (definitions[i].name() == strip_quotes($2))
{
if (definitions[i].value() != strip_quotes(tokenized))
definitions[i].value(strip_quotes(tokenized));
found = true;
}
}
if (found == false)
{
definitions[definitions.length() - 1].name(strip_quotes($2));
definitions[definitions.length() - 1].value(strip_quotes(tokenized));
definitions.insert();
}
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (strip_quotes(tokenized) == definitions[i].name())
definitions[definitions.length() - 2].value(definitions[i].value());
}
conprint("#define %s %s", $2.getString().c_str(), tokenized.getString().c_str());
}
| DEFINE STRING OPST string
{
bool found = false;
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (definitions[i].name() == strip_quotes($2))
{
if (definitions[i].value() != $4)
definitions[i].value($4);
found = true;
}
}
if (found == false)
{
definitions[definitions.length() - 1].name(strip_quotes($2));
definitions[definitions.length() - 1].value($4);
definitions.insert();
}
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (strip_quotes($4) == definitions[i].name())
definitions[definitions.length() - 2].value(add_quotes(definitions[i].value()));
}
conprint("#define %s %s", $2.getString().c_str(), add_quotes($4).getString().c_str());
}
| UNDEF STRING
{
bool found = false;
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (definitions[i].name() == strip_quotes($2))
{
definitions[i].line(outcount);
found = true;
}
}
}
;
string2: STRING
{
conprint("%s", $1.getString().c_str());
}
| TSTRING
{
conprint("%s", $1.getString().c_str());
}
;
string: STRING
{
String str = yytext;
String str2 = "";
bool saw = false;
for (unsigned long i = 0; i < str.length(); ++i)
{
if (str[i] == '\\')
{
if ((i - 1) > 0)
{
if (str[i - 1] == '\\')
saw = true;
}
if ((i + 1) == str.length())
yyerror("Unterminated escape sequence.");
else
{
switch (str[i + 1])
{
case '\\':
str2 += '\\';
break;
case 'n':
str2 += '\n';
break;
default:
if (isdigit((int)str[i + 1]) && !saw)
{
String str3 = "";
unsigned long j;
for (j = i + 1; isdigit((int)str[j]) && j < str.length(); ++j)
{
str3 += str[j];
i = j;
}
unsigned long num = atol(str3.getString().c_str());
str2 += (char)num;
}
else if (isdigit((int)str[i + 1]) && saw)
continue;
else
yyerror("Unknown escape sequence.");
break;
} // End switch
} // End else (if ((i + 1) == str.length()))
} // End if (str[i] == '\\')
else
{
str2 += str[i];
} // End else (if (str[i] == '\\'))
} // End for loop
$$ = str2;
} // End string
;
string_cmd: string
{
$$ = strip_quotes($1);
}
| OPST string
{
$$ = $2;
}
;
macro_command: macro_definition
| macro_call
;
macro_definition: MACRO STRING OPPAREN
{
Array<String> strs;
strs[0] = "";
bool found = false;
for (unsigned long i = 0; i < macros.length(); ++i)
{
if (macros[i].name() == strip_quotes($2))
found = true;
}
if (found)
yyerror("Macro already defined.");
macros[macros.length() - 1].name(strip_quotes($2));
macros[macros.length() - 1].parameters() = strs;
}
tstrings
{
for (unsigned long i = 0; i < macros[macros.length() - 1].values().length(); ++i)
macros[macros.length() - 1].value(i, $5);
macrovalues[macrovalues.length() - 1] = macros[macros.length() - 1].values();
}
ENDM
{
macros.insert();
}
| MACRO STRING LPAREN
{
bool found = false;
for (unsigned long i = 0; i < macros.length(); ++i)
{
if (macros[i].name() == strip_quotes($2))
found = true;
}
if (found)
yyerror("Macro already defined.");
macros[macros.length() - 1].name(strip_quotes($2));
}
parameter_list RPAREN
{
Array<String> strs;
for (unsigned i = 0, j = 0; i < $4.length(); ++i)
{
if ($4[i] == ' ')
{
++j;
strs.insert();
continue;
}
strs[j] += $4[i];
}
macros[macros.length() - 1].parameters() = strs;
}
tstrings
{
String str = "";
for (unsigned long i = 0, j = 0; i < $7.length(); ++i)
{
if ($7[i] == ' ')
{
macros[macros.length() - 1].values().insert();
macrovalues[macrovalues.length() - 1].insert();
++j;
str = "";
continue;
}
str += $7[i];
macros[macros.length() - 1].value(j, str);
}
macrovalues[macrovalues.length() - 1] = macros[macros.length() - 1].values();
}
ENDM
{
macros.insert();
replacements.insert();
macrovalues.insert();
}
;
parameter_list: STRING
{
macros[macros.length() - 1].parameters().insert();
replacements[replacements.length() - 1].insert();
$$ = strip_quotes($1);
}
| parameter_list COMMA parameter_list
{
$$ = strip_quotes($1) + " " + strip_quotes($3);
}
;
tstrings: TSTRING
{
$$ = $1;
}
| tstrings TSTRING
{
$$ = $1 + " " + $2;
}
;
macro_call: STRING OPPAREN
{
bool found = false;
for (unsigned long i = 0; i < macros.length(); ++i)
{
if (macros[i].name() == strip_quotes($1))
{
macroindex = i;
found = true;
}
}
if (!found)
yyerror("Macro not defined.");
for (unsigned long i = 0; i < macros[macroindex].values().length(); ++i)
conprint("%s", macros[macroindex].values()[i].getString().c_str());
}
| STRING LPAREN
{
bool found = false;
for (unsigned long i = 0; i < macros.length(); ++i)
{
if (macros[i].name() == strip_quotes($1))
{
macroindex = i;
found = true;
}
}
if (!found)
yyerror("Macro not defined.");
macrovalues[macroindex] = macros[macroindex].values();
}
parameter_list2
{
Array<String> strs;
strs[0] = "";
for (unsigned i = 0, j = 0; i < $4.length(); ++i)
{
if ($4[i] == ' ')
{
++j;
strs.insert();
strs[j] = "";
continue;
}
strs[j] += $4[i];
}
replacements[macroindex] = strs;
for (unsigned long i = 0; i < macros[macroindex].parameters().length(); ++i)
{
for (unsigned long j = 0; j < macrovalues[macroindex].length(); ++j)
{
if (macros[macroindex].parameter(i) == macrovalues[macroindex][j])
{
macrovalues[macroindex][j] = replacements[macroindex][i];
}
}
}
}
RPAREN
{
for (unsigned long i = 0; i < macrovalues[macroindex].length(); ++i)
{
unsigned j = i;
++j;
j == macrovalues[macroindex].length() ? conprint("%s", macrovalues[macroindex][i].getString().c_str()) :
conprint("%s ", macrovalues[macroindex][i].getString().c_str());
}
parametercounter = 0;
}
;
parameter_list2:
STRING
{
$$ = strip_quotes($1);
++parametercounter;
}
| parameter_list2 COMMA parameter_list2
{
$$ = $1 + " " + $3;
}
;
if_command: ifdef
| ifndef
;
ifdef: IFDEF STRING tstrings
{
bool found = false;
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (definitions[i].name() == strip_quotes($2))
{
if (definitions[i].line() == 0)
found = true;
}
}
if (found == true)
{
conprint("%s", $3.getString().c_str());
}
}
ENDIF
| IFDEF STRING tstrings ELSE tstrings
{
bool found = false;
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (definitions[i].name() == strip_quotes($2))
{
if (definitions[i].line() == 0)
found = true;
}
}
if (found == true)
{
conprint("%s", $3.getString().c_str());
}
else
{
conprint("%s", $5.getString().c_str());
}
}
ENDIF
;
ifndef: IFNDEF STRING tstrings
{
bool found = false;
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (definitions[i].name() == strip_quotes($2))
{
if (definitions[i].line() == 0)
found = true;
}
}
if (found == false)
{
conprint("%s", $3.getString().c_str());
}
}
ENDIF
| IFNDEF STRING tstrings ELSE tstrings
{
bool found = false;
for (unsigned long i = 0; i < definitions.length(); ++i)
{
if (definitions[i].name() == strip_quotes($2))
{
if (definitions[i].line() == 0)
found = true;
}
}
if (found == false)
{
conprint("%s", $3.getString().c_str());
}
else
{
conprint("%s", $5.getString().c_str());
}
}
ENDIF
;
predefined_command: PDATE
{
time_t t = time(0);
struct tm * now = localtime(&t);
conprint("%d-%d-%d", (now->tm_year + 1900), (now->tm_mon + 1), now->tm_mday);
}
| PTIME
{
time_t t = time(0);
struct tm * now = localtime(&t);
conprint("%d:%d:%d", now->tm_hour, now->tm_min, now->tm_sec);
}
| PLINE
{
conprint("%d", lineno);
}
| PFILE
{
conprint("%s", input_file.getString().c_str());
}
| PCDATE
{
conprint("%s", __DATE__);
}
| PCTIME
{
conprint("%s", __TIME__);
}
;
%%
/* Additional C/C++ Code */
String strip_quotes(String str)
{
String str2 = "";
for (unsigned long i = 0; i < str.length(); ++i)
{
if (i == 0)
continue;
else if (i == str.length() - 1)
continue;
else
str2 += str[i];
}
return str2;
}
String remove_extension(String file)
{
String ret;
file = strrev((char *)file.getString().c_str());
unsigned long pos = file.getString().find('.');
if (pos == string::npos)
ret = strrev((char *)file.getString().c_str());
ret = file.getString().substr(pos + 1);
ret = strrev((char *)ret.getString().c_str());
return ret;
}
String get_extension(String file)
{
String extension;
unsigned long index = file.getString().find(".");
if (index == string::npos)
{
extension = file;
return extension;
}
extension = file.getString().substr(index);
return extension;
}
String add_quotes(String str)
{
String str2 = "\"";
for (unsigned long i = 0; i < str.length(); ++i)
str2 += str[i];
str2 += '\"';
return str2;
}
File to play around with:
Code:
' This is a comment...
#define "Hello" "Block"
#import "b.txt"
Hello World!
#macro "World2"()
Hello World!
I am a cat.
#endm
"World2"()
#macro "World3"("a")
Hello a
#endm
"World3"("Post")
#ifdef "Hello"
Kitty cat.
#endif
#undef "Hello"
#ifdef "Hello"
Kitty cat.
#endif
Hello World!
"World3"("Fence")
' #macro "times"()
' a * b
' #endm
' #macro "times2"("a", "b")
' a * b
' #endm
' "times"()
' "times"("2", "3")
#ifdef "Turkey"
Hello World!
#else
I am a fiddle.
#endif
#ifndef "Turkey"
Hello World!
#endif
#define "Amy" ""
#ifndef "Amy"
Hello World!
#else
Garbage disposal.
#endif
_DATE()
_TIME()
_LINE()
_FILE()
**************************
Compiled date is: _CDATE()
Compiled time is: _CTIME()
You run the program with:
03-26-2017, 12:06 AM
#2
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
By adding some output statements, I can see that parameters, & values are not being stored right, or something clobbers them later...
03-26-2017, 12:07 AM
#3
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
That is, as I come back to it later. This doesn't give me a big clue yet...
03-26-2017, 02:13 AM
#4
Moderator
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,263
Welcome back des_a!
Where to start...?
First, you say you are having problems getting macros with parameters to work, but you don't provide any details about how you expect them to work and how they are failing. We cannot provide specific help without a more specific description of the problem.
If you could provide a complete example, including the input text, the expected output or behavior and what you are actually getting would be the best way to approach asking for help with that.
I have reviewed our
most recent discussion from last June , which oddly enough I remember (even though I cannot remember what I had for breakfast!). You have certainly done a lot of work since then.
I have spent some time trying to understand the code posted in this thread and would like to offer some constructive comments on it, which may or may not bear directly on your macro problems.
I tried to extract your grammer rules into a form that could stand on it's own without the action code to make your PNF language itself a bit more clear. Here is the result with comments below:
Code:
%%
/* Grammar Rules */
NOTE: {..$x..} indicates symbol values referenced inline in respectiv action code blocks
input: // Empty
| line input
;
line: '\n'
| command
| string2
| error
{
yyerrok;
}
;
command: include_command
| import_command
| define_command
| macro_command
| if_command
| predefined_command
;
include_command: INCLUDE STRING {..$2..}
| INCLUDE OPLT STRING OPGT {..$3..}
;
import_command: IMPORT STRING {..$2..}
| IMPORT OPLT STRING OPGT {..$3..}
;
define_command: DEFINE STRING string {..$2, $3..}
| DEFINE STRING string_cmd OPTK string_cmd {..$2, $3, $5..}
| DEFINE STRING OPST string {..$2, $4..}
| UNDEF STRING {..$2..}
;
string2: STRING {..$1..}
| TSTRING {..$1..}
;
string: STRING {..yytext, $$..}
;
string_cmd: string {..$$, $1..}
| OPST string {..$$, $2..}
;
macro_command: macro_definition
| macro_call
;
macro_definition: MACRO STRING OPPAREN {..$2..} tstrings {..$5..} ENDM {..}
| MACRO STRING LPAREN {..$2..} parameter_list RPAREN {..$4..} tstrings {..$7..} ENDM {..}
;
parameter_list: STRING {..$$, $1..}
| parameter_list COMMA parameter_list {..$$, $1, $3..}
;
tstrings: TSTRING {..$$, $1..}
| tstrings TSTRING {..$$, $1, $2..}
;
macro_call: STRING OPPAREN {..$1..}
| STRING LPAREN {..$1..} parameter_list2 {..$4..} RPAREN {..}
;
parameter_list2: STRING {..$$, $1..}
| parameter_list2 COMMA parameter_list2 {..$$, $1, $3..}
;
if_command: ifdef
| ifndef
;
ifdef: IFDEF STRING tstrings {..$2, $3..} ENDIF
| IFDEF STRING tstrings ELSE tstrings {..$2, $3, $5..} ENDIF
;
ifndef: IFNDEF STRING tstrings {..$2, $3..} ENDIF
| IFNDEF STRING tstrings ELSE tstrings {..$2, $3, $5..} ENDIF
;
predefined_command: PDATE
| PTIME
| PLINE
| PFILE
| PCDATE
| PCTIME
;
I have removed the action code and listed only the symbol values referenced in each block. While I will not say that I followed all the code, the above outline does show that you never actually use anything but string values, in particular you never look at any of the token values (yylval) which you set in the lexer code (more on that below).
You do a lot of repetitive scrubbing of strings in each rule which should probably be done once in a single rule then passed up the parse tree. It also looks as if you further subdivide the string values in your code, which would be much better done in the lexer and returned as separate tokens.
You also keep all the state information within your own code and make only limited use of non-terminals (by setting $$ values) to pass state up the parse tree.
Which is not to say that you may not get it to do what you want, but it makes the grammer rules obscure and means that you are still not using the power of the parser in the way it is intended. You are using the grammer more like a complex switch{...} block than to define an actual language. As in noted in our previous conversations, you are duplicating too much in your own code that you get for free from the parser, once you have a well defined grammer. Please take that as a constructive comment.
Also, you reference
yytext in your
string: rule, but yytext is a lexer variable not visible to the parser (unless you have defined it somewhere). This is probably an error.
Next, the lexer...
I found your reuse of token names confusing. Your tokens are defined in the Bison code, and are included in the lexer via the
pnfpp.tab.cc include. These are all integer values which the lexer should return as terminals (i.e. tokens) when the parser calls yylex().
But, after that include, you reuse those same token names for regular expression substitutions. When you then return those to the parser, do they have different values than you, or the parser expects?
UPDATE: The
enum definition and the
return value are both in C language context whereas the
regex substitutions are pre-processed by Flex. The names do not collide. So this is really a matter of style, but no less confusing.
For example, in the parser code you define these...
Code:
%token OPLT
%token OPGT
%token OPST
%token OPTK
...
Which are passed into the lexerr via pnfpp.tab.cc like this...
Code:
enum yytokentype {
OPLT = 258,
OPGT = 259,
OPST = 260,
OPTK = 261,
...};
But then you redefine those symbols in the lexer as literal characters...
Code:
OPLT "<"
OPGT ">"
OPST "#"
OPTK "##"
...
And finally you use them in lexer rules and return them to the parser...
Code:
{OPLT} yylval = "0"; return OPLT;
{OPGT} yylval = "1"; return OPGT;
{OPST} yylval = "2"; return OPST;
{OPTK} yylval = "3"; return OPTK;
...
Very confusing for me and maybe for the parser!
Additionally, you are setting an integer value, yylval, for each of those cases... but never using it for anything as far as I could tell. It makes me wonder if you think they are used as the token value itself...?
I suspect there is still some confusion about just how the parser and lexer interact, and about what is visible in each context. A simple fix for the above would be to simply use different names for the substitutions in the lexer, or skip the definitions and use the regular expressions inline.
So, before returning to the grammer, make sure that the lexer returns the tokens expected by the parser.
And again, please try to provide a description of the specific problem which includes an example of the input text, how you expect it to be handled by the parser and the expected output. (Also note that we cannot compile the parser due to the dependence on your DesLib code).
All the time I have for tonight, hope this helps!
Last edited by astrogeek; 03-27-2017 at 02:34 PM .
Reason: Confirmed non-collision of enum/substitutions
1 members found this post helpful.
03-26-2017, 04:30 AM
#5
Member
Registered: Apr 2010
Location: Geneva - Switzerland ( Bordeaux - France / Montreal - QC - Canada)
Distribution: Slackware 14.2 - 32/64bit
Posts: 609
Quote:
Originally Posted by
astrogeek
Where to start...?
Wow Astrogeek, nice answer, you really took time for that ! Congratulations !
Bests
Garry
03-28-2017, 12:00 AM
#6
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
Now I am one variable being set right to what should be it working okay. I am just needing the parameter variable set right.
03-28-2017, 12:03 AM
#7
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
So, I have used yylval. According to Google, yylval is what sets the $[*] variables in bison, and that is a way to access it from flex. I have set it and am therefore using it in a few places now. True that I am not using every value I set in it, but I "think" that's okay. What the C++ code it generates is, I have no idea. I didn't pry to find out. I just want it to work okay when I compile it for the final step.
03-28-2017, 12:04 AM
#8
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
Yes that seems to be the grammer without the actions. That part is working, it seems. It seems that the part that is not right now, is the actions.
03-28-2017, 12:05 AM
#9
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
yytext is available to the parser as well as the lexer. It does indeed compile, and work as is.
Last edited by des_a; 03-28-2017 at 12:06 AM .
Reason: Forgot something...
03-28-2017, 12:08 AM
#10
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
Quote:
But, after that include, you reuse those same token names for regular expression substitutions. When you then return those to the parser, do they have different values than you, or the parser expects?
Don't know what you mean. If it's a worthy point, please explain.
03-28-2017, 12:11 AM
#11
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
Quote:
And again, please try to provide a description of the specific problem which includes an example of the input text, how you expect it to be handled by the parser and the expected output. (Also note that we cannot compile the parser due to the dependence on your DesLib code).
Sorry for that. If you at some point really need that code, I will try to see if there is a mechanism to attatch a zip file full of the deslib code. I realize I keep posting this, and it is essentially public, but please don't let it further than I let it, which I just realized is a confusing statement, but I think you get it anyway.
03-28-2017, 12:12 AM
#12
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
Now for more information on what I expect it to do when it is finished and working properly...
03-28-2017, 12:13 AM
#13
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
Given this code:
Code:
#macro "a"()
a * b
#endm
"a"()
#macro "str"("a")
a
#endm
"str"("Hello")
#macro "times" ("a", "b")
a * b
#endm
"times"("2", "3")
...
03-28-2017, 12:14 AM
#14
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
It should give this output possibly with some more whitespace in there:
03-28-2017, 12:16 AM
#15
Senior Member
Registered: Sep 2006
Posts: 1,416
Original Poster
Rep:
Right now it gives this output:
Code:
a * ba * ba * b
a
a * b
...Which is NOT what I want.
All times are GMT -5. The time now is 04:57 PM .
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know .
Latest Threads
LQ News