Handling error/status messages by interface to C++ programs

Discussion in 'C++' started by Leslaw Bieniasz, Sep 8, 2009.

  1. Cracow, 8.09.2009

    Hi,

    I am writing a C++ program that does a job similar to a typical compiler:
    It reads some source text, analyses it for errors, and performs some
    conversion to a target format. I have a problem how to design the
    communication between my code and user interfaces, to achieve
    the following goals:

    1) The code should be able to run either in the console mode, or
    within a Windows GUI, but the kernel part of the code should be designed
    in such a way so that it is independent on the interface.

    2) The code should make available to the program user a list of
    errors detected during its operation, with some additional information
    about the location of the errors in the source text analysed.
    Also, the user should be informed about the current status of
    the program operation, by suitable messages.

    3) The operation of the code is rather fast, so that it seems that
    it is not necessary to run it in a separate thread (but who knows
    what will be needed in the future?)

    Owing to these features, I notice an analogy of my code to some of the
    commercial C++ compilers, such as, for example, Borland compilers,
    like C++ Builder. They can also run either in the console or Windows mode,
    and send appropriate error and status messages. In the case of the Windows
    GUI, the Builder displays status messages in a small Dialog-type window,
    opened for the time of the compilation, and error messages are
    added to a ListBox-type window. Later on, a user can click on any
    of the error messages, which causes that a part of the
    source text, containing the particular error, is displayed in another window.
    In the case of the console mode, the messages are sent to the console.

    I would like to have a similar behaviour in my code, so that if anybody
    knows how such things are designed, please help me.

    In the case of console programs, the easiest thing to do is to send
    various messages to an output stream, during the program operation, for example:

    cout << "Error detected: missing right parenthesis".

    However, this solution does not seem the best if the same code is to run
    also under graphical GUI, because there is no direct way to connect the output
    stream to the various windows. It therefore seems that the interface-independent
    kernel of my code should not send the messages but only keep a list of them somewhere.
    The interface would later display the messages in this or other way. But this solution
    is also not perfect, because then there would be a time shift between the actual
    events and the information about the events, revealed to the user.

    A related issue is how the code should behave internally when it detects
    an error. Is this a good idea to use exceptions in such cases? If yes,
    which part of the code (or interface?) should be responsible for
    catching the exceptions?

    I have to say I have already asked many programmers over the years,
    about the above problems, and I have never obtained any real help.
    This seems strange, as I can imagine these problems frequently arise
    in the design of any serious large applications.

    I would appreciate very much your help, ideally together with
    some examples, using OOP and C++.

    Leslaw
     
    Leslaw Bieniasz, Sep 8, 2009
    #1
    1. Advertising

  2. Leslaw Bieniasz

    Francesco Guest

    On Sep 8, 12:07 pm, Leslaw Bieniasz <> wrote:
    >                                         Cracow, 8.09.2009
    >
    > Hi,
    >
    > I am writing a C++ program that does a job similar to a typical compiler:
    > It reads some source text, analyses it for errors, and performs some
    > conversion to a target format. I have a problem how to design the
    > communication between my code and user interfaces, to achieve
    > the following goals:
    >
    > 1) The code should be able to run either in the console mode, or
    > within a Windows GUI, but the kernel part of the code should be designed
    > in such a way so that it is independent on the interface.
    >
    > 2) The code should make available to the program user a list of
    > errors detected during its operation, with some additional information
    > about the location of the errors in the source text analysed.
    > Also, the user should be informed about the current status of
    > the program operation, by suitable messages.


    Hi Leslaw,
    you can use the same technique used by GCC, that is, the compiler
    itself is a console program that is called by passing the source
    filename and the options to it, then it performs a single run dropping
    all messages to the standard output stream.

    When you have to call it from a GUI interface, simply intercept its
    output and display it on your interface.

    Actually, that compiler is not interactive, and I believe it is the
    best technique - after all, once it intercepts a problem in the source
    you have either to change the source or change its parameters, and
    then the best solution is to restart it from scratch with the new
    input.

    > 3) The operation of the code is rather fast, so that it seems that
    > it is not necessary to run it in a separate thread (but who knows
    > what will be needed in the future?)
    >
    > Owing to these features, I notice an analogy of my code to some of the
    > commercial C++ compilers, such as, for example, Borland compilers,
    > like C++ Builder. They can also run either in the console or Windows mode,
    > and send appropriate error and status messages. In the case of the Windows
    > GUI, the Builder displays status messages in a small Dialog-type window,
    > opened for the time of the compilation, and error messages are
    > added to a ListBox-type window. Later on, a user can click on any
    > of the error messages, which causes that a part of the
    > source text, containing the particular error, is displayed in another window.


    Your GUI can simply display the messages in a clickable list and
    "decode" each error message - which should report the filename and the
    line of code where the error happened.

    Hope this small help comes useful somehow.

    Have good coding, your project is really interesting and would be nice
    to read here about your progresses.

    Best regards,
    Francesco
     
    Francesco, Sep 8, 2009
    #2
    1. Advertising

  3. Leslaw Bieniasz

    Francesco Guest

    On Sep 8, 12:07 pm, Leslaw Bieniasz <> wrote:
    >                                         Cracow, 8.09.2009
    > In the case of console programs, the easiest thing to do is to send
    > various messages to an output stream, during the program operation, for example:
    >
    > cout << "Error detected: missing right parenthesis".
    >
    > However, this solution does not seem the best if the same code is to run
    > also under graphical GUI, because there is no direct way to connect the output
    > stream to the various windows.


    I think I have overlooked this point. Are you sure that you cannot
    intercept the output? Any operating system should be able to redirect
    the output.

    For example, under Windows the ">" character, appended to a program
    call, redirects the output to anything on the right side of that
    character. For example...

    c:\compiler.exe sourcefilename -option > messenger.exe

    ....redirects the output of compiler.exe to an hypothetical small
    messenger.exe utility whose unique task is to transform the output
    into a list which can be polled at runtime via the Windows API.

    Another solution, really simple, would be to dump the output to a file
    and then read it from your interface:
    c:\compiler.exe sourcefilename -option > dump.txt

    Hope this helps, once more.
    Just a couple of pointers that you will be surely able to dig.

    Kind regards,
    Francesco
     
    Francesco, Sep 8, 2009
    #3
  4. Francesco wrote:
    > On Sep 8, 12:07 pm, Leslaw Bieniasz <> wrote:
    >> Cracow, 8.09.2009
    >> In the case of console programs, the easiest thing to do is to send
    >> various messages to an output stream, during the program operation, for example:
    >>
    >> cout << "Error detected: missing right parenthesis".
    >>
    >> However, this solution does not seem the best if the same code is to run
    >> also under graphical GUI, because there is no direct way to connect the output
    >> stream to the various windows.

    >
    > I think I have overlooked this point. Are you sure that you cannot
    > intercept the output? Any operating system should be able to redirect
    > the output.
    >
    > For example, under Windows the ">" character, appended to a program
    > call, redirects the output to anything on the right side of that
    > character. For example...
    >
    > c:\compiler.exe sourcefilename -option > messenger.exe


    I believe you've confused two separate elements of the MS-DOS interface.
    The '>' redirects the output of the left operand (executable) to the
    file specified as the right operand, while '|' ("pipe") redirects the
    output and makes it standard *input* of the executable on the right.

    > ...redirects the output of compiler.exe to an hypothetical small
    > messenger.exe utility whose unique task is to transform the output
    > into a list which can be polled at runtime via the Windows API.


    I think the command should actually be

    c:\compiler.exe sourcefilename -option | messenger.exe

    > Another solution, really simple, would be to dump the output to a file
    > and then read it from your interface:
    > c:\compiler.exe sourcefilename -option > dump.txt


    Yes, AFA redirection to a file is concerned.

    > [..]


    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Sep 8, 2009
    #4
  5. Leslaw Bieniasz

    Francesco Guest

    Victor Bazarov ha scritto:
    > Francesco wrote:
    > > On Sep 8, 12:07 pm, Leslaw Bieniasz <> wrote:
    > >> Cracow, 8.09.2009
    > >> In the case of console programs, the easiest thing to do is to send
    > >> various messages to an output stream, during the program operation, for example:
    > >>
    > >> cout << "Error detected: missing right parenthesis".
    > >>
    > >> However, this solution does not seem the best if the same code is to run
    > >> also under graphical GUI, because there is no direct way to connect the output
    > >> stream to the various windows.

    > >
    > > I think I have overlooked this point. Are you sure that you cannot
    > > intercept the output? Any operating system should be able to redirect
    > > the output.
    > >
    > > For example, under Windows the ">" character, appended to a program
    > > call, redirects the output to anything on the right side of that
    > > character. For example...
    > >
    > > c:\compiler.exe sourcefilename -option > messenger.exe

    >
    > I believe you've confused two separate elements of the MS-DOS interface.
    > The '>' redirects the output of the left operand (executable) to the
    > file specified as the right operand, while '|' ("pipe") redirects the
    > output and makes it standard *input* of the executable on the right.
    >
    > > ...redirects the output of compiler.exe to an hypothetical small
    > > messenger.exe utility whose unique task is to transform the output
    > > into a list which can be polled at runtime via the Windows API.

    >
    > I think the command should actually be
    >
    > c:\compiler.exe sourcefilename -option | messenger.exe


    Oh, yes, I mistaken it, thank you for the correction.

    In any case, that was just a pointer about a possible solution.

    Francesco
     
    Francesco, Sep 8, 2009
    #5
  6. Leslaw Bieniasz schrieb:

    > Hi,
    >
    > I am writing a C++ program that does a job similar to a typical compiler:
    > It reads some source text, analyses it for errors, and performs some
    > conversion to a target format. I have a problem how to design the
    > communication between my code and user interfaces, to achieve
    > the following goals:
    >
    > 1) The code should be able to run either in the console mode, or
    > within a Windows GUI, but the kernel part of the code should be designed
    > in such a way so that it is independent on the interface.


    You have (at least) two different solutions for this problem. You can
    either create a console mode program, or put the compiler stuff into a
    library. I choose to create a library such cases, with a small stub
    executable for the console mode which calls the functions from the
    library. The main advantage of this approach is that in the GUI the
    errors from the compilation does not to be parsed, but can come from a
    well specified interface. Also I use the strategy pattern[1] to notify
    the GUI about the progress.

    This is the outline of such a system:

    class Progress
    {
    public:
    // The function which the compiler calls when something changed
    virtual void progress(int state) = 0;
    // Errors callback
    virtual void error(int line, std::string message) = 0;

    // Always add a destructor to classes with virtual functions
    ~Progress();
    };

    class GuiProgress: public Progress
    {
    public:
    virtual void progress( int state )
    {
    m_progressBar.setState( state );
    }

    virtual void error(int line, std::string message)
    {
    showDialog( message );
    }
    };

    class GuiProgress: public Progress
    {
    public:
    virtual void progress( int state )
    {
    std::cout << "progress: " << state / 100.0 << '%' << std::endl;
    }

    virtual void error(int line, std::string message)
    {
    std::cerr << "Error on line " << line << ": " << message << '\n';
    }
    };

    class Compiler
    {
    public:
    void compile( std::istream& input, Progress& pg );
    };

    bye
    Rudi

    [1] http://en.wikipedia.org/wiki/Strategy_pattern
     
    Rüdiger Ranft, Sep 8, 2009
    #6
  7. Leslaw Bieniasz

    Jorgen Grahn Guest

    On Tue, 8 Sep 2009 03:42:28 -0700 (PDT), Francesco <> wrote:
    > On Sep 8, 12:07 pm, Leslaw Bieniasz <> wrote:
    >>                                         Cracow, 8.09.2009


    Mildly offtopic, but I have to mention it anyway. I thought I had seen
    all theoretically possible date formats already, but "8.09.2009" is
    new to me. "8.9.2009" yes, but not a form with padded month numbers.

    >> I am writing a C++ program that does a job similar to a typical compiler:
    >> It reads some source text, analyses it for errors, and performs some
    >> conversion to a target format. I have a problem how to design the
    >> communication between my code and user interfaces, to achieve
    >> the following goals:
    >>
    >> 1) The code should be able to run either in the console mode, or
    >> within a Windows GUI, but the kernel part of the code should be designed
    >> in such a way so that it is independent on the interface.
    >>
    >> 2) The code should make available to the program user a list of
    >> errors detected during its operation, with some additional information
    >> about the location of the errors in the source text analysed.
    >> Also, the user should be informed about the current status of
    >> the program operation, by suitable messages.

    >
    > Hi Leslaw,
    > you can use the same technique used by GCC, that is, the compiler
    > itself is a console program that is called by passing the source
    > filename and the options to it, then it performs a single run dropping
    > all messages to the standard output stream.
    >
    > When you have to call it from a GUI interface, simply intercept its
    > output and display it on your interface.
    >
    > Actually, that compiler is not interactive, and I believe it is the
    > best technique - after all, once it intercepts a problem in the source
    > you have either to change the source or change its parameters, and
    > then the best solution is to restart it from scratch with the new
    > input.


    Yes. All this is how compilers and compiler-like programs (not just
    GCC) have worked for the past forty years.

    Actually it would surprise me if even Windows compilers were
    implemented in any other way. It has too many benefits. (One is that
    you can implement the compiler in portable C++.)

    >> 3) The operation of the code is rather fast, so that it seems that
    >> it is not necessary to run it in a separate thread (but who knows
    >> what will be needed in the future?)


    This is one of the many things that the solution above makes non-issues.
    It's even trivial to make the GUI thing call a standard make tool instead
    of your "compiler", so the user can e.g. build a dozen things in
    parallel to speed things up on an SMP machine. No code needed.

    >> Owing to these features, I notice an analogy of my code to some of the
    >> commercial C++ compilers, such as, for example, Borland compilers,
    >> like C++ Builder. They can also run either in the console or Windows mode,
    >> and send appropriate error and status messages. In the case of the Windows
    >> GUI, the Builder displays status messages in a small Dialog-type window,
    >> opened for the time of the compilation, and error messages are
    >> added to a ListBox-type window. Later on, a user can click on any
    >> of the error messages, which causes that a part of the
    >> source text, containing the particular error, is displayed in another window.

    >
    > Your GUI can simply display the messages in a clickable list and
    > "decode" each error message - which should report the filename and the
    > line of code where the error happened.


    And if those error messages look even /remotely/ like those from other
    "compilers", I bet existing GUIs know what to do with them. I know
    Emacs (M-x compile) does.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Sep 8, 2009
    #7
  8. Leslaw Bieniasz

    James Kanze Guest

    On Sep 8, 2:18 pm, Victor Bazarov <> wrote:
    > Francesco wrote:
    > > On Sep 8, 12:07 pm, Leslaw Bieniasz <> wrote:
    > >> Cracow, 8.09.2009
    > >> In the case of console programs, the easiest thing to do is
    > >> to send various messages to an output stream, during the
    > >> program operation, for example:


    > >> cout << "Error detected: missing right parenthesis".


    > >> However, this solution does not seem the best if the same
    > >> code is to run also under graphical GUI, because there is
    > >> no direct way to connect the output stream to the various
    > >> windows.


    Just for the record, I've never seen a compiler which had a
    graphical interface.

    > > I think I have overlooked this point. Are you sure that you
    > > cannot intercept the output? Any operating system should be
    > > able to redirect the output.


    > > For example, under Windows the ">" character, appended to a
    > > program call, redirects the output to anything on the right
    > > side of that character. For example...


    > > c:\compiler.exe sourcefilename -option > messenger.exe


    > I believe you've confused two separate elements of the MS-DOS
    > interface. The '>' redirects the output of the left operand
    > (executable) to the file specified as the right operand, while
    > '|' ("pipe") redirects the output and makes it standard
    > *input* of the executable on the right.


    The usual solution is for the GUI (the IDE) to use something
    like system() to invoke the compiler, redirecting the output to
    a temporary file which it then reads and exploits, e.g.:

    system( "c:\compiler.exe sourcefilename > c:\temp
    \compiler.out" ) ;

    > > ...redirects the output of compiler.exe to an hypothetical
    > > small messenger.exe utility whose unique task is to
    > > transform the output into a list which can be polled at
    > > runtime via the Windows API.


    > I think the command should actually be


    > c:\compiler.exe sourcefilename -option | messenger.exe


    I doubt the that messenger.exe is even necessary; typically, the
    IDE will start the compiler in a separate thread, which then
    waits for it to finish using something like the wait() system
    call under Unix. It then reads the compiler output files.

    --
    James Kanze
     
    James Kanze, Sep 8, 2009
    #8
  9. On Sep 8, 2:57 pm, James Kanze <> wrote:
    > On Sep 8, 2:18 pm, Victor Bazarov <> wrote:
    > > Francesco wrote:
    > > > ...redirects the output of compiler.exe to an hypothetical
    > > > small messenger.exe utility whose unique task is to
    > > > transform the output into a list which can be polled at
    > > > runtime via the Windows API.

    > > I think the command should actually be
    > >     c:\compiler.exe sourcefilename -option | messenger.exe

    >
    > I doubt the that messenger.exe is even necessary; typically, the
    > IDE will start the compiler in a separate thread, which then
    > waits for it to finish using something like the wait() system
    > call under Unix.  It then reads the compiler output files.


    Slightly off-topic from thread's topic: Do people actually do such
    complex and convoluted things like make a messenger program which uses
    windows specific things and then poll from it? The first thing I do is
    whip out my portable wrappers which work on posix and windows for
    threading and processes. Ex:

    ProcessBuilder pb = ProcessBuilder()
    .exe("compiler.exe")
    .arg("sourcefilename")
    .arg("-option")
    .redirectErrToOut()
    .pipeOut();
    auto_ptr<Process> p(pb.spawn());
    auto_ptr<ProcessIstream> childsOut(
    p->releaseReadEndFromChildsStdout());
    for (string line; getline(*childsOut, line); )
    cout << line << endl;

    Boost is good too, for those shops which actually use it.
     
    Joshua Maurice, Sep 8, 2009
    #9
  10. Leslaw Bieniasz

    Jerry Coffin Guest

    In article <-kr.edu.pl>,
    says...

    [ ... ]

    > 1) The code should be able to run either in the console mode, or
    > within a Windows GUI, but the kernel part of the code should be designed
    > in such a way so that it is independent on the interface.


    That's certainly good so far.

    > 2) The code should make available to the program user a list of
    > errors detected during its operation, with some additional information
    > about the location of the errors in the source text analysed.
    > Also, the user should be informed about the current status of
    > the program operation, by suitable messages.


    Likewise, perfectly reasonable.

    > 3) The operation of the code is rather fast, so that it seems that
    > it is not necessary to run it in a separate thread (but who knows
    > what will be needed in the future?)


    Using multiple threads may make sense, even if it's not really
    _necessary_. This does seem to contradict your second point though:
    if the process takes long enough to run that the user will ever see
    any message about its current status other than "finished", it's
    taking long enough that it probably justifies running in a separate
    thread (or process).

    [ ... ]

    > In the case of console programs, the easiest thing to do is to send
    > various messages to an output stream, during the program operation, for example:
    >
    > cout << "Error detected: missing right parenthesis".
    >
    > However, this solution does not seem the best if the same code is to run
    > also under graphical GUI, because there is no direct way to connect the output
    > stream to the various windows.


    Yes and no. If you use cerr directly, that's true. OTOH, it's fairly
    easy to use an object of _some_ sort that can write to a stream or a
    window, depending on what you prefer. For example, years ago I wrote
    a program that had an ABC named 'display', with two descendants name
    text_display and window_display. You could produce output via either
    one (or, theoretically both). IIRC, if you instantiated more than one
    window_display, each would create its own list-box to hold output. I
    never really put that to much use, but in something like an IDE, I
    could see using it to put output from different tools into different
    windows.

    > It therefore seems that the interface-independent
    > kernel of my code should not send the messages but only keep a list of them somewhere.
    > The interface would later display the messages in this or other way. But this solution
    > is also not perfect, because then there would be a time shift between the actual
    > events and the information about the events, revealed to the user.


    There's always going to be at least some delay between detecting an
    error and displaying the associated message -- but as long as the
    delay is less than 100 ms or so, the user won't be able to see the
    difference. Even 200 ms still looks very close. In any case, a small
    delay is rarely a huge problem. At very best, a typical screen is
    only updated about 60 times a second, so trying to update faster than
    that accomplishes nothing.

    It's perfectly reasonable to queue a message in one thread, and have
    a different thread update the display on the screen in response to
    that message.

    > A related issue is how the code should behave internally when it detects
    > an error. Is this a good idea to use exceptions in such cases? If yes,
    > which part of the code (or interface?) should be responsible for
    > catching the exceptions?


    Assuming your code really is a lot like a compiler, I'd say the
    answer is probably no. An exception is for dealing with something
    unexpected -- but compilers normally deal with human input, and
    finding an error in human input is _never_ unexpected. In reality,
    rather the opposite is true -- the _usual_ situation is for a
    compiler to find at least one error, and issue a message about it. In
    most cases, such an error means no other output is created, so the
    majority of the time, the ONLY output from a compiler is error
    messages. Once the compiler runs successfully and generates code as
    output, there's not a great deal of reason to run it on that code
    again (except for things like installing a package from source code).

    --
    Later,
    Jerry.
     
    Jerry Coffin, Sep 10, 2009
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    12
    Views:
    1,685
    Dave Thompson
    Jan 10, 2005
  2. Coca
    Replies:
    7
    Views:
    764
    Aidan Grey
    Aug 24, 2004
  3. Replies:
    18
    Views:
    644
    Dave Thompson
    Jan 10, 2005
  4. lone_eagle
    Replies:
    3
    Views:
    661
    psykeedelik
    May 26, 2009
  5. Casey Hawthorne
    Replies:
    14
    Views:
    464
Loading...

Share This Page