Home > Net >  C Program does nothing if I add a function call near the end
C Program does nothing if I add a function call near the end

Time:09-11

So I am currently trying to write a fairly simple program that takes a file as input, reads it, and lexes it (lexical analysis) (I will get to parsing and interpreting later)

I have written similar programs before that worked perfectly, but surprisingly, this one hangs when I add a function at the end.

The following works perfectly:

#include <stdio.h>
#include <stdlib.h>
#include "include/slex.h"

int main(void) {
    // Read the file and save it into source.
    printf("start\n");
    FILE* fp = fopen("test.sl", "r");
    printf("fileopen\n");
    fseek(fp, 0, SEEK_END);
    printf("seek\n");
    char* source = malloc((ftell(fp)   1) * sizeof (char)); //  1 because of the null terminator.
    printf("allocation\n");
    fseek(fp, 0, SEEK_SET);
    char c;
    int i = 0;
    while ((c = fgetc(fp)) != EOF) {
        source[i  ] = c;
    } // Iterate through every single character in the file and store it into source.
    
    source[i] = '\0';
    fclose(fp);
    // Now lex the file;
    printf("Lex\n");
    lexer_t lexer;
    printf("lex2\n");
    lexer_init(&lexer, source);
    printf("lex3\n");
    /*
    lex(&lexer);
    printf("lex4");
    tl_print(&lexer.tokens);
    */
}

But when I uncomment (hope that is an actual word) lex(&lexer), it just hangs. It does not print the previous statements.

The function lex is defined in slex.c and slex.c includes slex.h.

I compiled it with gcc -Wall Wextra -o sl main.c slex.c, and it does not give me any warning, nor any error.

void lex(lexer_t* lexer):

void lex(lexer_t* lexer) {
    printf("lex"); // Debugging
    // Some people would call this function "make_tokens", I will call it "lex".
    while (lexer->current != '\0') {
        if (lexer->current == '\n') {
            token_t token = {.type = NEWLINE};
            tl_append(&lexer->tokens, token);
        }

        if (isdigit(lexer->current)) {
            token_t token = {.type = INT, .int_value = lex_integer(lexer)};
            tl_append(&lexer->tokens, token);
        }

        else if (isalpha(lexer->current)) {
            token_t token = {.type = ID, .id_value = lex_identifier(lexer)};
            tl_append(&lexer->tokens, token);
        }
    }
}

I hope someone finds a solution to my problem, because I do not understand it. Have a nice day and thank you.

And do not hesitate to ask if you need more information, just comment it and I will edit my question.

CodePudding user response:

As Bill Lynch said, Adding fflush(stdout); before lex(&lexer); solved my issue. Thanks to everyone who came by this question, really appreciate your help. I wish you all a nice day.

CodePudding user response:

Credit @Bill Lynch (first comment) who noted "app will [likely] hang" with infinite loop.

It's one thing to printf() to confirm operation. It's something else to check return codes and exit with helpful message.

Below is a rewritten (untested) version of your code using short name aliases to enhance clarity of what is being performed at different locations.

#include <stdio.h>
#include <stdlib.h>
#include "include/slex.h"

void lex( lexer_t *l ) {
    fprintf( stderr, "Entered lex()\n" ); // debug

    char c;
    while( ( c = l->current ) != '\0' ) {
        token_t t = { 0 };

        if( c == '\n') t.type = NEWLINE;
            // still infinite loop...
            // what "advances" the pointer?? Credit @Craig Estey

        else if( isdigit( c ) ) t.type = INT, t.int_value = lex_integer( l );

        else if( isalpha( c) ) t.type = ID, t.id_value = lex_identifier( l );

        else { // equivalent to "default:" in a "switch"
            fprintf( stderr, "Un-lex-able char ('%c') encountered\n", c );
            exit( EXIT_FAILURE );
        }

        tl_append( &l->tokens, t );
    }
}

int main() {
    char *fname = "test.sl";

    FILE* fp = fopen( fname, "r" );
    if( fp == NULL ) {
        fprintf( stderr, "Failed to open %s\n", fname );
        exit( EXIT_FAILURE );
    }

    fseek( fp, 0, SEEK_END );
    size_t size = ftell( fp );
    fseek(fp, 0, SEEK_SET);

    fprintf( stderr, "Size %zu\n", size ); // debug

    char *buf = malloc( (size   1) * sizeof *buf ); //  1 because of the null terminator.
    if( buf == NULL ) {
        fprintf( stderr, "Failed to alloc block %zu\n", size   1 );
        exit( EXIT_FAILURE );
    }

    size_t nread = fread( buf, sizeof buf[0], size, fp );
    if( nread != size ) {
        fprintf( stderr, "Expected %zu. Read %zu\n", size. nread );
        exit( EXIT_FAILURE );
    }
    fclose( fp );
    buf[ nread ] = '\0';

    lexer_t lexer;
    lexer_init( &lexer, buf );

    lex( &lexer );

    // free( buf ); // Unsure if you refer back to original..

    tl_print( &lexer.tokens );

    return 0;
}

You can add as many optimistic "making progress" printf calls as you'd like. It's the pessimistic "not working" print statements that are needed to push forward.

  •  Tags:  
  • c
  • Related