luac.c
(4.0.1)
/*
** $Id: luac.c,v 1.28 2000/11/06 20:06:27 lhf Exp $
** lua compiler (saves bytecodes to files; also list binary files)
** See Copyright Notice in lua.h
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lparser.h"
#include "lstate.h"
#include "lzio.h"
#include "luac.h"
#define OUTPUT "luac.out" /* default output file */
static void usage(const char* message, const char* arg);
static int doargs(int argc, const char* argv[]);
static Proto* load(const char* filename);
static FILE* efopen(const char* name, const char* mode);
static void strip(Proto* tf);
static Proto* combine(Proto** P, int n);
lua_State* lua_state=NULL; /* lazy! */
static int listing=0; /* list bytecodes? */
static int dumping=1; /* dump bytecodes? */
static int stripping=0; /* strip debug information? */
static int testing=0; /* test integrity? */
static const char* output=OUTPUT; /* output file name */
#define IS(s) (strcmp(argv[i],s)==0)
int main(int argc, const char* argv[])
{
Proto** P,*tf;
int i=doargs(argc,argv);
argc-=i; argv+=i;
if (argc<=0) usage("no input files given",NULL);
L=lua_open(0);
P=luaM_newvector(L,argc,Proto*);
for (i=0; i<argc; i++)
P[i]=load(IS("-")? NULL : argv[i]);
tf=combine(P,argc);
if (dumping) luaU_optchunk(tf);
if (listing) luaU_printchunk(tf);
if (testing) luaU_testchunk(tf);
if (dumping)
{
if (stripping) strip(tf);
luaU_dumpchunk(tf,efopen(output,"wb"));
}
return 0;
}
static void usage(const char* message, const char* arg)
{
if (message!=NULL)
{
fprintf(stderr,"luac: "); fprintf(stderr,message,arg); fprintf(stderr,"\n");
}
fprintf(stderr,
"usage: luac [options] [filenames]. Available options are:\n"
" - process stdin\n"
" -l list\n"
" -o file output file (default is \"" OUTPUT "\")\n"
" -p parse only\n"
" -s strip debug information\n"
" -t test code integrity\n"
" -v show version information\n"
);
exit(1);
}
static int doargs(int argc, const char* argv[])
{
int i;
for (i=1; i<argc; i++)
{
if (*argv[i]!='-') /* end of options */
break;
else if (IS("-")) /* end of options; use stdin */
return i;
else if (IS("-l")) /* list */
listing=1;
else if (IS("-o")) /* output file */
{
output=argv[++i];
if (output==NULL) usage(NULL,NULL);
}
else if (IS("-p")) /* parse only */
dumping=0;
else if (IS("-s")) /* strip debug information */
stripping=1;
else if (IS("-t")) /* test */
{
testing=1;
dumping=0;
}
else if (IS("-v")) /* show version */
{
printf("%s %s\n",LUA_VERSION,LUA_COPYRIGHT);
if (argc==2) exit(0);
}
else /* unknown option */
usage("unrecognized option `%s'",argv[i]);
}
if (i==argc && (listing || testing))
{
dumping=0;
argv[--i]=OUTPUT;
}
return i;
}
static Proto* load(const char* filename)
{
Proto* tf;
ZIO z;
char source[512];
FILE* f;
int c,undump;
if (filename==NULL)
{
f=stdin;
filename="(stdin)";
}
else
f=efopen(filename,"r");
c=ungetc(fgetc(f),f);
if (ferror(f))
{
fprintf(stderr,"luac: cannot read from ");
perror(filename);
exit(1);
}
undump=(c==ID_CHUNK);
if (undump && f!=stdin)
{
fclose(f);
f=efopen(filename,"rb");
}
sprintf(source,"@%.*s",Sizeof(source)-2,filename);
luaZ_Fopen(&z,f,source);
tf = undump ? luaU_undump(L,&z) : luaY_parser(L,&z);
if (f!=stdin) fclose(f);
return tf;
}
static Proto* combine(Proto** P, int n)
{
if (n==1)
return P[0];
else
{
int i,pc=0;
Proto* tf=luaF_newproto(L);
tf->source=luaS_new(L,"=(luac)");
tf->maxstacksize=1;
tf->kproto=P;
tf->nkproto=n;
tf->ncode=2*n+1;
tf->code=luaM_newvector(L,tf->ncode,Instruction);
for (i=0; i<n; i++)
{
tf->code[pc++]=CREATE_AB(OP_CLOSURE,i,0);
tf->code[pc++]=CREATE_AB(OP_CALL,0,0);
}
tf->code[pc++]=OP_END;
return tf;
}
}
static void strip(Proto* tf)
{
int i,n=tf->nkproto;
tf->lineinfo=NULL;
tf->nlineinfo=0;
tf->source=luaS_new(L,"=(none)");
tf->locvars=NULL;
tf->nlocvars=0;
for (i=0; i<n; i++) strip(tf->kproto[i]);
}
static FILE* efopen(const char* name, const char* mode)
{
FILE* f=fopen(name,mode);
if (f==NULL)
{
fprintf(stderr,"luac: cannot open %sput file ",*mode=='r' ? "in" : "out");
perror(name);
exit(1);
}
return f;
}
void luaU_testchunk(const Proto* Main)
{
UNUSED(Main);
fprintf(stderr,"luac: -t not operational in this version\n");
exit(1);
}