How to change PackCC input from stdin to a file?

58 views Asked by At

I'm trying to get PackCC to parse contents from a file. I open the file, read its contents into a buffer, then pass that inward as an auxiliary value to the .peg file.

static void parser_read(const char *contents, int mode) {
    FILE *fp = fopen(contents, "r");
    
    if (fp == NULL) {
        perror("Error opening file");
        exit(EXIT_FAILURE);
    }
    
    char buffer[2048];
    memset(buffer, 0, sizeof buffer);
    fgets(buffer, 2048, fp);
    fclose(fp);
    scheme_context_t *ctx = scheme_create(buffer); // Not sure about this line.

    ast *my_ast = NULL;
    scheme_parse(ctx, &my_ast);
    ast_print(my_ast);
    eval_ast(my_ast);
}

Unfortunately, PackCC continues to only read from standard input and seems to completely ignore the auxiliary buffer I supply it. Am I doing this wrong? The PackCC documentation is very vague and almost non-existant with this situation.

1

There are 1 answers

1
rici On BEST ANSWER

PackCC reads input one character at a time using the macro PCC_GETCHAR(auxil). By default, this macro is defined as getchar(), and PackCC expects that PCC_GETCHAR(auxil) will return values in the same way that getchar() does; that is, an integer between 0 and 255 representing the input character, or EOF to represent end of file (or an error condition, which I believe is treated as though it were an end of file).

The simplest way of reading from a different file is to put a FILE* member in your auxiliary data structure and fill it in (by calling fopen). You do not require a buffer. (In fact, since PackCC itself creates a buffer, creating another one would be redundant.)

The code you present does not include the PackCC directives; I'm just assuming that you used something like %auxil "char*". What you want, however, is something like this (untested, I'm afraid):

%auxil "SchemeAuxil*"
%value "ast*"

%header {
#include <stdio.h>
#include <stdlib.h>
#include "ast.h"

// This could go in a different header. 
typedef struct SchemeAuxil {
  FILE* infile;
  // ... Any other needed auxiliary data
} SchemeAuxil;

}

%source {
#define PCC_GETCHAR(auxil) fgetc(auxil->infile)

/*
 * This might go in a separate file, along with other support routines.
 * In that case, you would also create a header file to declare the support
 * functions, and put the #include for the header file in the %header block
 * above. 
 */

/* Returns NULL on failure. Please check. */
SchemeAuxil* create_auxiliary(FILE* infile) {
  SchemeAuxil* aux = malloc(sizeof *aux);
  if (aux) {
    aux->infile = infile;
    // initialize other needed auxiliary data fields
  }
  return aux;
}

void destroy_auxiliary(SchemeAuxil* aux) {
  if (aux) {
    if (aux->infile) fclose(aux->infile);
    // delete other auxiliary data fields
    free(aux);
  }
}

/* This replaces your parser_read function */
static void parser_read(const char *contents, int mode) {
    FILE *fp = fopen(contents, "r");
    
    if (fp == NULL) {
        perror("Error opening file");
        exit(EXIT_FAILURE);
    }
    /* We should check that both create_auxiliary and scheme_create
     * returned non-NULL values.
     */
    SchemeAuxiliary* aux = create_auxiliary(fp);
    scheme_context_t *ctx = scheme_create(aux);
    ast *my_ast = NULL;

    // Should check the return value of scheme_parse.
    scheme_parse(ctx, &my_ast);
    ast_print(my_ast);
    eval_ast(my_ast);
    // delete ast
    destroy_auxiliary(aux);
    scheme_destroy(ctx);
}
}