The Link Your Class | https://bbs.csdn.net/forums/MUEE308FZ?category=0 |
---|---|
The Link of Requirement of This Assignment | https://bbs.csdn.net/topics/600798588 |
The Aim of This Assignment | Code individually & learn how to use git and submit codes & learn how to use unit test and performance test & extract keywords of different levels from the C or C++ code files that are read in. |
MU STU ID and FZU STU ID | 19104553 and 831902205 |
You can visit my github website: My github website
Directory
Design and Implementation Process
Coverage Optimization and Performance Testing
PSP Form
Personal Software Process Stages | Estimated Time/minutes | Completed Time/minutes |
---|---|---|
Planning | 30 | 30 |
Estimate | 15 | 15 |
Development | - | - |
Analysis | 120 | 210 |
Design Spec | 60 | 60 |
Design Review | 30 | 30 |
Coding Standard | 10 | 10 |
Design | 100 | 200 |
Coding | 600 | 900 |
Code ReviewPlanning | 60 | 45 |
Test | 120 | 150 |
Reporting | - | - |
Test Report | - | - |
Size Measurement | 10 | 10 |
Postmortem&Process Improvement | 120 | 150 |
total | 1275 | 1810 |
Preparation
I have learned the basic grammar of Java, C++ and Python. According to this lab
's requirements, I decide to use Python.
According to other blogs, I learned how to use github and git to submit my files to the repository on Github for the first time. I submitted my first file to Github by using remote clone repositories.
Since I have no idea what coding styles I can use, I revise my coding styles depending on the content of this website: PEP8 and the code specification is Code Specification
Because I have been learning Python for less than one months, I need to search for the corresponding functions of Python on the Internet which takes me a lot of time. For instance, I don't know how to achieve the implement of stack in Python, so I browsed the Internet for a long time, just like the image below:
What a hard work it was!
Problem-solving Ideas
According to the requirements of this lab, I seperate the code into two steps.
- Process the data
- Achieve the requirements of this lab step by step
So the main purpose of the first step is to eliminate the effect of the comment. I decide to use the regular expression to solve the problem. The regular expression can match not only the complete English word, but also the unnecessary comments and words.
The needed regular expressiong is shown below:
- Comment: r"(\/\*([^\*^\/]*|[\*^\/*]*|[^\**\/]*)*\*\/|\/\/.*|'.*'|\"([^\"]*)\")"
- English Word: r'\b[a-zA-Z]+\b'
- else if: r"\be.*?f\b"
Based on these expressions, I can identify the comments and the English words. After reading and processing the data, I can proceed the second step.
And the second step can be divided into three little steps according to the requirements. Before every little steps, the data must be processed again using regular expressions.
- Use regular expressions to identify the words from other symbols, count the number of every words and add the number together, then get the final result.
- Just like the first little step, the English words are identified. So how to count the number of keyword "switch" ? I think the "switch" can only be counted after the next "switch" appears. And the cases of one "switch" can be counted between two "switch" by using a flag to indicate whether the process is between two "switch".
- So how to count the number of if, else and if-elseif-else? The first thing is to eliminate the space of "else if" between "else" and "if". And then we continue to do the real operations. I think the stack can be used. Once a "if" has been identified, this "if" will be pushed into "stack". And the size of stack will be checked. If the size is bigger than one, the program will go the next judge. If we encounter a "elseif" and the last value of the stack is "if", this "elseif" will be pushed into this stack too. If we encounter a "else", then we will check the last value of stack. If the last value is "if", then we can conclude that it is a "if-else" structure. Otherwise, we will pop the stack and calculate the number of "if-else-if".
Design and Implementation Process
Code Description
- Stack. Since I decide to use stack in the function "countIfElseIf", I write a stack class by hand by referencing other's blogs.
class Stack(object):
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
def value(self,num):
return self.items[num]
- Read the file. Because I am not very familiar with the way of reading in a file, I search on the Internet and I found the function "open" and it can detect whether this file is c or c++.
result = []
if file_name.endswith('.cpp') or file_name.endswith('.c'):
fr = open(file_name, 'r')
for line in fr:
result.append(line)
fr.close()
text = "".join(result)
And then the comment should be replaced with ' '.
reg = r"(\/\*([^\*^\/]*|[\*^\/*]*|[^\**\/]*)*\*\/|\/\/.*|'.*'|\"([^\"]*)\")" #Replace the comment
com = re.finditer(reg,text)
for key in com:
text = text.replace(key.group(),' ')
- Count the number of keywords.AS mentioned above, the English words can be identified using regular expression.
reg = r'\b[a-zA-Z]+\b'
line = re.findall(reg, text)
res = {}
for word in kwList:
num = line.count(word)
if num != 0:
res[word] = num
items = list(res.items())
sum = 0
for i in range(len(items)):
kw, num = items[i]
# print(kw, 'num : ', num)
sum += num
- Count the number of "switch" and corresponding cases. The first idea is to use default, which ends the match. On second thought, not every switch has a default. So I think the "switch" can only be counted after the next "switch" appears. And the nested "switch" should not be considered according to TA.
def countSwitch(text):
reg = r'\b[a-zA-Z]+\b'
line = re.findall(reg, text)
switch_num = 0
flag = 0
case_num = []
if line.count('switch') == 0:
print("There is no switch keyword in the keywords list")
return 0
for kw in line:
if kw == 'switch':
switch_num += 1
flag = 1
case_num.append(0)
if flag == 1 and kw == 'case':
case_num[switch_num-1] += 1
print("switch num: ", switch_num)
for i in range(len(case_num)):
print("Case num for No.{} switch: {}".format(i+1, case_num[i]))
- Count the number of "if-else" and "if-elseif-else". Since there exists a space in "else if" between "else" and "if", I use a function to replace " " with '' based on the regular expression mentioned above.
def replaceElseIf(text, reg):
elseIf = re.finditer(reg, text)
for key in elseIf:
text = text.replace(key.group(), 'elseif')
return text
And then the number of two structures can be counted
def countIfElseIf(text, level):
reg = r"\be.*?f\b"
reg1 = r'\b[a-zA-Z]+\b'
newText = replaceElseIf(text, reg)
newkwList = re.findall(reg1, newText)
ifelse_num = 0
ifelifelse_num = 0
ifelifelse_flag = 0
stack = Stack()
for kw in newkwList:
if kw == 'if':
stack.push('if')
if stack.size() >= 1:
if kw == 'elseif':
if stack.value(-1) == 'if':
stack.push('elseif')
elif kw == 'else':
if stack.value(-1) == 'if':
ifelse_num += 1
else:
while (stack.value(-1) != 'if'):
ifelifelse_flag = 1
stack.pop()
stack.pop()
if ifelifelse_flag:
ifelifelse_num += 1
ifelifelse_flag = 0
if level == 3:
print("if-else num: {}".format(ifelse_num))
if level == 4:
print("if-elif-else num: {}".format(ifelifelse_num))
- The main function is shown below:
if __name__ == "__main__":
kwList = ["auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum",
"extern", "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed",
"sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"]
file_name = input("Please enter the path of your file: ")
level = int(input("Please enter the level you want(1-4): "))
text = readFile(file_name)
if level == 1:
countKeyWords(kwList, text)
elif level == 2:
countSwitch(text)
else:
countIfElseIf(text, level)
- More than 10 commits:
Source code: LAB2.py
Unit Test
I haven't heard this word before this lab, so I searched on the Internet and obtained some results. I created a new file and added following codes:
import unittest
import 软件工程lab2
text = 软件工程lab2.readFile("d:/test.c")
class test(unittest.TestCase):
def test_read_file(self):
path = "d:/test.c"
def test_countKeywords(self):
kwList = ["auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum",
"extern", "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed",
"sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"]
self.assertEqual(软件工程lab2.countKeyWords(kwList, text), 35)
def test_countSwitch(self):
self.assertEqual(软件工程lab2.countSwitch(text), 2)
def test_count_if_else(self):
self.assertEqual(软件工程lab2.countIfElseIf(text, 3), [2, 2])
if __name__ == '__main__':
unittest.main()
And after running this program, I get the output:
It seems that everything is OK, my code has passed the unit test.
Coverage Optimization and Performance Testing
I haven't heard these words before this lab, so I searched on the Internet and obtained some results.
By using the coverage tool in Python, I obtained the results:
According to the above images, I have my coverage optimization which is 96%. And the missing code is the warning when we don't have "switch" keyword and some codes in stack class. It can be concluded that most codes are covered.
After searching on the Internet, I use cProfile of Python and get the final result of performance testing. It seems that my code performs well.
211 function calls in 0.003 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.003 0.003 <frozen importlib._bootstrap>:1002(_find_and_load)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:112(release)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:152(__init__)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:156(__enter__)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:160(__exit__)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:166(_get_module_lock)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:185(cb)
2 0.000 0.000 0.002 0.001 <frozen importlib._bootstrap>:220(_call_with_frames_removed)
10 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:231(_verbose_message)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:351(__init__)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:385(cached)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:398(parent)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:406(has_location)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:486(_init_module_attrs)
1 0.000 0.000 0.002 0.002 <frozen importlib._bootstrap>:558(module_from_spec)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:58(__init__)
1 0.000 0.000 0.002 0.002 <frozen importlib._bootstrap>:659(_load_unlocked)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:736(find_spec)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:811(find_spec)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:87(acquire)
3 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:874(__enter__)
3 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:878(__exit__)
1 0.000 0.000 0.001 0.001 <frozen importlib._bootstrap>:901(_find_spec)
1 0.000 0.000 0.003 0.003 <frozen importlib._bootstrap>:967(_find_and_load_unlocked)
7 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:114(<listcomp>)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:1155(__init__)
1 0.000 0.000 0.002 0.002 <frozen importlib._bootstrap_external>:1171(create_module)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:1179(exec_module)
3 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:1337(_path_importer_cache)
3 0.000 0.000 0.001 0.000 <frozen importlib._bootstrap_external>:135(_path_stat)
1 0.000 0.000 0.001 0.001 <frozen importlib._bootstrap_external>:1374(_get_spec)
1 0.000 0.000 0.001 0.001 <frozen importlib._bootstrap_external>:1406(find_spec)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:145(_path_is_mode_type)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:1500(_get_spec)
2 0.000 0.000 0.001 0.000 <frozen importlib._bootstrap_external>:1505(find_spec)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:154(_path_isfile)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:167(_path_isabs)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:491(_get_cached)
2 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:64(_relax_case)
1 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:696(spec_from_file_location)
7 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:91(_path_join)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
5 0.000 0.000 0.000 0.000 {built-in method _imp.acquire_lock}
1 0.002 0.002 0.002 0.002 {built-in method _imp.create_dynamic}
1 0.000 0.000 0.000 0.000 {built-in method _imp.exec_dynamic}
1 0.000 0.000 0.000 0.000 {built-in method _imp.is_builtin}
1 0.000 0.000 0.000 0.000 {built-in method _imp.is_frozen}
5 0.000 0.000 0.000 0.000 {built-in method _imp.release_lock}
2 0.000 0.000 0.000 0.000 {built-in method _thread.allocate_lock}
2 0.000 0.000 0.000 0.000 {built-in method _thread.get_ident}
1 0.000 0.000 0.003 0.003 {built-in method builtins.exec}
6 0.000 0.000 0.000 0.000 {built-in method builtins.getattr}
4 0.000 0.000 0.000 0.000 {built-in method builtins.hasattr}
3 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance}
15 0.000 0.000 0.000 0.000 {built-in method builtins.len}
1 0.000 0.000 0.000 0.000 {built-in method nt._path_splitroot}
1 0.000 0.000 0.000 0.000 {built-in method nt.fspath}
3 0.001 0.000 0.001 0.000 {built-in method nt.stat}
2 0.000 0.000 0.000 0.000 {method '__exit__' of '_thread.lock' objects}
7 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
24 0.000 0.000 0.000 0.000 {method 'endswith' of 'str' objects}
2 0.000 0.000 0.000 0.000 {method 'get' of 'dict' objects}
7 0.000 0.000 0.000 0.000 {method 'join' of 'str' objects}
1 0.000 0.000 0.000 0.000 {method 'pop' of 'dict' objects}
1 0.000 0.000 0.000 0.000 {method 'replace' of 'str' objects}
4 0.000 0.000 0.000 0.000 {method 'rpartition' of 'str' objects}
21 0.000 0.000 0.000 0.000 {method 'rstrip' of 'str' objects}
15 0.000 0.000 0.000 0.000 {method 'startswith' of 'str' objects}
Summary
- After four days' hard work, I have browsed hundreds of websites. It is really an unforgettable experience because I realized that writing code is only a small part of the assignment, sourcing and optimizing code takes up most of the time.
- After this lab, I have a deeper understanding of Python. And I learned how to do unit test and performance test which improved my ability of finding information.
- During the discussion with my classmates, I realized that I still had many things to consider, such as the removal of header files.