首页
社区
课程
招聘
[原创 + 抄袭]TinyBASIC Version 1.0
发表于: 2007-5-28 11:55 8272

[原创 + 抄袭]TinyBASIC Version 1.0

2007-5-28 11:55
8272

// TinyBASIC.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <stdio.h>
#include <setjmp.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>

#define NUM_LAB                100
#define LAB_LEN                10
#define FOR_NEST        25
#define SUB_NEST        25
#define PROG_SIZE        10000

#define DELIMITER        1
#define VARIABLE        2
#define NUMBER                3
#define COMMAND                4
#define STRING                5
#define QUOTE                6

#define PRINT                1
#define INPUT                2
#define IF                        3
#define THEN                4
#define FOR                        5
#define NEXT                6
#define TO                        7
#define GOTO                8
#define EOL                        9
#define FINISHED        10
#define GOSUB                11
#define RETURN                12
#define END                        13

// Holds expressions to be analyzed.
char* p_buf;
char* prog;

// Holds environment for longjmp().
jmp_buf e_buf;

// 26 user variables,A-Z.
int variables[ 26 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

// Keywords lookup table.Commands must be entered lowercase in this table.
struct commands {
        char command[ 20 ];
        char tok;
} table[] = {
        { "print", PRINT  },
        { "input", INPUT  },
        { "if",    IF     },
        { "then",  THEN   },
        { "goto",  GOTO   },
        { "for",   FOR    },
        { "next",  NEXT   },
        { "to",    TO     },
        { "gosub", GOSUB  },
        { "return",RETURN },
        { "end",   END    },
        { "",      END    }
};

char token[ 80 ];
char token_type;
char tok;

struct label {
        char name[ LAB_LEN ];
        char* p;        // Points to place to go in source file.
} label_table[ NUM_LAB ];

char* find_label();
char* gpop();

// Stack for FOR-NEXT loop.
struct for_stack {
        int var;        // Counter variable.
        int target;        // Target value.
        char* loc;
} fstack[ FOR_NEST ];

struct for_stack fpop();

// Stack for GOSUB.
char* gstack[ SUB_NEST ];

// Index to top of FOR stack.
int ftos;

// Index to top of GOSUB stack.
int gtos;

void print();
void scan_labels();
void find_eol();
void exec_goto();
void exec_if();
void exec_for();
void exec_next();
void input();
void gosub();
void greturn();

int load_program( char* p,char* fname );
void label_init();
int get_next_label( char* s );
void fpush( struct for_stack i );
void gpush( char* s );
int look_up( char* s );

void get_exp( int* result );
//void level1( int* result );
void assignment();
void level2( int* result );
void level3( int* result );
void level4( int* result );
void level5( int* result );
void level6( int* result );
void primitive( int* result );
void arith( char o,int* r,int* h );
void unary( char o,int* r );
void putback();
void serror( int error );
void get_token();
int iswhite( char c );
int isdelim( char c );
int find_var( char* s );

int _tmain(int argc, _TCHAR* argv[])
{
        printf( "\r\n" );
        printf( "[]--------------------------------------------------[]\r\n" );
        printf( "|| TinyBASIC Version 1.0 - (C)2007 AZMC.13 presents ||\r\n" );
        printf( "[]--------------------------------------------------[]\r\n" );
        printf( "\r\n" );

        if( argc != 2 ) {
                printf( "Usage: TinyBasic <filename>\r\n" );
                exit( 1 );
        }

        // Allocate memory for the program.
        if( !( p_buf = ( char* )malloc( PROG_SIZE ) ) ) {
                printf( "Allocate memory failure!\r\n" );
                exit( 1 );
        }

        // Load the program to execute.
        if( !load_program( p_buf,argv[ 1 ] ) ) {
                free( p_buf );
                printf( "Can not load the program %s to execute!\r\n",argv[ 1 ] );
                exit( 1 );
        }

        // Initialize the long jump buffer.
        if( setjmp( e_buf ) ) {
                free( p_buf );
                printf( "\r\n* * * BAD JOB! * * *\r\n" );
                exit( 1 );
        }

        prog = p_buf;
        scan_labels();
        ftos = 0;
        gtos = 0;

        do {
                //token_type = get_token();
                get_token();

                // Check for assignment statement.
                if( token_type == VARIABLE ) {
                        putback();                // Return the variable to the input stream.
                        assignment();        // Must be assignment statement.
                }
                // Is command.
                else {
                        switch( tok ) {
                                case PRINT:
                                        print();
                                        break;
                                case GOTO:
                                        exec_goto();
                                        break;
                                case IF:
                                        exec_if();
                                        break;
                                case FOR:
                                        exec_for();
                                        break;
                                case NEXT:
                                        exec_next();
                                        break;
                                case INPUT:
                                        input();
                                        break;
                                case GOSUB:
                                        gosub();
                                        break;
                                case RETURN:
                                        greturn();
                                        break;
                                case END:
                                        free( p_buf );
                                        printf( "\r\n* * * GOOD JOB! * * *\r\n" );
                                        exit( 0 );
                        }
                }
        } while( tok != FINISHED );
       
        return 0;
}

int load_program( char* p,char* fname )
{
        FILE* fp;
        int i;

        if( !( fp = fopen( fname,"rb" ) ) ) return 0;

        i = 0;
        do {
                *p = getc( fp );
                p++;
                i++;
        } while( !feof( fp ) && i < PROG_SIZE );
        *( p - 2 ) = '\0';        // Null terminate the program.
        *( p - 1 ) = '\0';

        fclose( fp );

        return 1;
}

void assignment()
{
        int var;
        int value;

        // Get the variable name.
        get_token();
        if( !isalpha( *token ) ) {
                serror( 4 );
                return;
        }

        var = toupper( *token ) - 'A';
        get_token();
        if( *token != '=' ) {
                serror( 3 );
                return;
        }
       
        // Get the value to assign to variable.
        get_exp( &value );
        variables[ var ] = value;
}

// Execute a simple version of the BASIC "PRINT" statement.
void print()
{
        int answer;
        int len = 0;
        int spaces;
        char last_delim = '\0';

        do {
                get_token();        // Get next list item.
                if( tok == EOL || tok == FINISHED ) break;
                if( token_type  == QUOTE ) {        // Is String.
                        printf( token );
                        len += ( int )strlen( token );
                        get_token();
                }
                else {        // Is expression.
                        putback();
                        get_exp( &answer );
                        get_token();
                        len += printf( "%d",answer );
                }
                last_delim = *token;

                if( *token == ';' ) {
                        // Compute number of sapces to move to next TAB.
                        spaces = 8 - ( len % 8 );
                        // Add in the tabbing position.
                        len += spaces;
                        while( spaces ) {
                                printf( " " );
                                spaces --;
                        }
                }
                else if( *token == ',' ) {
                        // Do nothing.
                }
                else if( tok != EOL && tok != FINISHED ) {
                        serror( 0 );
                }
        } while( *token == ';' || *token == ',' );

        if( tok == EOL || tok == FINISHED ) {
                if( last_delim != ';' && last_delim != ',' ) printf( "\n" );
        }
        else {
                serror( 0 );
        }
}

// Find all labels.
void scan_labels()
{
        int addr;
        char* temp;

        // Zero all labels.
        label_init();
        // Save pointer to top of program.
        temp = prog;

        // If the first token in the file is label.
        get_token();
        if( token_type == NUMBER ) {
                strcpy( label_table[ 0 ].name,token );
                label_table[ 0 ].p = prog;
        }

        find_eol();
        do {
                get_token();
                if( token_type == NUMBER ) {
                        addr = get_next_label( token );
                        if( addr == -1 || addr == -2 ) {
                                addr == -1 ? serror( 5 ) : serror( 6 );
                        }
                        strcpy( label_table[ addr ].name,token );
                        label_table[ addr ].p = prog;
                }
                // If not on a blank line,find next line.
                if( tok != EOL ) find_eol();
        } while( tok != FINISHED );

        prog = temp;
}

// Find the start of the next line.
void find_eol()
{
        while( *prog != '\n' && *prog != '\0' ) ++prog;
        if( *prog ) prog++;
}

// Return index of next free position in label arrary.
// -1: is returned if the array is full;
// -2: is returned when duplicate label is found.
int get_next_label( char* s )
{
        int t;

        for( t = 0; t < NUM_LAB; ++t ) {
                if( label_table[ t ].name[ 0 ] == 0 ) return t;
                if( !strcmp( label_table[ t ].name,s ) ) return -2;
        }
        return -1;
}

// Find location of given label.A null is returned if label is not found;otherwise a pointer to
// the position of label is returned.
char* find_label( char* s )
{
        int t;

        for( t = 0; t < NUM_LAB; ++t ) {
                if( !strcmp( label_table[ t ].name,s ) ) return label_table[ t ].p;
        }
        return 0;
}

// Execute a GOTO command.
void exec_goto()
{
        char* loc;

        // Get label to goto.
        get_token();
        // Find the location of label.
        loc = find_label( token );
        if( loc == '\0' ) serror( 7 );        // Label not define.
        else prog = loc;                                // Start program running at that loc.
}

// Initilize the array that holds the labels.
// By convention,a null label name indicates that array position is unused.
void label_init()
{
        int t;

        for( t = 0; t < NUM_LAB; ++t ) label_table[ t ].name[ 0 ] = '\0';
}

// Execute an IF statement.
void exec_if()
{
        int x;
        int y;
        int cond;
        char op;

        get_exp( &x );        // Get left expression.

        get_token();        // Get the operator.
        if( !strchr( "=<>",*token ) ) {
                serror( 0 );
                return;
        }
        op = *token;

        get_exp( &y );        // Get the right expression.

        // Determine the outcome.
        cond = 0;
        switch( op ) {
                case '<':
                        if( x < y ) cond = 1;
                        break;
                case '>':
                        if( x > y ) cond = 1;
                        break;
                case '=':
                        if( x == y ) cond = 1;
                        break;
        }

        if( cond ) {        // Is true so process target of IF.
                get_token();
                if( tok != THEN ) {
                        serror( 8 );
                        return;
                }                        // else program execution starts on next line.
        }
        else find_eol();        // Find start of next line.
}

// Execute a FOR loop.
void exec_for()
{
        struct for_stack i;
        int value;

        get_token();        // Read the control variable.
        if( !isalpha( *token ) ) {
                serror( 4 );
                return;
        }
        i.var = toupper( *token ) - 'A';        // Save its index.

        get_token();        // Read the equals sign.
        if( *token != '=' ) {
                serror( 3 );
                return;
        }

        get_exp( &value );        // Get initial value.
        variables[ i.var ] = value;

        get_token();
        if( tok != TO ) serror( 9 );        // Read and discard the TO.

        get_exp( &i.target );                        // Get target value.

        // If loop can execute at least once,push info on stack.
        if( value >= variables[ i.var ] ) {
                i.loc = prog;
                fpush( i );
        }
        // Otherwise,skip loop code altogether.
        else {
                while( tok != NEXT ) get_token();
        }
}

// Execute a NEXT statement.
void exec_next()
{
        struct for_stack i;

        i = fpop();        // Read the loop info.

        variables[ i.var ] ++;        // Increment control variable.
        if( variables[ i.var ] > i.target ) return;        // All down.
        fpush( i );

        prog = i.loc;        // Loop.
}

// Push function for the FOR stack.
void fpush( struct for_stack i )
{
        if( ftos > FOR_NEST ) serror( 0 );
        fstack[ ftos ] = i;
        ftos++;
}

// Pop function for the FOR stack.
struct for_stack fpop()
{
        ftos--;
        if( ftos < 0 ) serror( 11 );
        return( fstack[ ftos ] );
}

// Execute a simple form of the BASIC INPUT command.
void input()
{
        char var;
        int i;

        get_token();        // See if prompt string is present.
        if( token_type == QUOTE ) {
                printf( token );
                // If so,print it and check for comma.
                get_token();
                if( *token != ',' ) serror( 1 );
                get_token();
        }
        else printf( "?" );        // Otherwise,prompt with "?".

        var = toupper( *token ) - 'A';        // Get the input variable.
        scanf( "%d",&i );                                // Read input.

        variables[ var ] = i;                        // Store it.
}

// Execute a GOSUB statement.
void gosub()
{
        char* loc;

        get_token();
        // Find the label to call.
        loc = find_label( token );
        if( loc == '\0' ) {
                serror( 7 );
        }
        else {
                gpush( prog );        // Save place to return to.
                prog = loc;                // Start program running at that loc.
        }
}

// Return from GOSUB.
void greturn()
{
        prog = gpop();
}

// GOSUB stack push fuction.
void gpush( char* s )
{
        gtos++;
        if( gtos == SUB_NEST ) {
                serror( 12 );
                return;
        }

        gstack[ gtos ] = s;
}

// GOSUB stack pop function.
char* gpop()
{
        if( gtos == 0 ) {
                serror( 13 );
                return 0;
        }

        return gstack[ gtos-- ];
}

void get_exp( int* result )
{
        get_token();
        if( !( *token ) ) {
                serror( 2 );
                return;
        }
        level2( result );
        putback();        // Retuen last token read to input string.
}

void level2( int* result )
{
        char op;
        int hold;
       
        level3( result );
        while( ( op = *token ) == '+' || op == '-' ) {
                get_token();
                level3( &hold );
                arith( op,result,&hold );
        }
}

void level3( int* result )
{
        char op;
        int hold;
       
        level4( result );
        while( ( op = *token ) == '*' || op == '/' || op == '%' ) {
                get_token();
                level4( &hold );
                arith( op,result,&hold );
        }
}

void level4( int* result )
{
        int hold;

        level5( result );
        if( *token == '^' ) {
                get_token();
                level4( &hold );
                arith( '^',result,&hold );
        }
}

void level5( int* result )
{
        char op;
       
        op = 0;
        if( ( token_type == DELIMITER ) && *token == '+' || *token == '-' ) {
                op = *token;
                get_token();
        }
        level6( result );
        if( op ) {
                unary( op,result );
        }
}

void level6( int* result )
{
        if( ( *token == '(' ) && ( token_type == DELIMITER ) ) {
                get_token();
                level2( result );
                if( *token != ')' ) {
                        serror( 1 );
                        return;
                }
                get_token();
        }
        else {
                primitive( result );
        }
}

void primitive( int* result )
{
        switch( token_type ) {
                case VARIABLE:
                        *result = find_var( token );
                        get_token();
                        return;
                case NUMBER:
                        *result = atoi( token );
                        get_token();
                        return;
                default:
                        serror( 0 );
        }
}

void arith( char o,int* r,int* h )
{
        int t;
        int ex;
       
        switch( o ) {
                case '-':
                        *r = *r - *h;
                        break;
                case '+':
                        *r = *r + *h;
                        break;
                case '*':
                        *r = ( *r ) * ( *h );
                        break;
                case '/':
                        *r = ( *r ) / ( *h );
                        break;
                case '%':
                        t = ( *r ) / ( *h );
                        *r = *r - ( t * ( *h ) );
                        break;
                case '^':
                        ex = *r;
                        if( *h == 0 ) {
                                *r = 1;
                        }
                        else {
                                for( t = *h - 1; t > 0; --t ) {
                                        *r = ( *r ) * ex;
                                }
                        }
                        break;
        }
}

void unary( char o,int* r )
{
        if( o == '-' ) *r = -( *r );
}

void putback()
{
        char* t;
       
        t = token;
        for( ; *t; t++ ) prog--;
}

void serror( int error )
{
        static char* e[] = {
                "Syntax error!\r\n",
                "Unbalanced parentheses!\r\n",
                "No expression present!\r\n",
                "Equals sign expected!\r\n",
                "Not a variable!\r\n",
                "Label table full!\r\n",
                "Duplicate label!\r\n",
                "Undefined label!\r\n",
                "THEN expected!\r\n",
                "TO expected!\r\n",
                "Too many nested FOR loops\r\n",
                "NEXT without FOR!\r\n",
                "Too many nested GOSUB\r\n",
                "RETURN without GOSUB!\r\n"
        };
        char* temp;
        char* start = p_buf;
        char errline[ 80 ];
        int i = 0;
        int linenumber = 1;

        putback();
        temp = prog;
        while( *temp != '\n' && temp != p_buf ) temp--;
        if( temp != p_buf ) temp++;
        while( start <= temp ) {
                if( *start == '\r' ) linenumber++;
                start++;
        }
        while( *temp != '\r' ) {
                errline[ i ] = *temp;
                temp++;
                i++;
        }
        errline[ i ] = '\0';

        printf( "\r\n" );
        printf( "Error at line :: %d - [ %s ]\r\n",linenumber,errline );
        printf( ":::::::::::::::: %s\r\n",e[ error ] );
        longjmp( e_buf,1 );        // Return to save point.
}

void get_token()
{
        char* temp;
       
        token_type = 0;
        tok = 0;
        temp = token;

        if( *prog == '\0' ) {
                *token = 0;
                tok = FINISHED;
                token_type = DELIMITER;
                return;
        }

        // Skip over white space.
        while( iswhite( *prog ) ) ++prog;

        if( *prog == '\r' ) {        // CrLf.
                ++prog;
                ++prog;
                tok = EOL;
                token[ 0 ] = '\r';
                token[ 1 ] = '\n';
                token[ 2 ] = '\0';
                token_type = DELIMITER;
                return;
        }

        if( strchr( "+-*^/%=;(),><",*prog ) ) {        // Delimiter.
                *temp = *prog;
                prog++;        // Advance to next position.
                temp++;
                *temp = 0;
                token_type = DELIMITER;
                return;
        }

        if( *prog == '"' ) {        // Quoted string.
                prog++;
                while( *prog != '"' && *prog != '\r' ) *temp++ = *prog++;
                if( *prog == '\r' ) serror( 1 );
                prog++;
                *temp = 0;
                token_type = QUOTE;
                return;
        }

        if( isdigit( *prog ) ) {        // Number.
                while( !isdelim( *prog ) ) *temp++ = *prog++;
                *temp = 0;
                token_type = NUMBER;
                return;
        }

        if( isalpha( *prog ) ) {        // Variable or command.
                while( !isdelim( *prog ) ) *temp++ = *prog++;
                token_type = STRING;
        }
        *temp = 0;

        // See if a string is a command or a variable.
        if( token_type == STRING ) {
                tok = look_up( token );
                if( !tok ) token_type = VARIABLE;
                else token_type = COMMAND;
        }
}

// Look up a token's internal representation in the token table.
int look_up( char* s )
{
        int i;
        char* p;

        p = s;
        while( *p ) {
                *p = tolower( *p );
                p++;
        }

        for( i = 0; *table[ i ].command; i++ ) {
                if( !strcmp( table[ i ].command,s ) ) return table[ i ].tok;
        }

        return 0;
}

int iswhite( char c )
{
        if( c == ' ' || c == 0x9 ) return 1;
        return 0;
}

int isdelim( char c )
{
        if( strchr( ";,+-< >/*%^=()",c ) || c == 0x9 || c == '\r' || c == 0 ) return 1;
        return 0;
}

int find_var( char* s )
{
        if( !isalpha( *s ) ) {
                serror( 4 );
                return 0;
        }
        return variables[ toupper( *token ) - 'A' ];
}

===================
测试程序1
===================

PRINT "TinyBASIC testing..."

PRINT "西安是个好地方!"

FOR X=10 TO 15
        PRINT "X= ",X;" X/2= ",X/2;"X+X= ",X+X
NEXT

GOSUB 300

PRINT "Hello"

INPUT "Please input a integer:",H
PRINT H
IF H < 11 THEN GOTO 200

PRINT 155
200 PRINT 100
A=255
PRINT "A = ",A
IF A>10 THEN PRINT "This is OK!"
PRINT "A+34 = ",A+34
PRINT "H+A = ",H+A

INPUT "Enter a number: ",I
GOSUB 888

PRINT "AxHxI = ",A*H*I

FOR C=10 TO 30
        FOR D=1 TO 10
                PRINT C;D;C+D
        NEXT
NEXT

END

300 PRINT "This is a subroutine!"
    RETURN

888 FOR T = 1 TO I
        X=X+I
        GOSUB 999
    NEXT
    RETURN

999 PRINT X
    RETURN

===================
测试程序2
===================
FOR X=10 TO 15
        FOR B=X TO 25
                PRINT B
        NEXT
NEXT

PRINT "-------------"
PRINT -9


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (5)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
经典中的精华,小弟感叹
2007-5-28 12:52
0
雪    币: 8107
活跃值: (1955)
能力值: ( LV8,RANK:122 )
在线值:
发帖
回帖
粉丝
3
好文, 收藏一下
2007-5-28 16:40
0
雪    币: 217
活跃值: (99)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
想起当年盖茨的4K-BASIC,其中解释器只有1.3KB.
2007-5-28 19:29
0
雪    币: 223
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
强,,,,,,
收藏啦
2007-5-28 20:56
0
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
好,现看看再说,顶
2007-5-28 23:41
0
游客
登录 | 注册 方可回帖
返回
//