1139749Simp/*	$NetBSD$	*/
2193640Sariff
3193640Sariff/*
464881Scg** Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp
564881Scg** Lua compiler (saves bytecodes to files; also list bytecodes)
664881Scg** See Copyright Notice in lua.h
764881Scg*/
864881Scg
964881Scg#include <errno.h>
1064881Scg#include <stdio.h>
1164881Scg#include <stdlib.h>
1264881Scg#include <string.h>
1364881Scg
1464881Scg#define luac_c
1564881Scg#define LUA_CORE
1664881Scg
1764881Scg#include "lua.h"
1864881Scg#include "lauxlib.h"
1964881Scg
2064881Scg#include "ldo.h"
2164881Scg#include "lfunc.h"
2264881Scg#include "lmem.h"
2364881Scg#include "lobject.h"
2464881Scg#include "lopcodes.h"
2564881Scg#include "lstring.h"
2664881Scg#include "lundump.h"
2764881Scg
2864881Scg#define PROGNAME	"luac"		/* default program name */
2964881Scg#define	OUTPUT		PROGNAME ".out"	/* default output file */
3074763Scg
3174763Scgstatic int listing=0;			/* list bytecodes? */
3274763Scgstatic int dumping=1;			/* dump bytecodes? */
3374763Scgstatic int stripping=0;			/* strip debug information? */
3474763Scgstatic char Output[]={ OUTPUT };	/* default output file name */
3574763Scgstatic const char* output=Output;	/* actual output file name */
3674763Scgstatic const char* progname=PROGNAME;	/* actual program name */
3775319Scg
3875319Scgstatic void fatal(const char* message)
3974763Scg{
4074763Scg fprintf(stderr,"%s: %s\n",progname,message);
4174763Scg exit(EXIT_FAILURE);
4274763Scg}
4375319Scg
4475319Scgstatic void cannot(const char* what)
4570134Scg{
4689834Scg fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
4770134Scg exit(EXIT_FAILURE);
4875319Scg}
4989686Scg
5089834Scgstatic void usage(const char* message)
5170134Scg{
5270134Scg if (*message=='-')
5364881Scg  fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message);
5470134Scg else
5564881Scg  fprintf(stderr,"%s: %s\n",progname,message);
56193640Sariff fprintf(stderr,
57193640Sariff "usage: %s [options] [filenames].\n"
58193640Sariff "Available options are:\n"
59193640Sariff "  -        process stdin\n"
60193640Sariff "  -l       list\n"
61193640Sariff "  -o name  output to file " LUA_QL("name") " (default is \"%s\")\n"
62193640Sariff "  -p       parse only\n"
6374763Scg "  -s       strip debug information\n"
6474763Scg "  -v       show version information\n"
65117307Scg "  --       stop handling options\n",
66193640Sariff progname,Output);
6764881Scg exit(EXIT_FAILURE);
68193640Sariff}
69193640Sariff
70193640Sariff#define	IS(s)	(strcmp(argv[i],s)==0)
71193640Sariff
72193640Sariffstatic int doargs(int argc, char* argv[])
73193640Sariff{
74193640Sariff int i;
75193640Sariff int version=0;
76193640Sariff if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
77193640Sariff for (i=1; i<argc; i++)
7864881Scg {
79193640Sariff  if (*argv[i]!='-')			/* end of options; keep it */
80193640Sariff   break;
81193640Sariff  else if (IS("--"))			/* end of options; skip it */
82193640Sariff  {
83193640Sariff   ++i;
84193640Sariff   if (version) ++version;
85193640Sariff   break;
86193640Sariff  }
87193640Sariff  else if (IS("-"))			/* end of options; use stdin */
88193640Sariff   break;
8966308Scg  else if (IS("-l"))			/* list */
90193640Sariff   ++listing;
91193640Sariff  else if (IS("-o"))			/* output file */
92193640Sariff  {
93193640Sariff   output=argv[++i];
9466308Scg   if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument");
95193640Sariff   if (IS("-")) output=NULL;
96193640Sariff  }
97193640Sariff  else if (IS("-p"))			/* parse only */
98193640Sariff   dumping=0;
99193640Sariff  else if (IS("-s"))			/* strip debug information */
100193640Sariff   stripping=1;
101193640Sariff  else if (IS("-v"))			/* show version */
102193640Sariff   ++version;
103193640Sariff  else					/* unknown option */
104193640Sariff   usage(argv[i]);
105193640Sariff }
106193640Sariff if (i==argc && (listing || !dumping))
107193640Sariff {
108164614Sariff  dumping=0;
109193640Sariff  argv[--i]=Output;
110164614Sariff }
111164614Sariff if (version)
112164614Sariff {
113164614Sariff  printf("%s  %s\n",LUA_RELEASE,LUA_COPYRIGHT);
114164614Sariff  if (version==argc-1) exit(EXIT_SUCCESS);
115164614Sariff }
116193640Sariff return i;
117193640Sariff}
118193640Sariff
119193640Sariff#define toproto(L,i) (clvalue(L->top+(i))->l.p)
120193640Sariff
121193640Sariffstatic const Proto* combine(lua_State* L, int n)
122193640Sariff{
123193640Sariff if (n==1)
124193640Sariff  return toproto(L,-1);
125193640Sariff else
126193640Sariff {
127193640Sariff  int i,pc;
128193640Sariff  Proto* f=luaF_newproto(L);
129193640Sariff  setptvalue2s(L,L->top,f); incr_top(L);
130193640Sariff  f->source=luaS_newliteral(L,"=(" PROGNAME ")");
131193640Sariff  f->maxstacksize=1;
132193640Sariff  pc=2*n+1;
133193640Sariff  f->code=luaM_newvector(L,pc,Instruction);
134193640Sariff  f->sizecode=pc;
135193640Sariff  f->p=luaM_newvector(L,n,Proto*);
136193640Sariff  f->sizep=n;
137193640Sariff  pc=0;
138193640Sariff  for (i=0; i<n; i++)
139193640Sariff  {
140193640Sariff   f->p[i]=toproto(L,i-n-1);
141193640Sariff   f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i);
142193640Sariff   f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1);
143193640Sariff  }
144193640Sariff  f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
145193640Sariff  return f;
146193640Sariff }
147193640Sariff}
148193640Sariff
149193640Sariffstatic int writer(lua_State* L, const void* p, size_t size, void* u)
150193640Sariff{
151193640Sariff UNUSED(L);
152193640Sariff return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
153193640Sariff}
154193640Sariff
155193640Sariffstruct Smain {
156193640Sariff int argc;
157193640Sariff char** argv;
158193640Sariff};
159193640Sariff
160193640Sariffstatic int pmain(lua_State* L)
161193640Sariff{
162193640Sariff struct Smain* s = (struct Smain*)lua_touserdata(L, 1);
163193640Sariff int argc=s->argc;
164193640Sariff char** argv=s->argv;
165193640Sariff const Proto* f;
166193640Sariff int i;
167193640Sariff if (!lua_checkstack(L,argc)) fatal("too many input files");
168193640Sariff for (i=0; i<argc; i++)
169193640Sariff {
170193640Sariff  const char* filename=IS("-") ? NULL : argv[i];
171193640Sariff  if (luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1));
172193640Sariff }
173193640Sariff f=combine(L,argc);
174193640Sariff if (listing) luaU_print(f,listing>1);
175193640Sariff if (dumping)
176193640Sariff {
177193640Sariff  FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
178193640Sariff  if (D==NULL) cannot("open");
179193640Sariff  lua_lock(L);
180193640Sariff  luaU_dump(L,f,writer,D,stripping);
181193640Sariff  lua_unlock(L);
182193640Sariff  if (ferror(D)) cannot("write");
183193640Sariff  if (fclose(D)) cannot("close");
184193640Sariff }
185193640Sariff return 0;
186193640Sariff}
187193640Sariff
188193640Sariffint main(int argc, char* argv[])
189193640Sariff{
190193640Sariff lua_State* L;
191193640Sariff struct Smain s;
192193640Sariff int i=doargs(argc,argv);
193193640Sariff argc-=i; argv+=i;
194193640Sariff if (argc<=0) usage("no input files given");
195193640Sariff L=lua_open();
196164614Sariff if (L==NULL) fatal("not enough memory for state");
197193640Sariff s.argc=argc;
198193640Sariff s.argv=argv;
199193640Sariff if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1));
200193640Sariff lua_close(L);
201193640Sariff return EXIT_SUCCESS;
202164614Sariff}
203193640Sariff