LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
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


Reply
  Search this Thread
Old 03-25-2017, 01:58 AM   #1
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416
Blog Entries: 43

Rep: Reputation: 36
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:
Code:
PNFPP a.txt c.txt
 
Old 03-26-2017, 12:06 AM   #2
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
By adding some output statements, I can see that parameters, & values are not being stored right, or something clobbers them later...
 
Old 03-26-2017, 12:07 AM   #3
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
That is, as I come back to it later. This doesn't give me a big clue yet...
 
Old 03-26-2017, 02:13 AM   #4
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,263
Blog Entries: 24

Rep: Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194
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.
Old 03-26-2017, 04:30 AM   #5
NoStressHQ
Member
 
Registered: Apr 2010
Location: Geneva - Switzerland ( Bordeaux - France / Montreal - QC - Canada)
Distribution: Slackware 14.2 - 32/64bit
Posts: 609

Rep: Reputation: 221Reputation: 221Reputation: 221
Quote:
Originally Posted by astrogeek View Post
Where to start...?
Wow Astrogeek, nice answer, you really took time for that ! Congratulations !

Bests

Garry
 
Old 03-28-2017, 12:00 AM   #6
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
Now I am one variable being set right to what should be it working okay. I am just needing the parameter variable set right.
 
Old 03-28-2017, 12:03 AM   #7
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
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.
 
Old 03-28-2017, 12:04 AM   #8
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
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.
 
Old 03-28-2017, 12:05 AM   #9
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
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...
 
Old 03-28-2017, 12:08 AM   #10
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
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.
 
Old 03-28-2017, 12:11 AM   #11
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
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.
 
Old 03-28-2017, 12:12 AM   #12
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
Now for more information on what I expect it to do when it is finished and working properly...
 
Old 03-28-2017, 12:13 AM   #13
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
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")
...
 
Old 03-28-2017, 12:14 AM   #14
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
It should give this output possibly with some more whitespace in there:

Code:
a * b
Hello
2 * 3
 
Old 03-28-2017, 12:16 AM   #15
des_a
Senior Member
 
Registered: Sep 2006
Posts: 1,416

Original Poster
Blog Entries: 43

Rep: Reputation: 36
Right now it gives this output:

Code:
 
  



a * ba * ba * b


 




a


   
  



 a * b
...Which is NOT what I want.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] PNFPP: Syntax Errors while parsing strings des_a Programming 6 06-14-2016 01:22 AM
what are self-referential macros? ananth86coolguy Linux - Newbie 1 04-24-2010 07:38 AM
Macros In C drumstick Programming 8 11-21-2005 04:37 PM
Macros Twi7ch Linux - General 2 08-27-2005 09:37 PM
Html macros in Vi fieldmethods Linux - Software 1 12-20-2002 10:01 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:57 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration