section .data openfail: db 'File open failed :(',10,'Usage: a [file]',10 ; 10 -> linefeed openfailLen: equ $-openfail ; Length of the string totallines: db 'Total codes lines: ' totallinesLen:equ $-totallines return: db 10 ; linefeed print: db 00,00,00,00,00 ; 5 digits section .bss filep: resb 4 ; int content: resb 20479 ; 20479 bytes reallength: resb 4 ; int section .text global _start _start: ; command line arguments pop ebx ; argc (argument count) pop ebx ; argv[0] (argument 0, the program name) pop ebx ; The first real arg, a filename ; open file mov eax,5 ; sys_open mov ecx,0 ; open flag 0 - readonly mov edx,0 ; open mode 0 - mask int 80h ; check if open correctly test eax,eax ; negative means open failed js OPEN_FAILED ; read file content mov ebx,eax ; file descriptor mov eax,3 ; sys_read mov ecx,content ; content mov edx,20479 ; read 20479 bytes int 80h mov [reallength],eax ; store content length mov [filep],ebx ; store file descriptor ; check how many codes lines mov edi,0 mov ecx,[reallength] mov esi,0 ; content index NEXT: cmp esi,[reallength] ; EOF ??? jge EOF mov ebx,[content+esi] cmp bl,02fh ; slash jnz NOTSLASH call PARSECOMMENT jmp PARSELOOPOUT NOTSLASH: cmp bl,009h ; tab jnz NOTTAB jmp STARTWITHSPACE NOTTAB: cmp bl,020h ; space jnz NOTSPACE jmp STARTWITHSPACE NOTSPACE: cmp bl,00ah ; return je PARSELOOPOUT call GOLINE ; go through the codes line call INCLINECOUNT ; increase line count jmp PARSELOOPOUT STARTWITHSPACE: call GOSPACE ; a line start with spaces cmp bl,02fh ; slash jnz NOTSLASH call PARSECOMMENT jmp PARSELOOPOUT cmp esi,[reallength] ; EOF ??? jge PARSELOOPOUT call GOLINE ; go through the codes line call INCLINECOUNT ; increase line count jmp PARSELOOPOUT PARSELOOPOUT: inc esi loop NEXT EOF: ; store num into ascii reversely mov esi,print xor edx,edx ; clear dividend high mov eax,edi ; line count number mov ebx,10 ; divide 10 DIVAGAIN: div ebx add edx,030h ; '0' ascii mov [esi],edx ; store one char inc esi ; move index forward xor edx,edx ; clear quotient cmp eax,0 jnz DIVAGAIN ; print a sentence "Total lines: " mov eax,4 ; sys_write mov ebx,2 ; stderr mov ecx,totallines ; words mov edx,totallinesLen; words length int 80h ; output the count reversely, that's correct mov edi,5 ; loop id mov esi,print+4 ; from the tail to head NEXTOUT: mov eax,4 ; sys_write mov ebx,1 ; stdout mov ecx,esi ; the ascii to output mov edx,1 ; one byte int 80h dec esi ; move index back dec edi jnz NEXTOUT call printlinefeed ; print a new line CLOSE: ; close file mov eax,6 ; sys_close mov ebx,filep ; file descriptor int 80h jmp EXIT OPEN_FAILED: mov eax,4 ; sys_write mov ebx,1 ; stdout mov ecx,openfail mov edx,openfailLen int 80h EXIT: mov eax,1 ; sys_exit mov ebx,0 ; return 0 int 80h ; proc: print a new line printlinefeed: push eax push ebx push ecx push edx mov eax,4 ; sys_write mov ebx,2 ; stderr mov ecx,return ; one linefeed mov edx,1 ; one byte int 80h pop edx pop ecx pop ebx pop eax ret ; end proc ; proc: increase line count. affact edi INCLINECOUNT: inc edi ret ; end proc ; proc: go through all the continuing spaces and tabs, affact ebx/ecx/esi GOSPACE: SPACENEXT: inc esi cmp esi,[reallength] ; EOF ??? jge SPACEEND mov ebx,[content+esi] cmp bl,009h ; tab jnz SPACEEND cmp bl,020h ; space jnz SPACEEND loop SPACENEXT SPACEEND: ret ; end proc ; proc: go through a text line, affact ebx/ecx/esi GOLINE: LINENEXT: inc esi cmp esi,[reallength] ; EOF ??? jge LINEEND mov ebx,[content+esi] cmp bl,00ah ; return jz LINEEND loop LINENEXT LINEEND: ret ; end proc ; proc: parse the line start with '/', affact ebx/ecx/esi and edi -- linecount PARSECOMMENT: ;call eeeee push edx ; use it as the next char to '*', match '/*' and '*/' inc esi cmp esi,[reallength] ; EOF ??? jge SLASHFIRSTEOF mov ebx,[content+esi] cmp bl,02fh ; another slash, like '//' jnz NOTSLASHSECOND call GOLINE jmp SLASHFIRSTEND NOTSLASHSECOND: cmp bl,02ah ; like '/*' jnz NOTSLASHSTAR inc esi ; next char cmp esi,[reallength] ; EOF ??? jge SLASHFIRSTEOF mov ebx,[content+esi] TRYMATCH: inc esi ; next char in edx cmp esi,[reallength] ; EOF ??? jge SLASHFIRSTEOF mov edx,[content+esi] cmp bl,02ah ; follow a '*'? jz STAR jmp NOTMATCH STAR: cmp dl,02fh ; catch a '*', then look the next if it is a '/' jnz NOTMATCH jmp SLASHFIRSTEND NOTMATCH: mov bl,dl ; copy second to first jmp TRYMATCH NOTSLASHSTAR: call GOLINE ; codes start with '/' call INCLINECOUNT jmp SLASHFIRSTEND SLASHFIRSTEOF: call INCLINECOUNT ; this file ends with a '/' or '/*' jmp SLASHFIRSTEND SLASHFIRSTEND: pop edx ret ; end proc