Add function dectection, for detection, comments detection, typedef, struct, enum, union detection, global variable detection, prototype detection

Checks variables alignement in struct and union
Checks typedef names
Checks line number in functions
Checks ; before and after spaces
Starting check for for instruction
Fix check alignement of macros
Fix line number
Fix tabulation alignment
This commit is contained in:
Némunaire 2011-11-02 03:58:52 +01:00
parent 98095ca4ed
commit e83d2e5efc

491
c.py
View File

@ -21,21 +21,23 @@ def validatePreprocDirective(path, content, start, start_lign, states):
lign = start_lign lign = start_lign
current = start current = start
contentSize = len(content) contentSize = len(content)
cOnLine = 1 cOnLine = 0
eolAlign = -1 #Alignement de la fin de ligne eolAlign = -1 #Alignement de la fin de ligne
state = 0 state = 0
directive = "" #The name of the directive directive = "" #The name of the directive
content = "" #The rest of the line restol = "" #The rest of the line
ident = 0; ident = 0;
while current < contentSize and (content[current] != '\n' or content[current - 1] == '\\'): while current < contentSize and (content[current] != '\n' or content[current - 1] == '\\'):
current += 1 current += 1
if content[current] == '\n' and content[current - 1] == '\\': if content[current] == '\n' and content[current - 1] == '\\':
print "new line"
lign += 1 lign += 1
cOnLine = 0 cOnLine = -1
if content[current - 1] == '\t': if content[current - 1] == '\t':
cOnLine += 7 if cOnLine % 8 == 0:
cOnLine += 8 + 1
else: else:
cOnLine += cOnLine % 8 + 1
elif content[current] != '\n':
cOnLine += 1 cOnLine += 1
#Check indentation #Check indentation
@ -46,12 +48,10 @@ def validatePreprocDirective(path, content, start, start_lign, states):
#Wrap #Wrap
if content[current] == '\\': if content[current] == '\\':
print '\\'
if eolAlign <= 0: if eolAlign <= 0:
eolAlign = cOnLine eolAlign = cOnLine
elif cOnLine != eolAlign: elif cOnLine != eolAlign:
perr(path, "Bad endline", lign) perr(path, "Bad endline preprocessor alignement (expected: {0}, real: {1})".format(eolAlign, cOnLine), lign)
print '\\'
#Spaces state #Spaces state
if state == 2 or state == 4: if state == 2 or state == 4:
@ -77,6 +77,459 @@ def validatePreprocDirective(path, content, start, start_lign, states):
eaten = { 'chars': current - start - 1, 'lines': lign, 'col': cOnLine } eaten = { 'chars': current - start - 1, 'lines': lign, 'col': cOnLine }
return eaten return eaten
def validateType(path, content, current, lign, states):
content += " " #Add a sentinel
contentSize = len(content)
state = 0
while current + 1 < contentSize:
if content[current] == '*' and content[current - 1] != ' ':
perr(path, "No space before *", lign)
elif content[current] == '=' and content[current - 1] != ' ':
perr(path, "No space before =", lign)
elif content[current] == '=' and content[current + 1] != ' ':
perr(path, "No space after =", lign)
elif content[current] == '=':
state = 1
elif state == 1:
if content[current] == '*' and content[current + 1] != ' ':
perr(path, "No space after *", lign)
elif content[current] == '+' and content[current + 1] != ' ':
perr(path, "No space after +", lign)
elif content[current] == '+' and content[current - 1] != ' ':
perr(path, "No space before +", lign)
elif content[current] == '-' and content[current + 1] != ' ':
perr(path, "No space before -", lign)
elif content[current] == '-' and content[current - 1] != ' ':
perr(path, "No space before -", lign)
elif content[current] == '/' and content[current + 1] != ' ':
perr(path, "No space before /", lign)
elif content[current] == '/' and content[current - 1] != ' ':
perr(path, "No space before /", lign)
elif content[current] == '%' and content[current + 1] != ' ':
perr(path, "No space before %", lign)
elif content[current] == '%' and content[current - 1] != ' ':
perr(path, "No space before %", lign)
elif content[current] == '(' and content[current - 1] != ' ':
perr(path, "Warning: it seems there is a function calling with a declaration", lign)
current += 1
def validateStruct(path, content, start, start_lign, states):
lign = start_lign
current = start
contentSize = len(content)
cOnLine = 0
varAlign = -1
state = 0
lastBlank = 0
typeName = ""
strEc = ""
while current < contentSize and content[current] != '}':
if content[current] == ' ' and content[current + 1] != ';':
typeName += strEc + ' '
strEc = ""
else:
strEc += content[current]
#Search the struct begining
if state == 0:
if content[current] == '{':
state = 1
cOnLine = 0
strEc = ""
typeName = ""
if state == 1:
if content[current] == ' ' or content[current] == '\t':
lastBlank = cOnLine
elif content[current] == '\n' and lastBlank != 0:
#Check type
validateType(path, typeName.strip().rstrip(), 0, start_lign, states)
strEc = ""
typeName = ""
#Check variable alignment
if varAlign == -1:
varAlign = lastBlank
elif lastBlank != varAlign:
perr(path, "Bad variable alignement in a struct (expected: {0}, real: {1})".format(varAlign, lastBlank), lign)
elif content[current] == ',':
perr(path, "Two variable declarations aren't allowed on the same line", lign)
elif content[current] == ';' and content[current - 1] == ' ':
perr(path, "There are a space before ;", lign)
if content[current] == '\n':
lign += 1
cOnLine = -1
lastBlank = 0
current += 1
if content[current - 1] == '\t':
if cOnLine % 8 == 0:
cOnLine += 9
else:
cOnLine += cOnLine % 8 + 1
else:
cOnLine += 1
while current < contentSize and content[current] != ';':
cOnLine += 1
current += 1
if content[current] == ';' and content[current - 1] == ' ':
perr(path, "There is a space before ;", lign)
eaten = { 'chars': current - start - 1, 'lines': lign, 'col': cOnLine }
return eaten
def validateUnion(path, content, start, start_lign, states):
lign = start_lign
current = start
contentSize = len(content)
cOnLine = 0
varAlign = -1
state = 0
lastBlank = 0
typeName = ""
strEc = ""
while current < contentSize and content[current] != '}':
if content[current] == ' ' and content[current + 1] != ';':
typeName += strEc + ' '
strEc = ""
else:
strEc += content[current]
#Search the union begining
if state == 0:
if content[current] == '{':
state = 1
cOnLine = 0
strEc = ""
typeName = ""
if state == 1:
if content[current] == ' ' or content[current] == '\t':
lastBlank = cOnLine
elif content[current] == '\n' and lastBlank != 0:
#Check type
validateType(path, typeName.strip().rstrip(), 0, start_lign, states)
strEc = ""
typeName = ""
#Check variable alignment
if varAlign == -1:
varAlign = lastBlank
elif lastBlank != varAlign:
perr(path, "Bad variable alignement in an union (expected: {0}, real: {1})".format(varAlign, lastBlank), lign)
elif content[current] == ',':
perr(path, "Two variable declarations aren't allowed on the same line", lign)
elif content[current] == ';' and content[current - 1] == ' ':
perr(path, "There is a space before ;", lign)
if content[current] == '\n':
lign += 1
cOnLine = -1
lastBlank = 0
current += 1
if content[current - 1] == '\t':
if cOnLine % 8 == 0:
cOnLine += 9
else:
cOnLine += cOnLine % 8 + 1
else:
cOnLine += 1
while current < contentSize and content[current] != ';':
cOnLine += 1
current += 1
if content[current] == ';' and content[current - 1] == ' ':
perr(path, "There is a space before ;", lign)
eaten = { 'chars': current - start - 1, 'lines': lign, 'col': cOnLine }
return eaten
def validateEnum(path, content, start, start_lign, states):
lign = start_lign
current = start
contentSize = len(content)
cOnLine = 0
varAlign = -1
state = 0
while current < contentSize and content[current] != '}':
#Search the enum begining
if state == 0:
if content[current] == '{':
state = 1
cOnLine = 0
if state == 1:
if content[current] == '=' and content[current + 1] != ' ':
perr(path, "Missing space after =", lign)
if content[current] == '=' and content[current - 1] != ' ':
perr(path, "Missing space before =", lign)
if content[current] == ',' and content[current + 1] != '\n':
perr(path, "Two statements on the same line", lign)
if content[current] == '\n':
lign += 1
cOnLine = -1
if content[current - 1] == '\t':
if cOnLine % 8 == 0:
cOnLine += 9
else:
cOnLine += cOnLine % 8 + 1
else:
cOnLine += 1
current += 1
while current < contentSize and content[current] != ';':
cOnLine += 1
current += 1
if content[current] == ';' and content[current - 1] == ' ':
perr(path, "There is a space before ;", lign)
eaten = { 'chars': current - start - 1, 'lines': lign, 'col': cOnLine }
return eaten
def validateTypedef(path, content, start, start_lign, states):
lign = start_lign
current = start
contentSize = len(content)
cOnLine = 0
newname = "" #The name of the typedef
restol = "" #The rest of the line
state = 0
while current < contentSize and (content[current] != ';' or state > 0):
current += 1
if content[current] == '\n':
lign += 1
cOnLine = -1
if content[current - 1] == '\t':
if cOnLine % 8 == 0:
cOnLine += 9
else:
cOnLine += cOnLine % 8 + 1
else:
cOnLine += 1
if content[current] == '{':
state += 1
elif content[current] == '}':
state -= 1
if content[current] == ' ' and content[current + 1] != ';':
restol += newname + ' '
newname = ""
else:
newname += content[current]
if content[current - 1] == ' ' and content[current] == ';':
perr(path, "There is a space before ;", lign)
restol = restol.strip().rstrip();
if restol.find("struct") == 0:
validateStruct(path, restol + ";", 0, start_lign, states)
if newname[0] != 's' or newname[1] != '_':
perr(path, "Bad typedef name for a struct (expected: s_; real: {0}{1})".format(newname[0], newname[1]), lign)
elif restol.find("union") == 0:
validateUnion(path, restol + ";", 0, start_lign, states)
if newname[0] != 'u' or newname[1] != '_':
perr(path, "Bad typedef name for an union (expected: u_; real: {0}{1})".format(newname[0], newname[1]), lign)
elif restol.find("enum") == 0:
validateEnum(path, restol + ";", 0, start_lign, states)
if newname[0] != 'e' or newname[1] != '_':
perr(path, "Bad typedef name for an enum (expected: e_; real: {0}{1})".format(newname[0], newname[1]), lign)
else:
validateType(path, restol, 0, start_lign, states)
if newname[0] != 't' or newname[1] != '_':
perr(path, "Bad typedef name (expected: t_; real: {0}{1})".format(newname[0], newname[1]), lign)
eaten = { 'chars': current - start - 1, 'lines': lign, 'col': cOnLine }
return eaten
def validateFor(path, content, start, start_lign, states):
lign = start_lign
current = start
contentSize = len(content)
cOnLine = 0
stack = -1
while current < contentSize and (content[current] != ')' or stack >= 0):
current += 1
if content[current] == '\n':
lign += 1
cOnLine = -1
if content[current - 1] == '\t':
if cOnLine % 8 == 0:
cOnLine += 9
else:
cOnLine += cOnLine % 8 + 1
elif content[current] != '\n':
cOnLine += 1
if content[current] == ';':
if content[current - 1] == ' ' and content[current - 2] != ';':
perr(path, "There is a space before ;", lign)
if content[current + 1] != ' ':
perr(path, "There is no space after ;", lign)
if content[current] == '(':
stack += 1
elif content[current] == ')':
stack -= 1
if content[current] == ')':
if content[current - 1] == ' ' and content[current - 2] != ';':
perr(path, "There is a space before )", lign)
if content[current - 1] == ';':
perr(path, "There is no space before ), expected one in this case", lign)
eaten = { 'chars': current - start + 1, 'lines': lign, 'col': cOnLine }
return eaten
def validateComment(path, content, start, start_lign, states):
lign = start_lign
current = start
contentSize = len(content)
while current + 1 < contentSize and content[current] != '*' and content[current + 1] != '/':
current += 1
eaten = { 'chars': current - start - 1, 'lines': lign }
return eaten
def validateFunction(path, content, start, start_lign, states, prototype):
lign = start_lign
nbLign = 0
current = start
contentSize = len(content)
cOnLine = 0
stack = 0
while current < contentSize and (content[current] != '}' or stack >= 0):
current += 1
if content[current] == '\n':
if cOnLine > 0:
nbLign += 1
lign += 1
cOnLine = -1
if content[current - 1] == '\t':
if cOnLine % 8 == 0:
cOnLine += 9
else:
cOnLine += cOnLine % 8 + 1
elif content[current] != '\n':
cOnLine += 1
if content[current - 2] == 'f' and content[current - 1] == 'o' and content[current] == 'r':
eaten = validateFor(path, content, current, lign, states)
cOnLine = eaten['col'];
current += eaten['chars'];
lign = eaten['lines'];
if content[current - 1] == ';' and content[current] != '\n':
perr(path, "There is a ; without new line after", lign)
if content[current] == '{':
stack += 1
elif content[current] == '}':
stack -= 1
#Skip lines containing comments in the count
if content[current] == "/" == content[current - 1]:
nbLign -= 1
elif content[current] == "/" and content[current - 1] == "*":
eaten = validateComment(path, content, current, lign, states)
current += eaten['chars']
lign += eaten['lines']
if nbLign > 25:
perr(path, "To many line in this function: {0}".format(nbLign), start_lign)
#else:
# perr(path, "This function is a {0} lines function, good :)".format(nbLign), start_lign)
eaten = { 'chars': current - start - 1, 'lines': lign, 'col': cOnLine }
return eaten
def validateVarOrProto(path, content, start, start_lign, states):
return 1
def validateFunOrGlobal(path, content, start, start_lign, states):
lign = start_lign
current = start
contentSize = len(content)
cOnLine = 0
restol = "" #The rest of the line
while current < contentSize and content[current] != ';' and content[current] != '{':
current += 1
if content[current] == '\n':
lign += 1
cOnLine = -1
if content[current - 1] == '\t':
if cOnLine % 8 == 0:
cOnLine += 9
else:
cOnLine += cOnLine % 8 + 1
elif content[current] != '\n':
cOnLine += 1
if content[current] != '\n':
restol += content[current]
if content[current] == '{':
eaten = validateFunction(path, content, current, lign, states, restol)
current += eaten['chars']
cOnLine = eaten['col']
lign = eaten['lines']
else:
eaten = validateVarOrProto(path, content, current, lign, states)
eaten = { 'chars': current - start, 'lines': lign, 'col': cOnLine }
return eaten
def validateExternalWord(path, content, start, start_lign, states):
lign = start_lign
current = start
contentSize = len(content)
cOnLine = 0
directive = "" #The name of the directive
while current < contentSize and content[current] != '\n':
#Search keyword
if content[current] != ' ' and content[current] != '\t':
directive += content[current]
else:
if directive == "typedef":
eaten = validateTypedef(path, content, current, lign, states)
elif directive == "struct":
eaten = validateStruct(path, content, current, lign, states)
elif directive == "enum":
eaten = validateEnum(path, content, current, lign, states)
elif directive == "union":
eaten = validateUnion(path, content, current, lign, states)
else:
eaten = validateFunOrGlobal(path, content, current, lign, states)
current += eaten['chars']
cOnLine = eaten['col']
lign = eaten['lines']
current += 1
if content[current - 1] == '\t':
if cOnLine % 8 == 0:
cOnLine += 9
else:
cOnLine += cOnLine % 8 + 1
else:
cOnLine += 1
eaten = { 'chars': current - start - 1, 'lines': lign, 'col': cOnLine }
return eaten
def checkFile(path, opt): def checkFile(path, opt):
numLign = 1 numLign = 1
with open(path, "r") as fp: with open(path, "r") as fp:
@ -101,23 +554,37 @@ def checkFile(path, opt):
perr(path, "Preprocessor directive mark not on the first column", numLign) perr(path, "Preprocessor directive mark not on the first column", numLign)
eaten = validatePreprocDirective(path, content, current, numLign, states) eaten = validatePreprocDirective(path, content, current, numLign, states)
current += eaten['chars'] current += eaten['chars']
cOnLine += eaten['col'] cOnLine = eaten['col']
numLign = eaten['lines'] numLign = eaten['lines']
#String #String
elif content[current] == '"': elif content[current] == '"':
print "str"
eatenChar = validateString(path, content, current, numLign) eatenChar = validateString(path, content, current, numLign)
current += eatenChar current += eatenChar
cOnLine += eatenChar cOnLine += eatenChar
#Comments
elif content[current] == '*' and content[current - 1] == '/':
eaten = validateComment(path, content, current, numLign, states)
current += eaten['chars']
cOnLine = 0
numLign = eaten['lines']
#Skip empty lines
elif content[current] != '\n':
eaten = validateExternalWord(path, content, current, numLign, states)
current += eaten['chars']
cOnLine = eaten['col']
numLign = eaten['lines']
if last_nblank == cOnLine and content[current] == ' ' or content[current] == '\t': if last_nblank == cOnLine and content[current] == ' ' or content[current] == '\t':
last_nblank += 1 last_nblank += 1
current += 1 current += 1
cOnLine += 1 cOnLine += 1
print("Ce fichier contient {0} lignes".format(numLign + 1)) #print("Ce fichier contient {0} lignes".format(numLign))
import sys #import sys
checkFile(sys.argv[1], dict()) #checkFile(sys.argv[1], dict())