📄 yabasic.c
字号:
/*
YABASIC --- a tiny integrated Basic Compiler/Interpreter
written by Marc-Oliver Ihm 1995-99.
e-mail: ihm@kph.uni-mainz.de
Current Version:
*/
#define BASIC_VERSION "2.45"
/*
Date of last change:
*/
#define DOLC "February 26, 1999"
char YABLICENSE[]=
" This program is free software; you can redistribute it and/or \n"
" modify it under the terms of the GNU General Public License \n"
" as published by the Free Software Foundation; either version \n"
" of the License, or (at your option) any later version. \n"
" \n"
" This program is distributed in the hope that it will be useful, \n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of \n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n"
" GNU General Public License for more details. \n"
" \n"
" You should have received a copy of the GNU General Public License \n"
" along with this program (the file is named COPYING); \n"
" if not, write to the Free Software \n"
" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. \n"
;
/* ------------- defines ---------------- */
/*
Define one and only one of the following symbols, depending on your
System:
- UNIX: uses some UNIX-features and X11
- WINDOWS: uses WIN32-features
*/
#define DONE {current=current->next;break;} /* reduces type-work */
#if defined(UNIX) && defined(WINDOWS)
UNIX and WINDOWS are defined at once; check your compiler settings
#endif
/* ------------- includes ---------------- */
#ifndef YABASIC_INCLUDED
#include "yabasic.h" /* all prototypes and structures */
#endif
#ifdef UNIX
#include <curses.h>
#endif
/* ------------- external references ---------------- */
extern int yylineno; /* current line number */
extern void switch_to_my_file(FILE *); /* switches lex input */
extern int yyparse(); /* call bison parser */
/* ------------- global variables ---------------- */
struct symbol *symroot; /* first element in symbol list */
struct symbol *symhead; /* last element ind symbol list */
struct stackentry *stackroot; /* lowest element in stack */
struct stackentry *stackhead; /* topmost element in stack */
struct command *current; /* currently executed command */
struct command *cmdroot; /* first command */
struct command *cmdhead; /* last command */
struct command *datapointer; /* current location for read-command */
int infolevel; /* controls issuing of error messages */
int errorlevel; /* highest level of error message seen til now */
int end_of_file=FALSE; /* TRUE, if end of file has been reached */
int diagnostic_count; /* number of diagnostic messages */
int note_count; /* number of notes */
int warning_count; /* number of warning messages */
int error_count; /* number of error messages */
int interactive; /* true, if commands come from stdin */
char *string; /* for trash-strings */
int labelcount=0; /* count self-generated labels */
int commandcount; /* total number of commands */
int program_state; /* state of program */
int prompted; /* TRUE, if prompt is fresh */
FILE *streams[10]; /* file streams */
FILE *cinstr; /* current stream for input */
FILE *coutstr; /* current stream for output */
char linebuffer[INBUFFLEN]; /* buffer for one line of input */
int curinized=FALSE; /* true, if curses has been initialized */
char *currchar; /* current char to read */
struct buff_chain *buffroot; /* start of sys-input buffer */
struct buff_chain **buffcurr; /* current entry in buff_chain */
int buffcount; /* number of filled buffers */
char *progname; /* name of yabasic-program */
char *explanation[cLAST_COMMAND-cFIRST_COMMAND+1]; /* explanations */
char **yabargv; /* arguments for yabasic */
int yabargc; /* number of arguments in yabargv */
/* printer-related */
FILE *printerfile=NULL; /* file to print on */
char *prfilename=NULL; /* filename to print on */
int print_to_file; /* print to file ? */
/* ------------- global variables for Graphics ---------------- */
char *text_align; /* specifies alignement of text */
char *winorigin; /* direction to increase y */
#ifdef UNIX
Display *display; /* X-Display */
Window window,root; /* ID of window and root window */
GC gc; /* GC for drawing */
GC rgc; /* GC for reverse drawing */
XSizeHints sizehints; /* hints for window manager */
static unsigned long f_colour,b_colour; /* colors */
XFontStruct *myfont; /* properties of default font */
#elif WINDOWS
WNDCLASS myclass; /* window class for my program */
HWND window; /* handle of my window */
HANDLE this_instance;
HDC devcon; /* device context for screen */
HDC bitcon; /* device context backing bitmap */
HBITMAP backbit; /* backing bitmap */
char *my_class="my_class";
HANDLE wthandle; /* handle of win thread */
DWORD wtid; /* id of win thread */
HANDLE wtevent=INVALID_HANDLE_VALUE; /* handle for win thread event */
LOGFONT logfont; /* structure for font-characteristics */
HFONT myfont; /* handle of font for screen */
HFONT printerfont; /* handle of printer-font */
HPEN printerpen; /* handle of printer-pen */
HDC printer=NULL; /* handle of printer */
float prnscale; /* scaling factor for printer */
float prnoff; /* offset for printer */
BOOL Commandline; /* true if launched from command line */
HANDLE ConsoleInput; /* handle for console input */
HANDLE ConsoleOutput; /* handle for console output */
int LINES=0; /* number of lines on screen */
int COLS=0; /* number of columns on screen */
HANDLE mainthread=INVALID_HANDLE_VALUE; /* handle to main thread */
#endif
int winwidth,winheight; /* size of window */
int winx,winy; /* position of window */
int winopened=FALSE; /* flag if window is open already */
double psscale; /* from pixels to points */
int fontheight; /* height of used font in pixel */
char *foreground=NULL;
char *background=NULL;
char *geometry=NULL;
char *displayname=NULL;
char *font=NULL;
/* for plotting */
double xoff=0.; /* offset for x-mapping */
double xinc=1.; /* inclination of x-mapping */
double yoff=0.; /* offset for y-mapping */
double yinc=1.; /* inclination for y-mapping */
/* timing */
time_t compilation_start,compilation_end,execution_end;
/* ------------- main program ---------------- */
int main(int argc,char **argv)
{
#ifdef WINDOWS
CONSOLE_SCREEN_BUFFER_INFO csbi;
#endif
string=(char *)malloc(sizeof(char)*INBUFFLEN);
program_state=HATCHED;
infolevel=WARNING; /* set the initial Infolevel */
#ifdef WINDOWS
/* get handle for current thread */
DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),
GetCurrentProcess(),&mainthread,THREAD_ALL_ACCESS,FALSE,0);
/* get handle of instance */
this_instance=GetModuleHandle(NULL);
/* define my window class */
myclass.style=0;
myclass.lpfnWndProc=(LPVOID)mywindowproc;
myclass.cbClsExtra=0; /* no extra bytes */
myclass.cbWndExtra=0;
myclass.hInstance=this_instance;
myclass.hIcon=LoadIcon(this_instance,"yabasicIcon");
myclass.hCursor=LoadCursor(NULL,IDC_ARROW); /* standard cursor */
myclass.hbrBackground=(HBRUSH)COLOR_WINDOW; /* default-background */
myclass.lpszMenuName=NULL;
myclass.lpszClassName=my_class;
RegisterClass(&myclass);
/* get console handles */
ConsoleInput=GetStdHandle(STD_INPUT_HANDLE);
ConsoleOutput=GetStdHandle(STD_OUTPUT_HANDLE);
/* find out, if launched from commandline */
GetConsoleScreenBufferInfo(ConsoleOutput,&csbi);
Commandline=!((csbi.dwCursorPosition.X==0) && (csbi.dwCursorPosition.Y==0));
if ((csbi.dwSize.X<=0) || (csbi.dwSize.Y <= 0)) Commandline=TRUE;
#endif
parse_arguments(argc,argv);
time(&compilation_start);
initialize();
program_state=INITIALIZED;
error(NOTE,"Calling parser/compiler");
if (interactive) {
printf("Enter your program; type <RETURN> twice, when done.\n");
}
program_state=COMPILING;
if (yyparse() && errorlevel>ERROR) {
error(ERROR,"Couldn't parse program");
}
add_command(cEND);
sprintf(string,"Read %d line(s)",yylineno);
error(NOTE,string);
sprintf(string,"Generated %d command(s)",commandcount);
error(NOTE,string);
time(&compilation_end);
if (errorlevel>ERROR) {
program_state=RUNNING;
run_it();}
else {
program_state=FINISHED;
error(ERROR,"Program not executed");
}
sprintf(string,"%d diagnostic(s), %d note(s), %d warning(s), %d error(s)",
diagnostic_count,note_count,warning_count,error_count);
error(NOTE,string);
time(&execution_end);
sprintf(string,"Compilation time = %g second(s)",
difftime(compilation_start,compilation_end));
error(NOTE,string);
sprintf(string,"Execution time = %g second(s)",
difftime(execution_end,compilation_end));
error(NOTE,string);
end_it((errorlevel<=ERROR)?1:0);
return 0;
}
/* ------------- subroutines ---------------- */
struct symbol *get_sym(char *name,int type,int add)
/* gets the value of a symbol, or creates it with initial value type */
{
struct symbol *curr,*new;
curr=symroot;
while(curr!=symhead) { /* search 'til head of list */
if (curr->type==type /* do the types match ? */
&&!strcmp(name,curr->name)) /* do the names match ? */
return curr; /* give back address */
curr=curr->next; /* try next entry */
}
/* run (ppp) through all variables. */
if (!add) return NULL; /* dont create, if not found */
/* end of list, create new element */
new=(struct symbol *)my_malloc(sizeof(struct symbol)); /* ceate new item */
symhead=new; /* advance head */
curr->name=my_strdup(name); /* store new name */
curr->next=new;
curr->value=0.0;
curr->pointer=NULL;
curr->type=type;
curr->value=0.0;
if (type==sySTRING) { /* create empty string */
curr->pointer=my_malloc(sizeof(char));
*(char *)(curr->pointer)='\0';
}
return curr;
}
void create_pushdbl(double value) /* create command 'cPUSHDBL' */
{
struct command *cmd;
cmd=add_command(cPUSHDBL);
if (cmd->pointer==NULL) cmd->pointer=my_malloc(sizeof(double));
*(double *)(cmd->pointer)=value;
}
void pushdbl(struct command *cmd)
{
/* push double onto stack */
struct stackentry *p;
p=push();
p->value= *(double *)cmd->pointer;
p->type=stNUMBER;
}
void create_pushdblsym(char *symbol) /* create command 'pushdblsym' */
{
struct command *cmd;
cmd=add_command(cPUSHDBLSYM);
/* get room to store specific information */
cmd->pointer= &(get_sym(symbol,syNUMBER,TRUE)->value);
}
void pushdblsym(struct command *cmd)
{
/* push double symbol onto stack */
struct stackentry *p;
p=push();
p->value=*(double *)cmd->pointer;
p->type=stNUMBER;
}
void create_popdblsym(char *symbol) /* create command 'popdblsym' */
{
struct command *cmd;
struct symbol *s;
cmd=add_command(cPOPDBLSYM);
if (symbol) {
/* store specific information: */
s=get_sym(symbol,syNUMBER,TRUE);
cmd->pointer= &(s->value);
}
else {
cmd->pointer=NULL;
return;
}
}
void popdblsym(struct command *cmd) /* pop double from stack */
{
double d;
d=pop()->value;
if (cmd->pointer==NULL) return;
*(double *)(cmd->pointer)=d;
}
void create_dblbin(char c) /* create command for binary double operation */
{
switch(c) {
case '+':add_command(cDBLADD);break;
case '-':add_command(cDBLMIN);break;
case '*':add_command(cDBLMUL);break;
case '/':add_command(cDBLDIV);break;
case '^':add_command(cDBLPOW);break;
}
/* no specific information needed */
}
void dblbin(struct command *cmd) /* compute with two numbers from stack */
{
struct stackentry *d;
double a,b,c;
b=pop()->value;
a=pop()->value;
d=push();
switch(cmd->type) {
case(cDBLADD):c=a+b; break;
case(cDBLMIN):c=a-b; break;
case(cDBLMUL):c=a*b; break;
case(cDBLDIV):
if (fabs(b)<DBL_MIN) {
sprintf(string,"Division by zero, set to %g",DBL_MAX);
error(NOTE,string);
c=DBL_MAX;}
else
c=a/b;
break;
case(cDBLPOW):
if (b==2)
c=a*a;
else if (a<0) {
error(ERROR,"Power of negative value. Don't now what to do");
return;}
else
c=exp(b*log(a));
break;
}
d->value=c;
d->type=stNUMBER;
}
void negate() /* negates top of stack */
{
struct stackentry *a,*b;
double d;
a=pop();
d=a->value;
b=push();
b->type=stNUMBER;
b->value= -d;
}
void create_pushstrptr(char *symbol) /* push string-pointer onto stack */
{
struct command *cmd;
cmd=add_command(cPUSHSTRPTR);
cmd->pointer=&get_sym(symbol,sySTRING,TRUE)->pointer;
}
void pushstrptr(struct command *cmd) /* push string-pointer onto stack */
{
struct stackentry *p;
p=push();
p->pointer=*(char **)cmd->pointer;
p->type=stSTRING;
}
void create_pushstrsym(char *symbol) /* push string-symbol onto stack */
{
struct command *cmd;
cmd=add_command(cPUSHSTRSYM);
/* get room to store specific information */
cmd->pointer=&get_sym(symbol,sySTRING,TRUE)->pointer;
}
void pushstrsym(struct command *cmd) /* push string-symbol onto stack */
{
struct stackentry *p;
p=push();
p->pointer=my_strdup(*(char **)cmd->pointer);
p->type=stSTRING;
}
void create_popstrsym(char *symbol) /* create command 'popstrsym' */
{
struct command *cmd;
struct symbol *s;
cmd=add_command(cPOPSTRSYM);
if (symbol) {
/* storing specific information: */
s=get_sym(symbol,sySTRING,TRUE);
cmd->pointer=(char **)&(s->pointer);
}
else {
cmd->pointer=NULL;
}
}
void popstrsym(struct command *cmd) /* pop string from stack */
{
struct stackentry *p;
p=pop();
if (cmd->pointer==NULL) return;
if (*(char **)cmd->pointer!=NULL) free(*(char **)cmd->pointer);
*(char **)cmd->pointer=my_strdup(p->pointer);
}
void create_token(int delimiter) /* create command 'token' */
{
struct command *cmd;
cmd=add_command(cTOKEN);
cmd->args=delimiter;
}
void token(struct command *cmd) /* extract token from variable */
{
char *del; /* delimiter for strings */
struct stackentry *t;
char *old,*new,*tok;
if (cmd->args) del=pop()->pointer;
else del=" \t";
t=pop();
old=t->pointer;
t->pointer=NULL; /* prevent push from freeing the memory */
t=push();
t->type=stSTRING;
new=old;
tok=NULL;
while(*new) {
if (!tok && !strchr(del,*new)) tok=new; /* found start of token */
if (tok && strchr(del,*new)) break; /* found end of token */
new++;
}
if (*new) {
*new='\0'; /* terminate token */
new++;
while(*new) {
if (!strchr(del,*new)) break; /* found start of next token */
new++;
}
}
t->pointer=my_strdup(tok?tok:""); /* copy token */
/* move rest of string */
do {
*old=*new;
old++;
new++;
} while(*new);
*old='\0';
}
void concat() /* concetenates two strings from stack */
{
struct stackentry *a,*b,*c;
char *aa,*bb,*cc;
a=pop();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -