typedef struct loc_file_s {
	char *fn;              /* file name, as present in #include */
	char *path;            /* full path (note search paths) */
} loc_file_t;

typedef struct loc_s {
	loc_file_t *file;      /* host file */
	int soffs, eoffs;      /* byte offsets from the start of the file (start/end) counting from 0 */
	int sline, scol;       /* start line/col counting from 1 */
	int eline, ecol;       /* end line/col counting from 1 */

	/* NOTE: update loc_cpy_start()/loc_cpy_end() when new fields are inserted */

	int offs; /* last seen byte offset in the file */

#ifdef PARSER_NALLOC_DEBUG
	int yline;
#endif

	int macro_level;          /* macro expansion nesting level; 0 means not in macro */
	int is_local;             /* whether the location is local (directly in the target file, not in included file) */

	int cpp_line;
	const char *cpp_file;

	node_t *twin_parent;      /* parent in the twin tree: for a grammar tree node, this is the token node */
	int twin_parent_uid;      /* for the duration of loading nodes from a file: valid only as long as twin_parent is NULL */
} loc_t;

/* a string with location: for saving token start info */
typedef struct strloc_s {
	char *str;
	loc_t loc;
} strloc_t;


/* current location we are reading tokens at (top of the location stack) */
extern loc_t *loc_current;
extern loc_t loc_invalid;

/* format string for printing location */
extern char *loc_format;

/* print location using loc_format in a static buffer */
const char *loc_print(const node_t *node);

/* convert a location found in in, using loc_format in a static buffer (returned) */
loc_t *loc_scan(const char *in);

/* Open a new file, set it as current loc_file, pushing the old current on
   top of the stack; hash files by path */
void loc_file_open(const char *fn, const char *path);

/* Close current loc_file, pop loc from the stack, make that the current one */
void loc_file_close(void);

/* New location file name; check if it's the currently open file. If not,
   decide whether it's an include or the end of the current input */
void loc_switch_file(const char *fn, const char *path);

/* Copy current loc end fields to start fields, advance the end
   fields as needed using token string; returns token to shorten source
   of the .l */
const char *loc_update_end(const char *token);

/* Copy location struct */
void loc_cpy(loc_t *dst, const loc_t *src);

/* Copy location not related to start/end (file, cpp) */
void loc_cpy_misc(loc_t *dst, const loc_t *src);

/* Copy token-start fields of a location struct */
void loc_cpy_start(loc_t *dst, const loc_t *src);

/* Copy token-end fields of a location struct */
void loc_cpy_end(loc_t *dst, const loc_t *src);

/* set dst location to start..end; if start or end is NULL, no modification
   is made on that field of dst. */
void loc_set(loc_t *dst, const loc_t *start, const loc_t *end);

/* macro shorthands for the most common case: copy between node locations */
#define Nloc_cpy(ndst, nsrc)        loc_cpy(&((ndst)->loc), &((nsrc)->loc))
#define Nloc_cpy_start(ndst, nsrc)  loc_cpy_start(&((ndst)->loc), &((nsrc)->loc))
#define Nloc_cpy_end(ndst, nsrc)    loc_cpy_end(&((ndst)->loc), &((nsrc)->loc))


/* return a cpp location file name - have unique pointer to each file name */
const char *loc_cpp_file_lookup(const char *fn);

/* Delete the location files database and stack */
void loc_destroy();


