Tivon Mohammed
Tivon Mohammed

Reputation: 13

Read the first three strings of a line into individual arrays, then read the rest of the line into a fourth string in C?

I'm writing the first pass of an assembler in C for an assignment and need to read in lines of a text file with assembly code, and store the label, opcode, and operand, as well as any comments in the line after the first three strings. I initially used

fscanf(fileptr1,"%s\t%s\t%s",label,opcode,operand);

for a file without comments, but sscanf wouldn't work to put the rest of the line into a single char array. It seems like I would use fgets, but how would I separate that into the first three strings separated by whitespace, followed by the rest of the line until the newline character?

For reference, the lines follow this formatting:

LABEL   OPCODE  OPERAND     COMMENTS IN MULTIPLE STRINGS

I would want the label, opcode, and operand in individual strings, as I have right now, and then a separate string for the entirety of the rest of the line. A few lines from the assembly code for reference:

COPY    START   1000        COPY FILE FROM INPUT TO OUTPUT
FIRST   STL     RETADR      SAVE RETURN ADDRESS
CLOOP   JSUB    RDREC       READ INPUT RECORD
        LDA     LENGTH      TEST FOR EOF (LENGTH = 0)
        COMP    ZERO
        JEQ     ENDFIL      EXIT IF EOF FOUND
        JSUB    WRREC       WRITE OUTPUT RECORD
J       CLOOP   LOOP

Upvotes: 1

Views: 192

Answers (2)

Clifford
Clifford

Reputation: 93476

Define the specific delimiter for each field

fscanf( fileptr1, "%[^\t] %[^\t] %[^\t] %[^\n]", label, opcode, operand, comment ) ;

You should perhaps add field width specifiers and check the return value, to check for errors and overruns but that is a different question.

But there are other means. For example you could fgets() the whole line into one array, then split it up using strtok() using \t as the delimiter.

char line[1024] = {0} ;

fgets( line, sizeof(line), fileptr1 ) ;

char* label = strtok( line, "\t" ) ;
char* opcode = label != 0 ? strtok( 0, "\t" ) : 0 ;
char* operand = opcode != 0 ? strtok( 0, "\t" ) : 0 ;
char* comment = operand != 0 ? strtok( 0, "\n" ) : 0 ;

Upvotes: 0

chux
chux

Reputation: 153517

Step 1: read the line with fgets()

char buffer[256];
while (fgets(buffer, sizeof buffer,fileptr1) {

how would I separate that into the first three strings separated by whitespace, ...

This is an incorrect assessment of the problem. The 3 "strings" are not separated by whitespace in the case of " LDA LENGTH TEST FOR EOF (LENGTH = 0)" for the first "string" or label is empty.

Instead code needs to look for missing fields.

Step 2: There are numerous approaches: Below is a try-it-1-of-2-ways depending on if leading character is a white-space. Test if scanning succeeded by testing n

    char label[8];
    char opcode[8];
    char operand[12];
    char comment[sizeof buffer];  // big enough to handle the rest of the line
    label[0] = '\0';
    opcode[0] = '\0';
    operand[0] = '\0';
    comment[0] = '\0';

    int n = 0;  
    if (isspace((unsigned char) buffer[0])) {
      //                      vv--------- Save offset of scan if we got that far
      sscanf(buffer, "%7s%11s %n" , opcode, operand, &n); 
    } else {
      sscanf(buffer, "%7s%7s%11s %n" , label, opcode, operand, &n); 
    }
    if (n == 0) {
      // Handle bad input with TBD code
      continue;
    }
    // look for comment starting at `n`
    if (buffer[n]) {
      // scan in comment  
      sscanf(buffer + n, "%[^\n]" , comment); 
    }

    // do something with input
    printf("<%s> <%s> <%s> <%s>\n", label,opcode,operand,comment);
}

Code could test for a "too long" a label,opcode,operand. Example:

    // Assume max length of opcode == 7
    char opcode[7 + 1 + 1];  // +1 for extra, +1 for null character
    ...
    sscanf(..., "...%8s...", .... opcode ...);
    if (opcode[7 + 1]) Handle_TooLoong();

Upvotes: 2

Related Questions