bbi_pars.cpp

/**************************************/
/*  filename:bbi.cpp 構文解析         */
/**************************************/
#include "bbi.h"
#include "bbi_prot.h"

#define NO_FIX_ADRS 0
Token token;
SymTbl tmpTb;
int blkNest;
int localAdrs;
int mainTblNbr;
int loopNest;
bool fncDecl_F;
bool explicit_F;
char codebuf[LIN_SIZ+1], *codebuf_p;
extern vector<char*> intercode;

void init()
{
    initChTyp();
    mainTblNbr = -1;
    blkNest = loopNest = 0;
    fncDecl_F = explicit_f = false;
    codebuf_p = codebuf;
}

void convert_to_internalCode(char *fname)
{
    init();
    
    fileOpen(fname);
    while (token=nextLine_tkn(), token.kind != EofProg){
        if (token.kind == Func){
            token = nextTkn(); set_name(); enter(tmpTb, fncId);
        }
    }
    push_intercode();
    fileOpen(fname);
    token = nextLine_tkn();
    while(token.kind != EofProg){
        convert();
    }
    
    set_startPc(1);
    if (mainTblNbr != -1){
        set_startPc(intercode.size());
        setCode(Fcall, mainTblNbr); setCode('('); setCode(')');
        push_intercode();
    }
}

void convert()
{
    switch (token.kind){
        case Option: optionSet(); break;
        case Var: varDec1(); break;
        case Func: fncDec1(); break;
        case While: case For:
            ++loopNest;
            convert_block_set(); setCode_end();
            --loopNest;
            break;
        case If:
            convert_block_set();
            while(token.kind==Elif){ convert_block_set(); }
            if (token.kind == Else) { convert_block_set(); }
            setCode_End();
            break;
        case Break:
            if (loopNest <= 0) err_exit("不正なbreakです。");
            setCode(token.kind); token= nextTkn(); convert_rest();
            break;
        case Return:
            if (!fncDecl_F) err_exit("不正なreturnです。");
            setCode(token.kind); token=nextTkn(); convert_rest();
            break;
        case Exit:
            setCode(token.kind); token = nextTkn(); convert_rest();
            break;
        case Print: case Println:
            setCode(token.kind); token = nextTkn(); convert_rest();
            break;
        case End:
            err_exit("不正なendです。");
            break;
        default: convert_rest(); break;
    }
}

void convert_block_set()
int patch_line;
patch_line = setCode(token.kind, NO_FIX_ADRS); token = nextTkn();
convert_rest();
convert_block();
backPatch(patch_line, get_lineNo());
}

void convert_block()
{
    TknKind k;
    ++blkNest;
    while(k=token.kind, k!=Elif && k!=Else && k!=End && k!=EofProg){
        convert();
    }
    --blkNest;
}

void convert_rest()
{
    int tblNbr;
    
    for(;;){
        if(token.kind == EofLine) break;
        switch (token.kind){
            case If: case Elif:case Eles: case For: case While: case Break:
            case Func: case Return: case Exit: case Print: case Println:
            case Option: case Var: case End:
                err_exit("不正な記述です: ", token.text);
                break;
            case Ident:
                set_name();
                if((tblNbr=searchName(tmpTb.name, 'F')) != -1){
                    if (tmpTb.name== "main") err_exit("main関数の呼び出しはできません。");
                    setCode(Fcall, tblNbr); continue;
                }
                if ((tblNbr=searchName(tmpTb.name, 'V')) == -1){
                    if (explicit_F) err_exit("変数宣言が必要です:", tmpTb.name);
                    tblNbr = enter(tmpTb, varId);
                }
                if (is_localName(tmpTb.name, varId) setCode(Lvar, tblNbr);
                    else setCode(Gvar, tblNbr);
                    continue;
                    case IntNum: case DblNum:
                    setCode(token.kind, set_LITERAL(token.dblVal));
                    break;
                    case String:
                    setCode(token.kind, set_LITERAL(token.text));
                    break;
                    default:
                    setCode(token.kind);
                    break;
        }
                    token = nextTkn();
    }
                    push_intercode();
                    token = nextLine_tkn();
}

void optionSet()
                {
                    setCode(Option);
                    setCode_rest();
                    token = nextTkn();
                    if (token.kind == String && token.text == "var") explicit__F = true;
                    else err_exit("option指定が不正です。");
                    token = nextTkn();
                    setCode_EofLine();
                }

void varDec1()
                {
                    setCode(Var);
                    setCode_rest();
                    for(;;){
                        token = nextTkn();
                        var_namechk(token);
                        set_name(); set_aryLen();
                        enter(tmpTb, varId);
                        if(token.kind != ',')break;
                    }
                    setCode_EofLine();
                }

void var_namechk(const Token& tk)
                {
                    if (tk.kind != Ident) err_exit(err_msg)
                        if (is_localScope() && tk.text&#91;0&#93; == '$')
                            err_exit("関数内のvar宣言では$付き名前を指定できません:", tk.text);
                    if (searchName(tk.text, 'V') != -1)
                        err_exit("識別子が重複しています:", tk.text);
                }

void set_name()
                {
                    if (token.kind != Ident) err_exit("識別子が必要です。:", token.text);
                    tmpTb.clear(); tmpTb.name = token.text;
                    token = nextTkn();
                }
void set_aryLen()
                {
                    tmpTb.aryLen = 0;
                    if (token.kind != '&#91;') return;
                    
                    token = nextTkn();
                    if (token.kind != IntNum)
                        err_exit("配列長は正の整数定数で指定してください。", token.text);
                    tmpTb.aryLen = (int)token.dblVal + 1;
                    token = chk_nextTkn(nextTkn(), '&#93;');
                    if (token.kind == '&#91;') err_exit("多次元配列は宣言できません。");
                }

void fncDecl()
                {
                    extern vector<SymTbl> Gtable;
                    int tblNbr, patch_line, fncTblNbr;
                    
                    if(blkNest > 0) err_exit("関数定義の位置が不正です。");
                    fncDecl_F = true;
                    localAdrs = 0;
                    set_startLtable();
                    patch_line = setCode(Func, NO_FIX_ADRS);
                    token = nextTkn();
                    
                    fncTblNbr = searchName(token.text, 'F');
                    Gtable[fncTblNbr].dtTyp = DBL_T;
                    token = nextTkn();
                    token = chk_nextTkn(token, '(');
                    setCode('(');
                    if (token.kind != ')'){
                        for (;; token=nextTkn()){
                            set_name();
                            tblNbr = enter(tmpTb, paraId);
                            setCode(Lvar, tblNbr);
                            ++Gtable[fncTblNbr].args;
                            if(token.kind != ',')break;
                            setCode(',');
                        }
                    }
                    token = chk_nextTkn(token, ')');
                    setCode(')'); setCode_EofLine();
                    convert_block();
                    
                    backPatch(patch_line, get_lineNo());
                    setCode_End();
                    Gtable[fncTblNbr].frame = localAdrs;
                    
                    if (Gtable[fncTblNbr].name == "main"){
                        mainTblNbr = fncTblNbr;
                        if (Gtable[mainTblNbr].args != 0)
                            err_exit("main関数では仮引数を指定できません。");
                    }
                    fncDecl_F = false;
                }
void backPatch(int line, int n)
                {
                    *SHORT_P(intercode[line] + 1) = (short)n;
                }

void setCode(int cd)
                {
                    *codebuf_p++ = (char) cd;
                }

int setCode(int cd, int nbr)
                {
                    *codebuf_p++ = (char)cd;
                    *SHORT_P(codebuf_p) = (short)nbr; codebuf_p += SHORT_SIZ;
                    return get_lineNo();
                }

void setCode_rest()
                {
                    extern char *token_p;
                    strcpy(codebuf_p, token_p);
                    codebuf_p += strlen(token_p)+1;
                }

void setCode_End()
                {
                    if (token.kind != End) err_exit(err_msg(token.text, "end"));
                    setCode(End); token = nextTkn(); setCode_EofLine();
                }

vose setCode_EofLine()
                {
                    if (token.kind != EofLine) err_exit("不正な記述です: ", token.text);
                    push_intercode();
                    token = nextLine_tkn();
                }

void push_intercode()
                {
                    int len;
                    char *p
                    
                    *codebuf_p++ = '\0';
                    if (( len = codebuf_p-codebuf) >= LIN_SIZ)
                        err_exit("返還後の内部コードが長すぎます。式を短くしてください。");
                    
                    try {
                        p = new char[len];
                        memcpy(p, codebuf, len);
                        intercode.push_back(p);
                    }
                    catch (bad_alloc){err_exit("メモリ確保できません");}
                    codebuf_p = codebuf;
                }

bool is_localScope()
                {
                    return fncDecl_F;
                }