0

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.

rici
  • 234,347
  • 28
  • 237
  • 341
  • Instead of a snippet post a [mre] – Allan Wind Dec 25 '22 at 01:03
  • @AllanWind It's not possible to produce a MRE with this. All I want is a way to read from a file and not standard input without having to send data directly to the stdin stream. – TheSinisterStone Dec 25 '22 at 01:06
  • @TheSinisterStone: You are free to produce a MRE which *only* shows your attempt to divert input to a file. The parser itself could do almost nothing other than read characters up to the end of input (which would be pretty minimal). That's what MRE means: create an example which focuses very tightly on the problem you're trying to resolve. – rici Dec 25 '22 at 01:08

1 Answers1

1

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);
}
}
rici
  • 234,347
  • 28
  • 237
  • 341
  • This worked perfectly. Thanks! I thought about overriding that macro when reading their documentation, but I couldn't really make heads or tails of it. – TheSinisterStone Dec 27 '22 at 00:17