/*
 * compile.c  -  Actually compile the MGL source code
 *
 * Copyright (C) 2003-2007 Gero Kuhlmann   <gero@gkminix.han.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: compile.c,v 1.11 2007/01/06 18:31:27 gkminix Exp $
 */

#include "mknbi.h"
#include "mgl.h"



/*
 *****************************************************************************
 *
 * Global variables
 */
int errors = 0;				/* Number of errors */
int warnings = 0;			/* Number of warnings */



/*
 *****************************************************************************
 *
 * Handle an internal error
 */
#ifdef PARANOID
void interror __F((num, msg), int num AND const char *msg)
{
  prnerr("internal error %d: %s", num, msg);
  nbexit(EXIT_INTERNAL);
}
#endif



/*
 *****************************************************************************
 *
 * Print an error message
 */
void error __F((msg, printtok), const char *msg AND int printtok)
{
  if (printtok)
	prnlog(LOGLEVEL_NORMAL, "[%s:%d] error: %s near '%s'", curfile, lineno, msg, yytext);
  else
	prnlog(LOGLEVEL_NORMAL, "[%s:%d] error: %s", curfile, lineno, msg);
  if (++errors > maxerrors) {
	prnerr("too many errors, aborting");
	nbexit(EXIT_MGL_COMPERRS);
  }
}



/*
 *****************************************************************************
 *
 * Print a warning message
 */
void warning __F((msg), const char *msg)
{
  prnlog(LOGLEVEL_NORMAL, "[%s:%d] warning: %s", curfile, lineno, msg);
  warnings++;
}



/*
 *****************************************************************************
 *
 * Compile the MGL input file. This routine returns a file descriptor
 * for a temporary file which contains the compiled output.
 */
int compile __F((infile, rtfile, outfile, incpath),
				char *infile AND
				char *rtfile AND
				char *outfile AND
				char *incpath)
{
  int fd, oldcharset;

  /* Initialize everything, and then call the parser */
  curlevel = -1;
  syminit();
  codeinit(rtfile);
  curlevel = 0;
  oldcharset = setcharset(CHARSET_UNKNOWN);
  yylexinit(infile, incpath);
  yyparse();
  (void)setcharset(oldcharset);
  if (errors > 0) {
	prnerr("%d error(s) encountered, aborting", errors);
	nbexit(EXIT_MGL_COMPERRS);
  }
  if (warnings > 0)
	prnerr("%d warning(s)", warnings);

  /* Write the compiled code into a temporary file */
  if (outfile == NULL) {
	fd = opentemp(verbose < 2);
	if (fd == -1)
		nbexit(-1);
  } else if ((fd = creat(outfile, 0644)) < 0) {
	prnerr("unable to create output file %s", outfile);
	nbexit(EXIT_CREATE);
  }
  codewrite(fd);
  return(fd);
}



/*
 *****************************************************************************
 *
 * Test routine which can be used to generate a program to just test the
 * MGL compiler without the mknbi overhead.
 */
#ifdef TEST
int main __F((argc, argv), int argc AND char **argv)
{
  char *infile;
  char *outfile;
  int fd;

  /* Check command line arguments */
  progname = argv[0];
  if (argc != 3) {
	fprintf(stderr, "usage: %s <infile> <outfile>\n", progname);
	exit(1);
  }
  infile = argv[1];
  outfile = argv[2];

  /* Now compile the input file */
  fd = compile(infile, NULL, outfile, NULL);
  close(fd);
  return(0);
}
#endif

