Program input question.


R. Clayton (rclayton@monmouth.edu)
(no date)


I have two programs in a file

  mov r0 12
  mov r1 13
  + r1 r2

  mov r4 12
  mov r6 19
  - r4 r6

I tried using istream_iterator and std::copy to copy the instructions into a
list. I tried another version using an overloaded << operator to read this
program into a list of Instructions (I have a class called
Instruction). When I ran the program in windows it read the blank line as an
empty string and called the default constructor of the class Instruction to
push_back the Instruction into the list. But on Solaris using both STL and
SaferSTL, the blank line never gets read as a blank line. Instead the
previous instruction read (+ r1 r2) gets copied into the list. I tried
several different versions of code and added checks for cin.fail() but to no
avail.

This didn't work -
  
  std::list<Instruction>
    tmp(std::istream_iterator<Instruction>(cin),
        std::istream_iterator<Instruction>());

This didn't work either
  
  Instruction i;
  while (cin >> i)
    if (cin.fail())
      tmp.push_back(Instruction());
      cin.clear();
    else tmp.push_back(i);

Is there something I'm doing wrong? All versions work correctly on windows.

  To be able to answer your question, I'd need to see how you implemented
  instruction extraction. Let's assume you did the obvious:

    struct instruction
      string op, first_arg, second_arg

    istream & operator >> (istream & is, instruction & i)
      return is >> i.op >> i.first_arg >> i.second_arg

  As you noticed, this implementation doesn't respect blank lines. Extraction
  will chew through all leading space characters until if finds a non-space
  character, which it takes as the first character of the string giving the
  op-code name; this is the standard default behavior. (I don't understand why
  you got the previous instruction back, I'll guess that it has something to do
  with your code.)

  But that's not the only problem. Instruction extraction as given will accept

    move

    r1

    a move

  as legal input because it also chews through all the other space characters
  too.

  These problems can be fixed by changing instruction extraction, but that's
  not a particularly easy course to take. As an alternative, reconsider your
  solution.

  By going from input stream to a pair of programs, you are, in my opinion,
  taking too big a step. My solution handles this in two steps: reading two
  blocks of text from the input stream, and then translating each block of text
  into a program consisting of a sequence of instructions:

    text_block tb1, tb2, tb3

    if not std::cin >> tb1
      error missing program

    if not std::cin >> tb2
      error missing program

    if std::cin >> tb3
      error extra junk on input

    string emsg
    program p1(tb1, emsg)
    if not emsg.empty()
      error emsg

    program p2(tb2, emsg)
    if not emsg.empty()
      error emsg

  Reading blocks of text from input is something I do often, so extraction for
  that's already done:

    istream operator >> (istream & is, text_block & tb)

      tb.clear()
  
      string str
  
      do
        if not getline(is, str)
          return is
      while is_blank_line(str)

      do tb.push_back(str)
      while getline(is, str) and not is_blank_line(str)

      return is

  By using getline() I avoid two problems: assembling input into lines
  (getline() does that for me) and run-away space skipping (getline() doesn't
  skip space characters).



This archive was generated by hypermail 2.0b3 on Mon May 03 2004 - 17:00:06 EDT