I can't understand how to embed C++ user-defined class into bison parser. Here is what I have (just some necessary pieces; if you need, I can post all code).
scanner.l
%{
#include "parser.tab.h"
#include "types.h"
#include <iostream>
#include <string>
#define YY_DECL extern "C" int yylex()
using namespace std;
int chars = 0;
int words = 0;
int lines = 0;
extern "C" {
int yylex(void);
} /* extern "C" */
%}
%%
"none" {
yylval.none_value = none_type();
return NONE;
} /* none type */
{DIGIT_BIN}|{DIGIT_OCT}|{DIGIT_DEC}|{DIGIT_HEX} {
yylval.int_value = atoi(yytext);
return INT;
} /* int type */
parser.y
%{
#include "types.h"
#include <iostream>
using namespace std;
void yyerror(const char *error) {
cerr << error << endl;
} /* error handler */
extern "C" {
int yylex(void);
int yyparse(void);
int yywrap() { return 1; }
} /* extern "C" */
%}
%union {
none_type none_value; /* HERE IS WHAT I WANT */
int int_value;
} /* union */
%token <none_value> NONE
%token <int_value> INT
types.h
#include <iostream>
class none_type {
public:
none_type(void);
~none_type();
}; /* none_type */
As you see the code here is not full, but it should be enough to describe what I want. Everything what I do with default C++ types works well; can I implement my own classes?
Compiler returns such errors:
parser.y:20:3: error: 'none_value' does not name a type
In file included from scanner.l:3:0:
parser.y:20:3: error: 'none_value' does not name a type
scanner.l: In function 'int yylex()':
scanner.l:54:32: error: cannot convert 'none_type' to 'int' in assignment
make: *** [caesar] Error 1
Thanks in advance!
When I compile your code with bison/g++ I get the errors:
parser.y:16:15: error: member ‘none_type YYSTYPE::none_value’ with constructor not allowed in union
parser.y:16:15: error: member ‘none_type YYSTYPE::none_value’ with destructor not allowed in union
parser.y:16:15: note: unrestricted unions only available with -std=c++0x or -std=gnu++0x
which tells you exactly what the problem is -- you can't put a non-POD type in a union, because the compiler can't tell which ctor/dtor to call for it. Note the comment that you CAN do it in C++ 11, but that doesn't really help, since in that case it won't call the ctor/dtor for you automatically, so stuff will simply not be cunstructed or destroyed properly.
If you want to play with putting genuine objects on your stack, then please, have a look at the current master branch of Bison, where you can run examples such as the following
%token <::std::string> TEXT;
%token <int> NUMBER;
%token END_OF_FILE 0;
%type <::std::string> item;
%type <::std::list<std::string>> list;
%printer { yyoutput << $$; } <int> <::std::string> <::std::list<std::string>>;
%%
result:
list { std::cout << $1 << std::endl; }
;
list:
/* nothing */ { /* Generates an empty string list */ }
| list item { std::swap ($$, $1); $$.push_back ($2); }
;
item:
TEXT { std::swap ($$, $1); }
| NUMBER { $$ = string_cast ($1); }
;
%%
// The yylex function providing subsequent tokens:
// TEXT "I have three numbers for you:"
// NUMBER 1
// NUMBER 2
// NUMBER 3
// TEXT " and that's all!"
// END_OF_FILE
static
yy::parser::symbol_type
yylex ()
{
static int stage = -1;
++stage;
yy::parser::location_type loc(0, stage + 1, stage + 1);
switch (stage)
{
case 0:
return yy::parser::make_TEXT ("I have three numbers for you.", loc);
case 1:
case 2:
case 3:
return yy::parser::make_NUMBER (stage, loc);
case 4:
return yy::parser::make_TEXT ("And that's all!", loc);
default:
return yy::parser::make_END_OF_FILE (loc);
}
}
Having opinions from possible users of this feature would be most useful. For instance on help-bison at gnu.org. See https://savannah.gnu.org/git/?group=bison for Git access to the repository.
Related
I wrote this code and was just trying to continue writing a function called register. I choose to set it to void because i am not certain if i am going to return anything at the moment. The Expected unqualified-id seems to show up when you put a semicolon in the wrong place, but i cant see that i make that error here..
I tried to comment out the menu.h include and all the three functions i get from the header file. No difference.
#include <iostream>
#include <string>
#include "menu.h"
//From the menu.h header file
int mainMenu();
int customerMenu();
int librarianMenu();
void register() { //Here the error appears.
}
int main () {
int runFlag = 1;
while(runFlag == 1) {
int mainMenuChoice = mainMenu();
if (mainMenuChoice == 1) {
customerMenu();
}
else if(mainMenuChoice == 2) {
librarianMenu();
}
}
}
I am trying to implement a SystemC basic TLM test bench for an adder module I created using basic simple_initiator_socket and simple_target_socket.
Currently the build is failing and I am having trouble diagnosing why.
Here are the implementations for the three main modules, the adder, the test bench, and the main module that instantiates both and initiates dataflow.
main.cc
#include "systemc.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
#include "tlm_utils/tlm_quantumkeeper.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
#include "test_bench.h"
#include "adder.h"
SC_MODULE(Top)
{
test_bench *tb;
adder *ad;
sc_signal<bool> rst;
Top(sc_module_name name) :
rst("rst")
{
tb = new test_bench("test_bench");
ad = new adder("adder");
tb->socket.bind(ad->socket);
}
};
int sc_main(int argc, char *argv[])
{
Top *top = new Top("Top");
}
test_bench.cc
#define SC_INCLUDE_DYNAMIC_PROCESS
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
using namespace sc_core;
using namespace std;
using namespace sc_dt;
#include "test_bench.h"
#include <fstream>
#include <iostream>
test_bench::test_bench(sc_module_name name):
sc_module(name), socket("socket")
{
SC_THREAD(run_tests);
}
void test_bench::run_tests()
{
ifstream infile("../adder.golden.dat");
ofstream ofs;
ofs.open("../adder.dat", ofstream::out | ofstream::app);
while(infile >> data[0] >> data[1])
{
tlm::tlm_generic_payload *trans = new tlm::tlm_generic_payload;
sc_time delay = sc_time(10, SC_NS);
trans->set_data_ptr((unsigned char*)data);
socket->b_transport(*trans, delay);
ofs << data[0] << data[1] << data[2];
delete trans;
}
infile.close();
ofs.close();
printf ("Comparing against output data \n");
if (system("diff -w sha1.dat sha1.golden.dat"))
{
cout << "*******************************************" << endl;
cout << "FAIL: Output DOES NOT match the golden output" << endl;
cout << "*******************************************" << endl;
}
else
{
cout << "*******************************************" << endl;
cout << "PASS: The output matches the golden output!" << endl;
cout << "*******************************************" << endl;
}
}
adder.cc
#define SC_INCLUDE_DYNAMIC_PROCESS
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
using namespace sc_core;
using namespace std;
#include "adder.h"
adder::adder(sc_module_name name)
: sc_module(name), socket("socket")
{
socket.register_b_transport(this, &adder::b_transport);
socket.register_transport_dbg(this, &adder::transport_dbg);
}
void adder::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay)
{
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 addr = trans.get_address();
uint32_t *ptr = (uint32_t*)trans.get_data_ptr();
unsigned int len = trans.get_data_length();
unsigned char *byt = trans.get_byte_enable_ptr();
unsigned int wid = trans.get_streaming_width();
addend1 = *ptr;
addend2 = *(ptr++);
add();
memcpy(ptr + sizeof(uint32_t) * 2, (char*) &sum, sizeof(uint32_t));
}
unsigned int adder::transport_dbg(tlm::tlm_generic_payload& trans)
{
return 0;
}
void adder::add()
{
sum = addend1 + addend2;
}
Here is the error I am seeing upon compilation.
In file included from
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_module.h:35:0,
from /home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/systemc:74,
from /home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/tlm:23,
from /home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/tlm_utils/simple_initiator_socket.h:23,
from /home/test_benches/adder/test_bench.cc:3:
/home/test_benches/adder/test_bench.cc:
In constructor ‘test_bench::test_bench(sc_core::sc_module_name)’:
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_module.h:463:29:
error: ‘SC_CURRENT_USER_MODULE’ has not been declared
SC_CURRENT_USER_MODULE, \
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_process.h:151:46: note: in definition of macro ‘SC_MAKE_FUNC_PTR’
static_cast(&callback_tag::func)
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_module.h:461:5:
note: in expansion of macro ‘declare_thread_process’
declare_thread_process( func ## _handle, \
/home/test_benches/adder/test_bench.cc:17:2: note: in expansion of
macro ‘SC_THREAD’ SC_THREAD(run_tests);
make: ***
[/home//test_benches/adder/obj/test_bench.o]
Error 1
My best guess is that I did not set up the sockets correctly. The test bench has a simple_initiator_socket and the adder has a simple_target_socket. Do I need to register the simple_target_socket with a b_transport method for the module? I did so in the initiator but in the tutorial below I did not see a requirement to do so for the target. My guess was the dataflow was like this:
simple_initiator_socket (member of test_bench) registered to b_transport method of module and simple_target_socket of another module (in top module)
Initiator module (test_bench) sets up tlm_generic_payload with data it needs to send to target (adder)
b_transport method of simple_initiator_socket (member of test_bench) called with tlm_generic_payload being passed (with addends for adder)
Target socket (target) receives and decodes tlm_generic_payload (addend values) that was passed.
Target socket (adder) performs operations (adds decoded addends) and modifies the tlm_generic_payload (passed by value) (by writing the computed sum back to the payload memory)
Initiator (test_bench) looks at modified tlm_generic_payload (now contains sum) and does some process (checks against theoretical sum)
I was trying to follow this example.
https://www.doulos.com/knowhow/systemc/tlm2/tutorial__1/
UPDATE
test_bench.h
class test_bench:
public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<test_bench> socket;
sc_out<bool> irq;
test_bench(sc_core::sc_module_name name);
void run_tests();
private:
uint32_t data[3];
};
There are two ways to declare modules in SystemC.
The first one is through using SC_MODULE macro:
SC_MODULE(mymodule) {
SC_CTOR(mymodule)
{
}
};
And the second one without it:
class mymodule : public sc_core::sc_module {
SC_HAS_PROCESS(mymodule);
public:
mymodule(sc_core::sc_module_name)
{ }
};
I would prefer the second one because:
It avoids those nasty macros as much as possible.
It allows you to inherit from another module.
Now why you need SC_MODULE or SC_HAS_PROCESS macros. The reason is that macros SC_METHOD and SC_THREAD need to know type of module they are being used from to do their job. Since SystemC is based on old revision of C++ language released in 1998, there was no way to do this automatically. So helper macro SC_HAS_PROCESS was defined as:
#define SC_HAS_PROCESS(user_module_name) typedef user_module_name SC_CURRENT_USER_MODULE
This allows SC_METHOD and SC_THREAD to use SC_CURRENT_USER_MODULE as synonym for module they are being used in. Macro SC_MODULE already uses SC_HAS_PROCESS behind the curtain.
Another advise - if you are using C++11 compatible compiler you can declare a helper macro for yourself:
#define DECL(name, ...) name{#name, __VA_ARGS__}
This can help you declare named objects without typing their name twice:
sc_in<bool> DECL(clk);
Any error message mentioning this port with contain proper name for it.
Can also be used in constructor to initialize member field:
mymodule(sc_core::sc_module_name)
: DECL(clk)
{
}
You don't have to go through the complete code from the beginning. The problem is in the execl(..) statement inside main. Code is --
#include <cstdio>
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <vector>
#define li long int
using namespace std;
char TypedCommandInTerminal[1001];
vector <string> ValidCommands,TypedCommand;
void ShowTerminal()
{
cout<<"User:$ ";
gets(TypedCommandInTerminal);
}
void PushCommands()
{
ValidCommands.push_back("mkdir");
}
void GetCommandIntoVector()
{
TypedCommand.clear();
char *p = strtok(TypedCommandInTerminal," ");
while(p)
{
TypedCommand.push_back(p);
p = strtok(NULL," ");
}
}
bool MatchCommand(string Command)
{
li i;
for(i=0;i<ValidCommands.size();i++)
{
if(ValidCommands[i].compare(Command)==0)
{
return true;
}
}
return false;
}
int main()
{
int status;
string StoredCommand;
PushCommands();
while(true)
{
ShowTerminal();
if(fork()!=0)
{
waitpid(-1,&status,0);
}
else
{
GetCommandIntoVector();
if(MatchCommand(TypedCommand[0]))
{
StoredCommand = "mkdir";
if(StoredCommand.compare(TypedCommand[0])==0)
{
execl("/bin/mkdir","mkdir",TypedCommand[1],NULL);/*ERROR*/
}
}
else
{
cout<<"Command Not Available\n";
return -1;
}
}
}
return 0;
}
I am trying to design a simple terminal using c++ in linux. What I am trying to do here is -- taking this command in console as input - "mkdir ab" . Then I managed to tokenize this string and kept "mkdir" in TypedCommand[0] and "ab" in TypedCommand[1]. Problem is when I write "TypedCommand[1]" inside execl compiler gives an error--"cannot pass objects of non-trivially-copyable type....."
I removed TypedCommand[1] and manually wrote "ab" in place of it. The code ran and created a folder named "ab" in the execution directory. So looks like execl is working fine.
I need to pass the second string saved in TypedCommand[1] inside execl in some way...what is wrong here ?
You're passing a std::string object as a optional argument to a function (execl accepts a variable number of arguments). std::string has non-trivial constructors, destructor, etc. and cannot be used this way. In this case you want to pass a pointer to a string anyway so change
execl("/bin/mkdir","mkdir",TypedCommand[1],NULL);
to
execl("/bin/mkdir","mkdir",TypedCommand[1].c_str(),NULL);
So I have a class called HPStack and I have to include it in my main class etc. However I get a "In File included from" error, what could be causing this?
Also my string objects also have errors I have have no idea why, the error is: "Unable to identifier string".
I'm new the C++ so any help would be appreciated, thanks in advance.
The error I am getting (I think) are these:
error: expected unqualified-id before "namespace"
error: expected `,' or `;' before "namespace"
error: expected namespace-name before ';' token
error: `<type error>' is not a namespace
Im not sure what I am missing but that isn't telling me much.
Here is my code: The class.h file.
#ifndef HPSTACK_H
#define HPSTACK_H
class HPStack {
public:
HPStack();
void push(double);
double pop();
double peek();
private:
double register_[4];
}
#endif
The class.cpp file.
#include "HPStack.h"
#include <cstdlib>
HPStack::HPStack() : register_{}{
}
double HPStack::push(double x) {
for (int i = 2; i >= 0; i--) {
if (isdigit(register_[i])) {
register_[i] = register_[i + 1];
}
register_[0] = x;
}
}
double HPStack::pop() {
return register_[0];
for (int i = 0; i < 3; i++) {
register_[i] = register_[i + 1];
}
}
double HPStack::peek() {
return register_[0];
}
And my main file:
#include "HPStack.h"
#include <cstdlib>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int main() {
HPStack stack;
string line;
while (getline(cin, line)) {
stringstream expression(line);
string token;
while (expression >> token) {
if (isdigit(token[0])) {
stack.push(atof(token.data()));
} else if (token == "+") {
double x = stack.pop();
double y = stack.pop();
double z = (y + x);
stack.push(z);
}
}
cout << stack.peek();
}
The error is, I'm guessing, because of this line:
double register_[4] = {};
You can not initialize class members when declaring them.
If your compiler is new enough to support C++11 features, you can use an initializer list with the constructor:
HPStack::HPStack()
: register_{}
{
}
Otherwise you have to initialize the array manually in the constructor.
And as I noted in a comment, using register_ - 2 makes no sense as it returns a pointer so the index variable i will be way beyond the end of the array.
And using register_ - 1 as the condition in the pop loop makes even less sense, as it will always be non-zero and therefore always true and the loop will loop forever.
You're missing the ; at the end of the class definition:
class HPStack {
...
}; // <== This semicolon is required
void main()
{
int xyz = 123; // original value
{ // code block starts
xyz++;
if(xyz < 1000)
xyz = 1;
} // code block ends
int original_value = xyz; // should be 123
}
void main()
{
int xyz = 123; // original value
MACRO_NAME(xyz = 123) // the macro takes the code code that should be executed at the end of the block.
{ // code block starts
xyz++;
if(xyz < 1000)
xyz = 1;
} // code block ends << how to make the macro execute the "xyz = 123" statement?
int original_value = xyz; // should be 123
}
Only the first main() works.
I think the comments explain the issue.
It doesn't need to be a macro but to me it just sounds like a classical "macro-needed" case.
By the way, there's the BOOST_FOREACH macro/library and I think it does the exact same thing I'm trying to achieve but it's too complex for me to find the essence of what I need.
From its introductory manual page, an example:
#include <string>
#include <iostream>
#include <boost/foreach.hpp>
int main()
{
std::string hello( "Hello, world!" );
BOOST_FOREACH( char ch, hello )
{
std::cout << ch;
}
return 0;
}
The cleanest way to do this is probably to use an RAII container to reset the value:
// Assumes T's assignment does not throw
template <typename T> struct ResetValue
{
ResetValue(T& o, T v) : object_(o), value_(v) { }
~ResetValue() { object_ = value_; }
T& object_;
T value_;
};
used as:
{
ResetValue<int> resetter(xyz, 123);
// ...
}
When the block ends, the destructor will be called, resetting the object to the specified value.
If you really want to use a macro, as long as it is a relatively simple expression, you can do this using a for-block:
for (bool b = false; b == false; b = true, (xyz = 123))
{
// ...
}
which can be turned into a macro:
#define DO_AFTER_BLOCK(expr) \
for (bool DO_AFTER_BLOCK_FLAG = false; \
DO_AFTER_BLOCK_FLAG == false; \
DO_AFTER_BLOCK_FLAG = true, (expr))
used as:
DO_AFTER_BLOCK(xyz = 123)
{
// ...
}
I don't really think the macro approach is a good idea; I'd probably find it confusing were I to see this in production source code.
You don't absolutely need a macro - you could use inner scope variables:
#include <stdio.h>
int main(void)
{
int xyz = 123;
printf("xyz = %d\n", xyz);
{
int pqr = xyz;
int xyz = pqr;
printf("xyz = %d\n", xyz);
xyz++;
if (xyz < 1000)
xyz = 1;
printf("xyz = %d\n", xyz);
}
printf("xyz = %d\n", xyz);
return(0);
}
This produces the output:
xyz = 123
xyz = 123
xyz = 1
xyz = 123
If you compile with GCC and -Wshadow you get a warning; otherwise, it compiles clean.
You can't write int xyz = xyz; in the inner block reliably; once the '=' is parsed, the declaration is complete and so the initializer is the inner 'xyz', not the outer. The two step dance works, though.
The primary demerit of this is that it requires a modification in the code block.
If there are side-effects in the block - like the print statements above - you could call a function that contains the inner block. If there are no side-effects in the block, why are you executing it at all.
#include <stdio.h>
static void inner(int xyz)
{
printf("xyz = %d\n", xyz);
xyz++;
if (xyz < 1000)
xyz = 1;
printf("xyz = %d\n", xyz);
}
int main(void)
{
int xyz = 123;
printf("xyz = %d\n", xyz);
inner(xyz);
printf("xyz = %d\n", xyz);
return(0);
}
You can't make a macro perform a command after a loop unless you put the loop in the macro. And seriously? It would be a much better idea just to make a scoped variable.
template<typename T> class CallFunctionOnScopeExit {
T t;
public:
CallFunctionOnScopeExit(T tt) : t(tt) {}
~CallFunctionOnScopeExit() { t(); }
};
Guaranteed in the cases of exception, etc, whereas the macro version most definitely isn't. I would prefer to use this pattern for the exception guarantees, and because it's more flexible than just copying the int.