diff options
Diffstat (limited to 'ebuildgen/filetypes/automake.py')
-rw-r--r-- | ebuildgen/filetypes/automake.py | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/ebuildgen/filetypes/automake.py b/ebuildgen/filetypes/automake.py new file mode 100644 index 0000000..c4ca432 --- /dev/null +++ b/ebuildgen/filetypes/automake.py @@ -0,0 +1,342 @@ +from ply import lex +from ply import yacc +import glob +import os + +def scanamfile(amfile): + """Scan automake (.am) file + + Returns ... + """ + amfile = "\n" + amfile #Add \n so you can guess vars + tokens = ( + "END", + "COL", + "EQ", + "PEQ", + "CVAR", + "MVAR", + "TEXT", + "ENDTAB", + "SPACE", + "IF", + "ELSE", + "ENDIF", + ) + + states = ( + ("com", "exclusive"), #comment + ("var", "inclusive"), + ("if", "exclusive"), + ) + + def t_begin_com(t): + r"[ \t]*\#" + t.lexer.begin("com") + + def t_com_other(t): + r"[^\\\n]+" + pass + + def t_com_lit(t): + r"\\." + pass + + def t_com_newline(t): + r".*\\\n" + t.lexer.lineno += 1 + pass + + def t_ifbegin(t): + #ugly hack to ensure that this is at the begining of the line and keep the newline token. + #PLY doesn't support the "^" beginning of line regexp :,( + r"\nif" + t.type = "END" + t.lexer.push_state("if") + return t + + def t_if_IF(t): + #http://www.gnu.org/s/hello/manual/automake/Usage-of-Conditionals.html#Usage-of-Conditionals + r"[ \t]+[^ \n\t]*" + t.value = t.value.strip() #take the variable to test + t.lexer.pop_state() + return t + + def t_ELSE(t): + r"\nelse" + return t + + def t_ENDIF(t): + r"\nendif" + return t + + def t_CVAR(t): #configure variable + r"@.*?@" #not greedy + return t + + def t_MVAR(t): #makefile variable + r"\$\(.*?\)" + return t + + def t_com_END(t): + r"\n" + t.lexer.begin("INITIAL") + t.lexer.lineno += 1 + return t + + def t_EQ(t): + r"[ \t]*=[ \t]*" + t.lexer.begin("var") + t.value = t.value.strip() + return t + + def t_PEQ(t): + r"[ \t]*\+=[ \t]*" + t.lexer.begin("var") + t.value = t.value.strip() + return t + + def t_contline(t): + r"\\\n" + t.lexer.lineno += 1 + pass + + def t_litteral(t): + r"\\." + t.value = t.value[1] #take the literal char + t.type = "TEXT" + return t + + def t_COL(t): + r"[ \t]*:[ \t]*" + t.lexer.begin("var") + return t + + def t_var_ENDTAB(t): + r"[ \t]*;[ \t]*" + return t + + def t_ENDTAB(t): + r"[ \t]*\n\t[ \t]*" + t.lexer.lineno += 1 + return t + + def t_var_TEXT(t): + r"[^ #\n\t,\$@\\]+" + return t + + def t_TEXT(t): + r"[^ \n\t:=\$@\\]+" + return t + + def t_END(t): + r"[ \t]*\n" + t.lexer.lineno += t.value.count('\n') + t.lexer.begin('INITIAL') + return t + + def t_var_SPACE(t): + r"[ \t]+" + return t + + def t_space(t): + r"[ \t]" + pass + + def t_var_special(t): + r"\$[^({]" + t.type = "TEXT" + return t + + def t_ANY_error(t): + print("Illegal character '%s'" % t.value[0]) + t.lexer.skip(1) + + lexer = lex.lex() + + #lexer.input(amfile) + #for tok in lexer: + # print(tok) + + #YACC stuff begins here + + def p_done(p): + "done : vars end" + p[0] = p[1] + + def p_vars(p): + """ + vars : vars end var + | end var + """ + if len(p) == 4: + p[1][0].update(p[3][0]) + p[1][2].update(p[3][2]) + p[0] = [p[1][0], p[1][1] + p[3][1], p[1][2]] + + else: + p[0] = p[2] + + def p_if(p): + """ + var : IF vars ENDIF + | IF vars ELSE vars ENDIF + """ + if len(p) == 4: + p[0] = [{},[],{p[1]:p[2]}] + + else: + p[0] = [{},[],{p[1]:p[2],"!"+p[1]:p[4]}] + + def p_var(p): + """ + var : textstr EQ textlst + | textstr EQ + | textstr PEQ textlst + """ + if p[2] == "=": + if len(p) == 4: + p[0] = [{p[1]: p[3]},[],{}] + else: + p[0] = [{p[1]: []},[],{}] + else: + p[0] = [{},[[p[1], p[3]]],{}] + + def p_textlst(p): + """ + textlst : textlst spacestr textstr + | textstr + """ + if len(p) == 4: + p[0] = p[1] + [p[3]] + else: + p[0] = [p[1]] + + def p_teststr(p): + """ + textstr : textstr TEXT + | textstr CVAR + | textstr MVAR + | TEXT + | CVAR + | MVAR + """ + if len(p) == 3: + p[0] = p[1] + p[2] + else: + p[0] = p[1] + + def p_space(p): + """ + spacestr : spacestr SPACE + | SPACE + """ + if len(p) == 3: + p[0] = p[1] + p[2] + else: + p[0] = p[1] + + def p_end(p): + """ + end : end END + | END + """ + + def p_error(p): + print("syntax error at '%s'" % p.type,p.value) + pass + + yacc.yacc() + + variables = yacc.parse(amfile) + return variables + +def initscan(amfile,iflst): + useflag_sources = {} #{source: [useflag, value]} + incflag_sources = {} #{source: [include flags]} + top_dir = os.path.split(amfile)[0] + "/" + + def scan(amfile): + curdir = os.path.split(amfile)[0] + "/" + amlist = scanamfile(openfile(amfile)) + #print(amfile) + + def sources_to_scan(amlist,curdir): + incflags = [] + sources = [] + extra_sources = [] + #perhaps use set() here to eliminate the possibilty of duplicates? + for variable in amlist[0]: + if variable.split("_")[-1] == "SOURCES": + if variable.split("_")[0] == "EXTRA": + extra_sources += amlist[0][variable] + else: + sources += amlist[0][variable] + + if variable.split("_")[-1] == "LDADD": + for item in amlist[0][variable]: + if item[0] == "@" and item[-1] == "@": + for ifstate in iflst: + if item.strip("@") in ifstate[1]: + for file in ifstate[1][item.strip("@")]: + for src in extra_sources: + if file.split(".")[0] == src.split(".")[0]: + useflag_sources[curdir + src] = ifstate[0] + incflag_sources[curdir + src] = incflags + + for src in extra_sources: + if item.split(".")[0] == src.split(".")[0]: + sources += [src] + + if variable.split("_")[-1] == "CFLAGS" or variable == "DEFAULT_INCLUDES": + for item in amlist[0][variable]: + if item[:2] == "-I": + if item[2:] == "$(top_srcdir)" or item[2:] == "$(srcdir)": + incflags += [top_dir] + elif item[2] == "/": + incflags += [item[2:]] + else: + incflags += [curdir + item[2:]] + + if not "DEFAULT_INCLUDES" in amlist[0]: + incflags += [curdir,top_dir] + + if "SUBDIRS" in amlist[0]: + for dir in amlist[0]["SUBDIRS"]: + sources += scan(curdir + dir + "/Makefile.am") + + for lst in amlist[1]: + if lst[0] == "SUBDIRS": + for dir in lst[1]: + sources += scan(curdir + dir + "/Makefile.am") + + for ifstatement in amlist[2]: + #print(ifstatement) + for item in iflst: + if ifstatement.lstrip("!") in item[1]: + if ifstatement[0] == "!": + if item[1][ifstatement.lstrip("!")] == "false": + for src in sources_to_scan(amlist[2][ifstatement],curdir): + useflag_sources[src] = item[0] + + elif item[1][ifstatement] == "true": + for src in sources_to_scan(amlist[2][ifstatement],curdir): + useflag_sources[src] = item[0] + + #add filepath + dirsources = [] + for source in sources: + if os.path.split(source)[0] == "": + dirsources += [curdir + source] + incflag_sources[curdir + source] = incflags + else: + dirsources += [source] + + return dirsources + + return sources_to_scan(amlist,curdir) + return scan(amfile),useflag_sources,incflag_sources + +def openfile(ofile): + with open(ofile, encoding="utf-8", errors="replace") as inputfile: + return inputfile.read() |