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.
CodePudding user response:
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.
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);
}
}