实现python版本的c语言词法分析
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
__pycache__/
|
244
lex_c.py
Normal file
244
lex_c.py
Normal file
@@ -0,0 +1,244 @@
|
||||
import os
|
||||
import sys
|
||||
import dataclasses
|
||||
|
||||
|
||||
TOKEN_IF = 256,
|
||||
TOKEN_BREAK = 257,
|
||||
TOKEN_WHILE=258,
|
||||
TOKEN_SWITCH=259,
|
||||
TOKEN_CASE=260,
|
||||
TOKEN_DO=261,
|
||||
TOKEN_CHAR=262,
|
||||
TOKEN_INT=263,
|
||||
TOKEN_VOID=264,
|
||||
TOKEN_SYMBOL = 265 ,
|
||||
TOKEN_NUM = 266 ,# 数字
|
||||
TOKEN_INC = 267,# 自增
|
||||
TOKEN_DEC = 268,# 自减
|
||||
TOKEN_EQ = 269,# 相等
|
||||
TOKEN_NEQ = 270,# 不相等
|
||||
TOKEN_LSH = 271,# 左移
|
||||
TOKEN_RSH = 272,# 右移
|
||||
TOKEN_LEQ = 273,# 小于等于
|
||||
TOKEN_GEQ = 274,# 大于等于
|
||||
TOKEN_ELSE = 275,
|
||||
TOKEN_CONTINUE = 276 ,
|
||||
TOKEN_CONST = 277 ,
|
||||
TOKEN_STATIC = 278 ,
|
||||
TOKEN_UNSIGNED = 279 ,
|
||||
TOKEN_TYPEDEF = 280 ,
|
||||
TOKEN_STRUCT = 281 ,
|
||||
TOKEN_ENUM = 282 ,
|
||||
TOKEN_UNION = 283,
|
||||
TOKEN_STRING = 284,
|
||||
TOKEN_DEFAULT = 285,
|
||||
TOKEN_RETURN = 286,
|
||||
|
||||
def TOKEN(t:str):
|
||||
return t.encode("utf-8")[0]
|
||||
|
||||
_KeyWordTable={
|
||||
"if":TOKEN_IF,
|
||||
"else":TOKEN_ELSE,
|
||||
"break":TOKEN_BREAK,
|
||||
"while":TOKEN_WHILE,
|
||||
"switch":TOKEN_SWITCH,
|
||||
"case":TOKEN_CASE,
|
||||
"do":TOKEN_DO,
|
||||
"char":TOKEN_CHAR,
|
||||
"int":TOKEN_INT,
|
||||
"void":TOKEN_VOID,
|
||||
"continue":TOKEN_CONTINUE,
|
||||
"const":TOKEN_CONST,
|
||||
"static":TOKEN_STATIC,
|
||||
"unisgned":TOKEN_UNSIGNED,
|
||||
"typedef":TOKEN_TYPEDEF,
|
||||
"struct":TOKEN_STRUCT,
|
||||
"enum":TOKEN_ENUM,
|
||||
"union":TOKEN_UNION,
|
||||
"default":TOKEN_DEFAULT,
|
||||
"return":TOKEN_RETURN,
|
||||
}
|
||||
|
||||
_MarkTable={
|
||||
"<<":TOKEN_LSH,
|
||||
">>":TOKEN_RSH,
|
||||
"<=":TOKEN_LEQ,
|
||||
">=":TOKEN_GEQ,
|
||||
"!=":TOKEN_NEQ,
|
||||
"==":TOKEN_EQ,
|
||||
"++":TOKEN_INC,
|
||||
"--":TOKEN_DEC,
|
||||
"=":TOKEN("="),
|
||||
"!":TOKEN("!"),
|
||||
"<":TOKEN("<"),
|
||||
">":TOKEN(">"),
|
||||
"+":TOKEN("+"),
|
||||
"-":TOKEN("-"),
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
# 是否是数字加字母
|
||||
def isalnum(num:int):
|
||||
return bytes([num]).isalnum()
|
||||
|
||||
# 是否是数字加字母或下划线
|
||||
def isalnum_(num:int):
|
||||
return bytes([num]).isalnum() or num==TOKEN("_")
|
||||
|
||||
# 是否是字母
|
||||
def isalpha(num:int):
|
||||
return bytes([num]).isalpha()
|
||||
|
||||
# 是否是字母或下划线
|
||||
def isalpha_(num:int):
|
||||
return bytes([num]).isalpha() or num==TOKEN("_")
|
||||
|
||||
# 是否是数字
|
||||
def isdigit(num:int):
|
||||
return bytes([num]).isdigit()
|
||||
|
||||
# 是否是数字或小数点
|
||||
def isdigitdot(num:int):
|
||||
return bytes([num]).isdigit() or num==TOKEN(".")
|
||||
|
||||
# 是否是空白字符 包括换行符
|
||||
def isspace(num:int):
|
||||
return bytes([num]).isspace()
|
||||
|
||||
# 是否是给定字符串之一
|
||||
def isinstr(num:int,t:str):
|
||||
c=bytes([num])
|
||||
return c in t.encode("utf-8")
|
||||
|
||||
# 是否是操作符
|
||||
def isoperator(num:int):
|
||||
return isinstr(num,"<>!+-=")
|
||||
|
||||
@dataclasses.dataclass
|
||||
class lex_token:
|
||||
name:str
|
||||
buff:bytearray
|
||||
token:int
|
||||
line:int
|
||||
pos:int
|
||||
|
||||
|
||||
class lex_class(object):
|
||||
def __init__(self,text:bytes) -> None:
|
||||
self.text=text
|
||||
self.index=-1
|
||||
self.line=1
|
||||
self.pos=-1
|
||||
self.token_list:list[lex_token]=[]
|
||||
self.token_buff=bytearray()
|
||||
def save_char(self,c:int):
|
||||
self.token_buff.append(c&0xff)
|
||||
def save_token(self,token:lex_token):
|
||||
self.token_list.append(token)
|
||||
self.token_buff=bytearray()
|
||||
def _get_char(self):
|
||||
if(self.index<len(self.text)):
|
||||
c= self.text[self.index]
|
||||
return c
|
||||
return -1
|
||||
def get_next_char(self):
|
||||
if not self.is_end():
|
||||
self.index+=1
|
||||
c= self._get_char()
|
||||
if(c==b'\n'[0]):
|
||||
self.line+=1
|
||||
self.pos=-1
|
||||
else:
|
||||
self.pos+=1
|
||||
return c
|
||||
def is_end(self):
|
||||
return self.index>=len(self.text)
|
||||
def save_one_char_token(self,c:int):
|
||||
token=lex_token(bytes([c]).decode("utf-8"),bytes([c]),c,self.line,self.pos)
|
||||
self.save_token(token)
|
||||
def read_name_and_save(self,c:int):
|
||||
token=lex_token("symbol",bytearray(),TOKEN_SYMBOL,self.line,self.pos)
|
||||
self.save_char(c)
|
||||
while True:
|
||||
c=self.get_next_char()
|
||||
if(isalnum_(c)):
|
||||
self.save_char(c)
|
||||
else:
|
||||
break
|
||||
name=self.token_buff.decode("utf-8")
|
||||
if(name in _KeyWordTable):
|
||||
token.token=_KeyWordTable[name]
|
||||
token.name=name
|
||||
token.buff=self.token_buff
|
||||
self.save_token(token)
|
||||
return c
|
||||
def read_operator_and_save(self,c:int):
|
||||
token=lex_token("operator",bytearray(),TOKEN_SYMBOL,self.line,self.pos)
|
||||
self.save_char(c)
|
||||
while True:
|
||||
c=self.get_next_char()
|
||||
if(isoperator(c)):
|
||||
self.save_char(c)
|
||||
else:
|
||||
break
|
||||
name=self.token_buff.decode("utf-8")
|
||||
if(name in _MarkTable):
|
||||
token.token=_MarkTable[name]
|
||||
token.name=name
|
||||
else:
|
||||
raise Exception(f"不存在的操作符 {name} ")
|
||||
token.buff=self.token_buff
|
||||
self.save_token(token)
|
||||
return c
|
||||
def read_num_and_save(self,c:int):
|
||||
token=lex_token("number",bytearray(),TOKEN_NUM,self.line,self.pos)
|
||||
self.save_char(c)
|
||||
while True:
|
||||
c=self.get_next_char()
|
||||
if(isdigitdot(c)):
|
||||
self.save_char(c)
|
||||
else:
|
||||
break
|
||||
if(self.token_buff.count(b'.')>1):
|
||||
raise Exception("数字不能包含多个点号")
|
||||
token.buff=self.token_buff
|
||||
self.save_token(token)
|
||||
return c
|
||||
def read_str_and_save(self,c:int):
|
||||
c=self.get_next_char()
|
||||
while c!=b'\"'[0]:
|
||||
self.save_char(c)
|
||||
c=self.get_next_char()
|
||||
self.save_token(lex_token("string",self.token_buff,TOKEN_STRING,self.line,self.pos))
|
||||
return self.get_next_char()
|
||||
|
||||
def lex(text:bytes):
|
||||
lex_obj = lex_class(text)
|
||||
c=lex_obj.get_next_char()
|
||||
while not lex_obj.is_end():
|
||||
if isalpha_(c):
|
||||
c=lex_obj.read_name_and_save(c)
|
||||
elif isinstr(c,"{}[]()~,;:*"):
|
||||
lex_obj.save_one_char_token(c)
|
||||
c=lex_obj.get_next_char()
|
||||
elif isdigit(c):
|
||||
c=lex_obj.read_num_and_save(c)
|
||||
elif isspace(c):
|
||||
c=lex_obj.get_next_char()
|
||||
elif isoperator(c):
|
||||
c=lex_obj.read_operator_and_save(c)
|
||||
elif isinstr(c,"\""):
|
||||
c=lex_obj.read_str_and_save(c)
|
||||
else:
|
||||
raise Exception(f"err char {bytes([c])} at line:{lex_obj.line} pos:{lex_obj.pos}")
|
||||
# for item in lex_obj.token_list:
|
||||
# print(f"{item}")
|
||||
return lex_obj.token_list
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open("main.c",mode='rb') as f:
|
||||
lex(f.read())
|
25
main.c
Normal file
25
main.c
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
|
||||
|
||||
|
||||
const char* get_type(int s) {
|
||||
const char* ret;
|
||||
switch (s)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
ret = "yes";
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = "no";
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
30
parser_c.py
Normal file
30
parser_c.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import os
|
||||
import sys
|
||||
import dataclasses
|
||||
from lex_c import lex_token
|
||||
from lex_c import lex
|
||||
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class node:
|
||||
name:str
|
||||
next:None
|
||||
chid:None
|
||||
token_list:list[lex_token]
|
||||
|
||||
# 变量声明节点
|
||||
@dataclasses.dataclass
|
||||
class node_vdecl(node):
|
||||
vvalue:None
|
||||
vtype:str
|
||||
vattr:list[str]
|
||||
|
||||
# 函数定义节点
|
||||
@dataclasses.dataclass
|
||||
class node_fdef(node):
|
||||
rettype:str
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open("main.c",mode='rb') as f:
|
||||
token_list=lex(f.read())
|
Reference in New Issue
Block a user