-#include <stddef.h>
-#include <stdio.h>
+#include "php_psi_stdinc.h"
+#include <sys/mman.h>
#include <assert.h>
-#include <errno.h>
-#include <string.h>
#include "parser.h"
-#include "parser_proc.h"
-void *PSI_ParserProcAlloc(void*(unsigned long));
-void PSI_ParserProcFree(void*, void(*)(void*));
-void PSI_ParserProc(void *, token_t, PSI_Token *, PSI_Parser *);
-void PSI_ParserProcTrace(FILE *, const char*);
+void *psi_parser_proc_Alloc(void*(unsigned long));
+void psi_parser_proc_Free(void*, void(*)(void*));
+void psi_parser_proc_(void *, token_t, struct psi_token *, struct psi_parser *);
+void psi_parser_proc_Trace(FILE *, const char*);
-PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename, psi_error_cb error, unsigned flags)
+struct psi_parser *psi_parser_init(struct psi_parser *P, psi_error_cb error, unsigned flags)
{
- FILE *fp;
-
- fp = fopen(filename, "r");
-
- if (!fp) {
- if (!(flags & PSI_PARSER_SILENT)) {
- error(NULL, NULL, PSI_WARNING, "Could not open '%s' for reading: %s",
- filename, strerror(errno));
- }
- return NULL;
- }
-
if (!P) {
P = malloc(sizeof(*P));
}
memset(P, 0, sizeof(*P));
- P->psi.file.fn = strdup(filename);
- P->fp = fp;
+ psi_data_ctor_with_dtors(PSI_DATA(P), error, flags);
+
P->col = 1;
P->line = 1;
- P->error = error;
- P->flags = flags;
- P->proc = PSI_ParserProcAlloc(malloc);
+ P->proc = psi_parser_proc_Alloc(malloc);
- if (flags & PSI_PARSER_DEBUG) {
- PSI_ParserProcTrace(stderr, "PSI> ");
+ if (flags & PSI_DEBUG) {
+ psi_parser_proc_Trace(stderr, "PSI> ");
}
- PSI_ParserFill(P, 0);
-
return P;
}
-size_t PSI_ParserFill(PSI_Parser *P, size_t n)
+bool psi_parser_open_file(struct psi_parser *P, const char *filename)
{
- if (P->flags & PSI_PARSER_DEBUG) {
- fprintf(stderr, "PSI> Fill: n=%zu\n", n);
+ FILE *fp = fopen(filename, "r");
+
+ if (!fp) {
+ P->error(PSI_DATA(P), NULL, PSI_WARNING,
+ "Could not open '%s' for reading: %s",
+ filename, strerror(errno));
+ return false;
}
- if (!n) {
- P->cur = P->tok = P->lim = P->mrk = P->buf;
- P->eof = NULL;
+
+ P->input.type = PSI_PARSE_FILE;
+ P->input.data.file.handle = fp;
+
+#if HAVE_MMAP
+ struct stat sb;
+ int fd = fileno(fp);
+
+ if (fstat(fd, &sb)) {
+ P->error(PSI_DATA(P), NULL, PSI_WARNING,
+ "Could not stat '%s': %s",
+ filename, strerror(errno));
+ return false;
}
- if (!P->eof) {
- size_t consumed = P->tok - P->buf;
- size_t reserved = P->lim - P->tok;
- size_t available = BSIZE - reserved;
- size_t didread;
-
- if (consumed) {
- memmove(P->buf, P->tok, reserved);
- P->tok -= consumed;
- P->cur -= consumed;
- P->lim -= consumed;
- P->mrk -= consumed;
- }
+ P->input.data.file.buffer = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (MAP_FAILED == P->input.data.file.buffer) {
+ P->error(PSI_DATA(P), NULL, PSI_WARNING,
+ "Could not map '%s' for reading: %s",
+ filename, strerror(errno));
+ return false;
+ }
+ P->input.data.file.length = sb.st_size;
+#else
+ P->input.data.file.buffer = malloc(BSIZE);
+#endif
- didread = fread(P->lim, 1, available, P->fp);
- P->lim += didread;
- if (didread < available) {
- P->eof = P->lim;
- }
+ P->file.fn = strdup(filename);
+
+ return true;
+}
+
+bool psi_parser_open_string(struct psi_parser *P, const char *string, size_t length)
+{
+ P->input.type = PSI_PARSE_STRING;
+ P->input.data.string.length = length;
+ if (!(P->input.data.string.buffer = strndup(string, length))) {
+ return false;
+ }
+
+ P->file.fn = strdup("<input>");
- if (P->flags & PSI_PARSER_DEBUG) {
- fprintf(stderr, "PSI> Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n",
- consumed, reserved, available, didread);
+ return true;
+}
+
+static ssize_t psi_parser_fill(struct psi_parser *P, size_t n)
+{
+ PSI_DEBUG_PRINT(P, "PSI< Fill: n=%zu (input.type=%d)\n", n, P->input.type);
+
+ /* init if n==0 */
+ if (!n) {
+ switch (P->input.type) {
+ case PSI_PARSE_FILE:
+ P->cur = P->tok = P->mrk = P->input.data.file.buffer;
+#if HAVE_MMAP
+ P->eof = P->input.data.file.buffer + P->input.data.file.length;
+ P->lim = P->eof;
+#else
+ P->eof = NULL;
+ P->lim = P->input.data.file.buffer;
+#endif
+ break;
+
+ case PSI_PARSE_STRING:
+ P->cur = P->tok = P->mrk = P->input.data.string.buffer;
+ P->eof = P->input.data.string.buffer + P->input.data.string.length;
+ P->lim = P->eof;
+ break;
}
+
+ PSI_DEBUG_PRINT(P, "PSI< Fill: cur=%p lim=%p eof=%p\n", P->cur, P->lim, P->eof);
}
- if (P->flags & PSI_PARSER_DEBUG) {
- fprintf(stderr, "PSI> Fill: avail=%zu\n", P->lim - P->cur);
+
+ switch (P->input.type) {
+ case PSI_PARSE_STRING:
+ break;
+
+ case PSI_PARSE_FILE:
+#if !HAVE_MMAP
+ if (!P->eof) {
+ size_t consumed = P->tok - P->buf;
+ size_t reserved = P->lim - P->tok;
+ size_t available = BSIZE - reserved;
+ size_t didread;
+
+ if (consumed) {
+ memmove(P->buf, P->tok, reserved);
+ P->tok -= consumed;
+ P->cur -= consumed;
+ P->lim -= consumed;
+ P->mrk -= consumed;
+ }
+
+ didread = fread(P->lim, 1, available, P->fp);
+ P->lim += didread;
+ if (didread < available) {
+ P->eof = P->lim;
+ }
+ PSI_DEBUG_PRINT(P, "PSI< Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n",
+ consumed, reserved, available, didread);
+ }
+#endif
+ break;
}
+
+ PSI_DEBUG_PRINT(P, "PSI< Fill: avail=%td\n", P->lim - P->cur);
+
return P->lim - P->cur;
}
-void PSI_ParserParse(PSI_Parser *P, PSI_Token *T)
+void psi_parser_parse(struct psi_parser *P, struct psi_token *T)
{
if (T) {
- PSI_ParserProc(P->proc, T->type, T, P);
+ psi_parser_proc_(P->proc, T->type, T, P);
} else {
- PSI_ParserProc(P->proc, 0, NULL, P);
+ psi_parser_proc_(P->proc, 0, NULL, P);
}
}
-void PSI_ParserDtor(PSI_Parser *P)
+void psi_parser_dtor(struct psi_parser *P)
{
- PSI_ParserProcFree(P->proc, free);
+ psi_parser_proc_Free(P->proc, free);
- if (P->fp) {
- fclose(P->fp);
+ switch (P->input.type) {
+ case PSI_PARSE_FILE:
+ if (P->input.data.file.buffer) {
+#if HAVE_MMAP
+ munmap(P->input.data.file.buffer, P->input.data.file.length);
+#else
+ free(P->input.data.file.buffer);
+#endif
+ }
+ if (P->input.data.file.handle) {
+ fclose(P->input.data.file.handle);
+ }
+ break;
+
+ case PSI_PARSE_STRING:
+ if (P->input.data.string.buffer) {
+ free(P->input.data.string.buffer);
+ }
+ break;
}
- PSI_DataDtor((PSI_Data *) P);
+ psi_data_dtor(PSI_DATA(P));
memset(P, 0, sizeof(*P));
}
-void PSI_ParserFree(PSI_Parser **P)
+void psi_parser_free(struct psi_parser **P)
{
if (*P) {
- PSI_ParserDtor(*P);
+ psi_parser_dtor(*P);
free(*P);
*P = NULL;
}
}
/*!max:re2c*/
-#define BSIZE 256
-
#if BSIZE < YYMAXFILL
# error BSIZE must be greater than YYMAXFILL
#endif
#define RETURN(t) do { \
P->num = t; \
- if (P->flags & PSI_PARSER_DEBUG) { \
- fprintf(stderr, "PSI> TOKEN: %d %.*s (EOF=%d %s:%u:%u)\n", \
+ PSI_DEBUG_PRINT(P, "PSI< TOKEN: %d %.*s (EOF=%d %s:%u:%u)\n", \
P->num, (int) (P->cur-P->tok), P->tok, P->num == PSI_T_EOF, \
- P->psi.file.fn, P->line, P->col); \
- } \
+ P->file.fn, P->line, P->col); \
return t; \
} while(1)
++P->line; \
goto label
-token_t PSI_ParserScan(PSI_Parser *P)
+token_t psi_parser_scan(struct psi_parser *P)
{
+ if (!P->cur) {
+ psi_parser_fill(P, 0);
+ }
for (;;) {
ADDCOLS;
nextline:
re2c:define:YYCURSOR = P->cur;
re2c:define:YYLIMIT = P->lim;
re2c:define:YYMARKER = P->mrk;
- re2c:define:YYFILL = "{ if (!PSI_ParserFill(P,@@)) RETURN(PSI_T_EOF); }";
+ re2c:define:YYFILL = "{ if (!psi_parser_fill(P,@@)) RETURN(PSI_T_EOF); }";
re2c:yyfill:parameter = 0;
B = [^a-zA-Z0-9_];
W = [a-zA-Z0-9_];
NAME = [a-zA-Z_]W*;
NSNAME = (NAME)? ("\\" NAME)+;
- DOLLAR_NAME = '$' NAME;
+ DOLLAR_NAME = '$' W+;
QUOTED_STRING = "\"" ([^\"])+ "\"";
NUMBER = [+-]? [0-9]* "."? [0-9]+ ([eE] [+-]? [0-9]+)?;
"]" {RETURN(PSI_T_RBRACKET);}
"=" {RETURN(PSI_T_EQUALS);}
"*" {RETURN(PSI_T_ASTERISK);}
+ "~" {RETURN(PSI_T_TILDE);}
+ "!" {RETURN(PSI_T_NOT);}
+ "%" {RETURN(PSI_T_MODULO);}
"&" {RETURN(PSI_T_AMPERSAND);}
"+" {RETURN(PSI_T_PLUS);}
"-" {RETURN(PSI_T_MINUS);}
"/" {RETURN(PSI_T_SLASH);}
+ "|" {RETURN(PSI_T_PIPE);}
+ "^" {RETURN(PSI_T_CARET);}
+ "<<" {RETURN(PSI_T_LSHIFT);}
+ ">>" {RETURN(PSI_T_RSHIFT);}
"..." {RETURN(PSI_T_ELLIPSIS);}
[\r\n] { NEWLINE(nextline); }
[\t ]+ { continue; }
'ARRAY' {RETURN(PSI_T_ARRAY);}
'OBJECT' {RETURN(PSI_T_OBJECT);}
'CALLBACK' {RETURN(PSI_T_CALLBACK);}
+ 'STATIC' {RETURN(PSI_T_STATIC);}
'FUNCTION' {RETURN(PSI_T_FUNCTION);}
'TYPEDEF' {RETURN(PSI_T_TYPEDEF);}
'STRUCT' {RETURN(PSI_T_STRUCT);}
'ARRVAL' {RETURN(PSI_T_ARRVAL);}
'OBJVAL' {RETURN(PSI_T_OBJVAL);}
'ZVAL' {RETURN(PSI_T_ZVAL);}
+ 'COUNT' {RETURN(PSI_T_COUNT);}
'CALLOC' {RETURN(PSI_T_CALLOC);}
'TO_OBJECT' {RETURN(PSI_T_TO_OBJECT);}
'TO_ARRAY' {RETURN(PSI_T_TO_ARRAY);}