getline reads only one line

I'm writing at time on a virtual machine. At the first step I'll make an assembler for that, here is the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 * This is the code for the assembler program, part of a virtual
 * machine implementation.
 *
 * Its address space will have a size of two bytes., register size also.
 * 
 */
#include <arpa/inet.h>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>

enum Opcode
{
    NOP
   ,JMP
};


class Assembler
{
public:
    Assembler( std::istream& istr, std::ostream& ostr );
    void parse();

private:
    void parse_line(const std::string & line);
    using addr_t = std::uint16_t;
    std::map<std::string,addr_t> m_label;
    std::istream& m_istr;
    std::ostream& m_ostr;
    std::vector<char> m_binary;
};
Assembler::Assembler( std::istream & istr, std::ostream & ostr )
: m_istr(istr), m_ostr(ostr)
{}
void Assembler::parse( )
{
    std::string tmp;
    while( std::getline( m_istr, tmp) );
    { 
        std::cerr << tmp << '\n';  //DEBUG
        parse_line( tmp );
    }
    for( auto byte : m_binary) m_ostr.put(byte);
}
void Assembler::parse_line(const std::string& line)
{   
    // parse for label
    for( int i = 0; i < line.length(); ++i )
    {
         if( line[i] == ':')
         {
             m_label[ line.substr(0,line[i]) ] = m_binary.size();
             return;
         }
    }
    // parse for NOP;
    if( line.substr(0,3) == "NOP")
    {
        m_binary.push_back(NOP);
        return;
    }
    // parse for JMP
    if( line.substr(0,3) == "JMP" )
    {
        std::istringstream iss(line);
        std::string tmp;
        iss >> tmp >> tmp;
        m_binary.push_back(JMP);
        addr_t t = htons(m_label[tmp]);
        char lsb = t & 0xff;
        char msb = (t >> 8) & 0xff;
        m_binary.push_back(msb);
        m_binary.push_back(lsb);
        return;
    }
}
             

void print_help()
{
    std::cout << "usage: asm <source> <target>\n";
}

int main( int argc, char **argv)
{
    if (argc < 3) {
        print_help();
        return 1;
    }
    
    std::ifstream ifile(argv[1]);
    if( !ifile ) {
        std::cout << argv[1] << " couldn't opened!\n";
        return 1;
    }
    std::ofstream ofile(argv[2], std::ios::binary);
    if( !ofile ) {
        std::cout << argv[2] << " couldn't opened!\n";
        return 1;
    }
    
    Assembler assembler( ifile, ofile );
    assembler.parse();
}

This is the content of the input file:
NOP
NOP
my_label:
NOP
NOP
JMP my_label
NOP


But it doesn't parse, only the first line. So I guess, there goes something wrong at the while-loop at line 44. So what's wrong with?

I also would appreciate, if I would get feedback about the design of my program.
Thanks for help :-)
Last edited on
You have a semi-colon after it. Your first line just happens to be the same as your last line.

feedback about the design of my program.

assembler.parse() doesn't sound like a function that would write to a file, but it does.
If you're working in binary, it would probably be faster to write more than one byte at a time, when possible.
Third, you might want to think about how to incorporate handling bad user (file) input.

line.substr(0,line[i])

What do you intend for this to be doing? Perhaps you meant to do just i?
Last edited on

You have a semi-colon after it. Your first line just happens to be the same as your last line.

Oh, what a silly mistake,.. If you hadn't this mentioned, I would have overlooked that perhaps for long time.

ine.substr(0,line[i])
What do you intend for this to be doing? Perhaps you meant to do just i?

If a colon would found, then I want to store the label-key without the colon, together with its address,


assembler.parse() doesn't sound like a function that would write to a file, but it does.

So it would be better, renaming parse() to e.g. assemble()?

If you're working in binary, it would probably be faster to write more than one byte at a time, when possible.

Is there a way using std::vector<char> like a raw array (char *buf), so I could using a vector like
ofile.wiite( my_vector, my_vector.size()) ?


You're right, this tiny program couldn't mess up with a real assembler. It will rather be used to have at anyway a method producing machine-language binaries, just or testing proposes.

PS: sorry for the lated answer, I got a break :-)
Oh, what a silly mistake,.. If you hadn't this mentioned, I would have overlooked that perhaps for long time.

This is usually the point at which someone tells you that if you haven't learned to use your debugger, you really should. This is exactly the sort of thing that would be obvious when stepping through your code.
renaming parse() to e.g. assemble()?
You'll find that naming things can be really hard at times. Yes, I think that assemble() would be a better name, but feel free to disagree with that.

std::vector<char> like a raw array (char *buf), so I could using a vector like
ofile.wiite( my_vector, my_vector.size()) ?
my_vector.data()
Last edited on
Topic archived. No new replies allowed.