# coding: Shift_JIS

# ##############################

# ファイル名: jotalvar.py
# 機能: pragma.pyで出力された解析済みCファイルから状態変数候補の変数を探し，
#	変数名のリストを出力する．
# 関数: divider, JokenifComparator, ShoriifComparator, jotaivar
# 著者名: 山本椋太，若林丈紘

# ##############################

import re
import os
import shutil
import sys

# ##############################

# 関数名: flatten
# 機能: 入れ子構造になっているlistを，すべてフラット（入れ子構造の解消）にする．
# 引数
#   li: リスト

# ##############################

def flatten(li):
    ret = []
    if type(li) == type([]):
        for l in li:
            if type(l) != type([]):
                ret.append(l)
            else:
                temp = flatten(l)
                if type(temp) == type([]):
                    for t in temp:
                        ret.append(t)
                else:
                    ret.append(temp)
        return ret
    else:
        return li

# ##############################

# 関数名: divider
# 機能: 条件文から変数を抽出する．
# 引数
#   instring: 解析中の文字列

# ##############################

def divider(instring):
    retstr = ""
    instring = str(instring)
    tempstr = instring.replace(" ", "")
    tempstr =  tempstr.replace("<<", "＜＜")
    tempstr =  tempstr.replace(">>", "＞＞")
    tempstr =  tempstr.replace("->", "―＞＞")
    instring = tempstr
    instring = str(instring)
    if re.search("==",instring):
        ss = instring.split("==")
        if len(ss) == 1:
            retstr = divider(str(ss[0]))
        else:
            for s in ss:
                retstr = retstr + divider(s)
    elif re.search(">=",instring):
        ss = instring.split(">=")
        if len(ss) == 1:
            retstr = divider(str(ss[0]))
        else:
            for s in ss:
                retstr = retstr + divider(s)

    elif re.search("<=",instring):
        ss = instring.split("<=")
        if len(ss) == 1:
            retstr = divider(str(ss[0]))
        else:
            for s in ss:
                retstr = retstr + divider(s)

    elif re.search("!=",instring):
        ss = instring.split("!=")
        if len(ss) == 1:
            retstr = divider(str(ss[0]))
        else:
            for s in ss:
                retstr = retstr + "\t" +divider(s)

    elif re.search(">",instring):
        ss = instring.split(">")
        if len(ss) == 1:
            retstr = retstr + "\t" + divider(str(ss[0]))
        else:
            for s in ss:
                retstr = retstr +  "\t" +divider(s)
    elif re.search("<",instring):
        ss = instring.split("<")
        if len(ss) == 1:
            retstr = divider(str(ss[0]))
        else:
            for s in ss:
                retstr = retstr +  "\t" + divider(s)

    elif re.search("&&",instring):
        ss = instring.split("&&")
        if len(ss) == 1:
            retstr = divider(str(ss[0]))
        else:
            for s in ss:
                retstr = retstr + "\t" + divider(s)
    elif re.search("\|\|",instring):
        ss = instring.split("||")
        if len(ss) == 1:
            retstr = divider(str(ss[0]))
        else:
            for s in ss:
                retstr = retstr + "\t" + divider(s)
    else:
        retstr = instring
    row = retstr.split("\t")
    for r in row:
        if re.match("[0-9]+.*",r):
            row.remove(r)
    retstr = ""
    for r in row:
        retstr = retstr + r + "\t"
    return(retstr)

# ##############################

# 関数名: ExtractVarUsedInNotEqualCondition
# 機能: 条件式で，<, >, <=, >=, != を使っている部分の項を抽出し，変数であろうとなかろうと抽出する．
# 引数
#   line: 解析中の行の文字列．

# ##############################

def ExtractVarUsedInNotEqualCondition(line):
    ret = list()
    if re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+<=[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line):
        line = line.replace(' \t','')
        term = line.split('<=')
        for t in term:
            temp = ExtractVarUsedInNotEqualCondition(t)
            if temp == None:
                if re.match("IF@@@",t):
                    t = t[8:]
                elif re.match("EI@@@",t):
                    t = t[12:]
                else:
                    t = t[:-1]
                ret.append(t.replace(' ',''))
            else:
                for tp in temp: ret.append(tp)
        if ret != []:
            return ret

    elif re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+>=[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line):
        line = line.replace(' \t','')
        term = line.split('>=')
        for t in term:
            temp = ExtractVarUsedInNotEqualCondition(t)
            if temp == None:
                if re.match("IF@@@",t):
                    t = t[8:]
                elif re.match("EI@@@",t):
                    t = t[12:]
                else:
                    t = t[:-1]
                ret.append(t.replace(' ',''))
            else:
                for tp in temp: ret.append(tp)
        if ret != []:
            return ret
    elif re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+<[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line):
        line = line.replace(' \t','')
        term = line.split('<')
        for t in term:
            temp = ExtractVarUsedInNotEqualCondition(t)
            if temp == None:
                if re.match("IF@@@",t):
                    t = t[8:]
                elif re.match("EI@@@",t):
                    t = t[12:]
                else:
                    t = t[:-1]
                ret.append(t.replace(' ',''))
            else:
                for tp in temp: ret.append(tp)
        if ret != []:
            return ret
    elif re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+>[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line):
        line = line.replace(' \t','')
        term = line.split('>')
        for t in term:
            temp = ExtractVarUsedInNotEqualCondition(t)
            if temp == None:
                if re.match("IF@@@",t):
                    t = t[8:]
                elif re.match("EI@@@",t):
                    t = t[12:]
                else:
                    t = t[:-1]
                ret.append(t.replace(' ',''))
            else:
                for tp in temp: ret.append(tp)
        if ret != []:
            return ret
    elif '!=' in line:
        line = line.replace(' \t','')
        term = line.split('!=')
        for t in term:
            temp = ExtractVarUsedInNotEqualCondition(t)
            if temp == None:
                if re.match("IF@@@",t):
                    t = t[8:]
                elif re.match("EI@@@",t):
                    t = t[12:]
                else:
                    t = t[:-1]
                ret.append(t.replace(' ',''))
            else:
                for tp in temp: ret.append(tp)
        if ret != []:
            return ret
    elif '==' in line:
        return []
    else:
        return None





    # ret = None
    # while re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+<=[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line) or
    #       re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+>=[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line) or
    #       re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+<[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line) or
    #       re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+<[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line) or
    #       '!=' in line or
    #       '==' not in line :

    #     if re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+<=[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line):
    #         line = line.replace(' \t','')
    #         term = line.split('<=')
    #         for t in term:
    #             temp = ExtractVarUsedInNotEqualCondition(t)
    #             if temp == None:




        # elif  re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+>=[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line) or
        # elif  re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+<[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line) or
        # elif  re.search('[(\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t)|\->]+<[\(\)a-zA-Z0-9_\+\-\*\/&\|\[\]\., \t]+',line) or

# ##############################

# 関数名: JokenifComparator
# 機能: dividerによって抽出した変数が状態変数候補の条件を満たすか調べる．
# 引数
#   instring: 解析中の行の文字列．

# ##############################

def JokenifComparator(instring):
#    print('==================')
#    print('JC')

    if "@@@" not in instring:
        return "",""
    # print(instring)
    vars = divider(instring)
    # print(vars)
    result = [""]
    vars = vars.split("\t")
    for var in vars:
        if re.match("IF@@@",var):
            var = var[8:]
        elif re.match("EI@@@",var):
            var = var[12:]
        elif re.match("EL@@@",var):
            break
        if re.search("[a-zA-Z0-9 ]\($",var):  #関数が引数の場合、スキップ
            continue
        var = var.replace("(","")
        var = var.replace(")","")
        if re.match("[0-9]+",var) or \
           re.match("0x[0-9]+",var):
            continue
        result.append(var)
    i = 0
    while [''] in result:
        result.remove([''])
    result = list(set(result))
    deletetarget=ExtractVarUsedInNotEqualCondition(instring)
    return result, deletetarget

# ##############################

# 関数名: ShoriifComparator
# 機能: dividerによって抽出した変数が状態変数候補の条件を満たすか調べる．
# 引数
#   instring: 解析中の行の文字列．

# ##############################

def ShoriifComparator(instring):
    result = [""]
    vars = divider(instring)
    if "=" not in vars:
        return("")
    vars = vars.split("=")
    if re.match("\(?0x[0-9A-Fa-f]+\)?",vars[0]) or \
       re.match("\(?[0-9]+\)?",vars[0]):
           return([""])
    vars[0] = re.sub("\+|\-|\*|\/","",vars[0])
    if vars[0] == None:
        vars[0] = ""
    return(vars[0])

# ##############################

# 関数名: jotaivar
# 機能: pragma.pyで出力された解析済みCファイルから状態変数候補の変数を探し，
#	変数名のリストを出力する．
# 引数
#   readFile:解析済みCファイル

# ##############################

def jotaivar(readFile):
    param = sys.argv[1:]
#    print('RF', readFile)
    fi = open(readFile)
    lines = fi.read()
    fi.close()
    # print('#',readFile)

    lines = lines.replace("\n","")
    lines = lines.replace("\t","")
    lines = lines.replace(";",";\n")
    lines = lines.replace("{","\n{\n")
    lines = lines.replace("}","\n}\n")
    while "\n\n" in lines:
        lines = lines.replace("\n\n","\n")
    lines = lines.split("\n")

    i = 0
    for line in lines:
        if re.match("for[ \t]*\(", line):
            while re.search( "\)[ \t]*;$",lines[i]) == None and re.search( "\)H###$",lines[i]) == None:
                lines[i] = lines[i].replace("\n","")
                lines[i] = lines[i]+lines[i+1]
                del lines[i+1]
        elif re.match("for[ \t]*\(", line):
            while re.search( "\)[ \t]*;$",lines[i]) == None and re.search( "\)H###$",lines[i]) == None:
                lines[i] = lines[i].replace("\n","")
                lines[i] = lines[i]+lines[i+1]
                del lines[i+1]
        # delete type check (without init val);
        if re.search("[ \t]*[(unsigned)|(static)|(volatile)]+[ \t]+[A-Za-z_][A-Za-z0-9_]*[ \t]+[A-Za-z_][A-Za-z0-9_]*[ \t];", line):
            if re.search("$[ \t]*unsigned ", line):
                line = line.replace('unsigned ','')
            if re.search("$[ \t]*static ", line):
                line = line.replace('static ','')
            if re.search("$[ \t]*volatile ", line):
                line = line.replace('volatile ','')

        # delete type check (with init val);
        elif re.search("[ \t]*[(unsigned)|(static)|(volatile)]+[ \t]+[A-Za-z_][A-Za-z0-9_]*[ \t]+[A-Za-z_][A-Za-z0-9_]*[ \t]*=[ \t]*[A-Za-z0-9_]+;", line):
            if re.search("$[ \t]*unsigned ", line):
                line = line.replace('unsigned ','')
            if re.search("$[ \t]*static ", line):
                line = line.replace('static ','')
            if re.search("$[ \t]*volatile ", line):
                line = line.replace('volatile ','')
        lines[i] = lines[i].replace(' ','')
        i += 1

    rfile = "lists/deletefunctions.txt"
    fi = open(rfile)
    flists = fi.readlines()
    fi.close()

    ### 削除する関数名を取得し正規表現検索のための準備

    for i, f in enumerate(flists):
        flists[i] = f.replace("\n","")
        flists[i] = "[ \\t]*"+flists[i]+"\\("
        # print('!',flists[i])
        i += 1

    joken = [""]
    shori = [""]
    delvar = [""]

    ### 状態変数の取得
    for line in lines:
#        print(line,end="")
        ### 余分な空白文字を削除
        line = line.replace(" ","")
        line = line.replace("\t","")
        line = line.replace("\n","")
        conflg = False

        ### 削除対象関数を含んでいるか
        for f in flists:
            if re.search(f,line):
                conflg = True
                break

        ### 読み飛ばしの判定
        if line == "{" \
           or line == "}" \
           or conflg == True \
           or re.search("%%%MJK%%%",line) \
           or re.search("[A-Za-z_]+[A-Za-z0-9_]*\([0-9]*\)",line) \
           or re.search("FC@@@",line):
           continue
        #print(line,end='')
        ### 式の分離
        # line = 'IF@@@if(g_TotalNumber >= (9999))'
        temp =['']
        temp, deletetarget = JokenifComparator(line)
        for t in temp: joken.append(t)
        delvar.append(deletetarget)

        shori.append(ShoriifComparator(line))
        joken = list(set(flatten(joken)))
        shori = list(set(shori))
        delvar = list(set(flatten(delvar)))
    jokenset = set(joken)
    shoriset = set(shori)
    jokenset.remove('')
    shoriset.remove('')

    formula = [""]

    for j in jokenset:
        temp = re.sub("\+|\-|\*|\/","\t",j)

        if "\t" in temp:
            temp = temp.split("\t")
            for t in temp:
                if t in shoriset:
                    formula.append(j)
                    break


    fi = open("temp/globalvar.tsv","r")
    lines = fi.read().split("\n")
    fi.close()

    fi = open("temp/idlist2.tsv","r")
    lines2 = fi.readlines()
    fi.close()


    fo = open("temp/jotaivarlist.tsv","w")

    # print('j:',jokenset)
    # print('s:',shoriset)


    formula = set(formula)
    setofvars = jokenset & shoriset
    setofvars = setofvars | formula

    for dv in delvar:
        if dv in setofvars:
            setofvars.remove(dv)

    setofvars.discard("")

    # print('sov:',setofvars)

    #print ("jokenset",jokenset)
    #print ("shoriset",shoriset)
    #print ("setofvars",setofvars)
    for r in setofvars:
        if r in lines:
            print(r + "\t" + "GLOBAL",file=fo)
        else:
            funcs = []
            for i,line2 in enumerate(lines2):
                if r in line2:
                    lines3 = lines2[:i]
                    lines3.reverse()
                    for line3 in lines3:
                        line3 = line3[:-1]
                        row3 = line3.split("\t")
                        nest = row3[2]
                        if nest == "0":
                            if row3[1] not in funcs:
                                print(r + "\t" + row3[1],file=fo)
                                funcs.append(row3[1])
                            break

    fo.close()

if __name__ == '__main__':
    jotaivar(sys.argv[1])
