Python-构建篇-编译器-1~2

前言

构建篇-第二栏

01

读取

相较于解释器,编译器同样需要先接收源代码,再进行词法/语法/语义分析,生成中间代码/目标代码,最后代码生成以及链接生成最终的可执行程序

所以跟上一栏解释器一样,我们仍然先读取源代码文件,并对源代码文件逐行解析

生成(转换)中间代码(Python),最后打包

首先,我们Add一个函数,这个函数接收两个参数,一个是源代码文件路径,另一个作为标志符

同时思考下在逐行解析时,我们总得把其解析后转换的内容给妥善保管,所以我们就可以使用临时文件来存储解析后转换的代码

def build_start(filename,domu='',self=''):
    global while_meet
    global newelseif_count
    doom = 0
    global fun_meet
    global allpathin
    with open(filename, 'r', encoding='utf-8') as file:
        total_lines = sum(1 for _ in file)  
        file.seek(0)
        with tempfile.NamedTemporaryFile(mode='w+', delete=False, encoding='utf-8') as temp_file:
            temp = temp_file.name

解析·转换

与解释器大同,同样我们可以用for循环来读取每一行内容,并使用if来判断该行是否有函数关键词

但同样的,我们仍需要一个十分重要的设置:一个变量,使用这个变量来控制控制流结构部分,并仍然作为一级执行

但顺序上可以稍微不同,将这个关键变量放在前面也是可以的,只要它不等于0就代表代码控制流结构的代码块还没有彻底跳过(每行)

for line_num, line in enumerate(file, start=1):
    if doom != 0:
        doom -=1
        continue

提参

我们要将源代码转换成python代码,非常重要的一步就是提参,顾名思义,提取参数

打个比方-你设置了一个函数:

prinf()

但实际上这就是print,而现在你要将它转换为print,那就肯定需要其参数

prinf('你好') -->> print('你好')

但就这?

我们需要去处理一些特殊符号,甚至当你的语法格式设置为打印内容,参数无需加引号时,在转换的时候你还得为其添加上引号

同时我们还需要确保考虑了多种情况,有引号?没引号?变量加引号?浮点数、整数加引号?

所以我们就需要一个完整的机制来处理参数问题

我们先想一下这个机制
我们可以让它获取两个参数:关键词和要提参的文本

跟上一栏get_code相差不大的是前面的处理,同样的正则表达式,以此来拿到括号里的内容

然后我们让其能清除参数内数组表示,同时要让其参数间正确地用逗号分割,再让它检查每个参数

最后我们还要让它合并,删除多余逗号

def get_codekey2(keyword, text):
    pattern = rf"{re.escape(keyword)}\(([^)]+)\)"
    match = re.search(pattern, text)
    if match:
        args_raw = match.group(1)
        args_raw = re.sub(r'\[.*?\]', '', args_raw)
        def handle_braces(match):
            brace_content = match.group(0)
            before_brace = match.start()
            after_brace = match.end()
            pre_text = args_raw[:before_brace]
            post_text = args_raw[after_brace:]
            if pre_text and pre_text[-1] != ',':
                brace_content = ',' + brace_content
            if post_text and post_text[0] != ',' and pre_text[-1] != ',':
                brace_content += ','
            return brace_content
        args_raw = re.sub(r'{[^}]*}', handle_braces, args_raw)
        args_raw = args_raw.replace('{', '').replace('}', '')
        args_list = re.split(r'(?<!\\),', args_raw)
        def add_quotes_if_needed(arg, skip_values=None):
            if arg.replace('.', '', 1).isdigit() or (arg.startswith('-') and arg[1:].replace('.', '', 1).isdigit()):
                try:
                    float(arg)
                    return arg 
                except ValueError:
                    pass  
            if skip_values is None or arg not in skip_values:
                return f"'{arg}'"
            return arg
        args_list = [add_quotes_if_needed(arg,doemlist) for arg in args_list if arg.strip()]
        args_raw = ','.join(args_list)
        args_raw = re.sub(r',+', ',', args_raw).strip(',')
        return args_raw
    else:
        return None

但数字还好说,变量又是怎么让其不被加引号处理的呢?

我们可以在处理变量时,(通常为赋值时)将变量加入列表,这样就不会让变量在被处理时被加上引号了

a = get_codekey2('prinf',line)
temp_file.write(f'print({a})')

赋值表达式转换

说实话这个没什么好讲的,就是if抓关键字等于号,然后split分割等号左右

重要的是还得考虑一个点,是callback还是直接赋值

如果是直接赋值,我们当然可以把这一行内容直接写入临时文件内,但如果不是呢?

在为callback时,我们可以将赋值表达式转换的部分也就是判断关键字等于号的部分放在判断doom下,同时在赋值表达式转换部分下不要直接跟elif,而是重置为if

原因很简单,从这讲:赋值表达式转换部分与别的部分逻辑上并不互斥

而且只要你认真学过,你就因该知道elif是为处理多个条件分支,只要一个条件为真,后面的条件都不会被再检查

所以我总不可能说 = 后的callback不处理

if '=' in line:
    parts = line.split('=', 1)
    if len(parts) == 2:
        name, expr = parts
        name = name.strip()
        if('(' in expr and ')' in expr):
            continues=0
        else:
             temp_file.write(f'{line}')
             doemlist.append(name)
if '' in line:
    ....
elif '' in line:
    ....

控制流结构转换

同样还是与上一栏逻辑相同

跟踪语句拿代码块内容,

部分内容需要多次处理

然后写入临时文件即可

处理函数也与上一栏大差不差,我就不过多赘述了

直接上代码

def searchdef2(file_path, keyword, wbornum, whilenum):
    with open(file_path, 'r', encoding='utf-8') as file:
        lines = file.readlines()
    in_function = False
    in_block = False
    collecting = False
    function_content = []
    current_content = []
    block_start_line = -1
    in_if_block = False 
    for i, line in enumerate(lines):
        stripped_line = line.strip()
        if stripped_line.startswith(keyword) and '(' in stripped_line and ')' in stripped_line:
            last_close_parenthesis = stripped_line.rfind(')')
            if last_close_parenthesis != -1:
                if stripped_line[last_close_parenthesis + 1:].strip() == '{':
                    in_function = True
                    collecting = True
                    block_start_line = i
                    continue
        if collecting:
            if stripped_line == '{':
                in_block = True
            elif stripped_line == '}':
                in_block = False
                if in_if_block:
                    in_if_block = False 
                else:
                    collecting = False
                    function_content.append(''.join(current_content).strip() + '\n}')
                    current_content = []
            else:
                if 'if' in stripped_line and '(' in stripped_line and ')' in stripped_line:
                    in_if_block = True  
                current_content.append(line)
            if in_function and not in_block:
                in_block = True
    full_content = function_content[whilenum]
    dpmvcjd = full_content.splitlines()
    doom2 = len(dpmvcjd) + 1
    if wbornum == 1:
        return doom2
    elif wbornum == 2:
        if in_if_block == True:
            return [full_content,0]
        else:
            return [full_content,1]
def searchdef(file_path, keyword, wbornum):
    with open(file_path, 'r', encoding='utf-8') as file:
        lines = file.readlines()
    function_contents = []
    function_count = 0  
    block_nesting = 0  
    else_started = False  
    for i, line in enumerate(lines):
        stripped_line = line.strip()
        if stripped_line.startswith(keyword) and '(' in stripped_line and ')' in stripped_line:
            if '{' in stripped_line:
                function_count += 1  
                block_nesting += 1 
                function_name = f"{keyword}{function_count}"
                function_contents.append((function_name, [])) 
                continue
        if block_nesting > 0:
            if stripped_line == '{':
                block_nesting += 1  
            elif stripped_line == '}':
                block_nesting -= 1  
                if block_nesting == 0:
                    function_contents[-1][1].append(line)
            else:
                if stripped_line.startswith('else'):
                    else_started = True
                function_contents[-1][1].append(line)
    results = []
    for func_name, content in function_contents:
        content_str = ''.join(content).strip()
        if wbornum == 1:
            results.append(len(content_str.splitlines()) + 1 if content_str else 0)
        elif wbornum == 2:
            else_content = [line for line in content if line.strip().startswith('else')]
            results.append((content_str, ''.join(else_content).strip()))
    return results if wbornum in (1, 2) else None
def zddeget2(contentb):
    pattern = r'while\((.*?)\)'
    match = re.search(pattern, contentb)
    if match:
        value_inside_brackets = match.group(1)
        return value_inside_brackets
def remove_empty_lines(text):
    lines = text.split("\n")  
    non_empty_lines = [line for line in lines if line.strip() != ""]  
    return "\n".join(non_empty_lines)
def zddeget(contentb):
    pattern = r'if\((.*?)\)'
    match = re.search(pattern, contentb)
    if match:
        value_inside_brackets = match.group(1)
        return value_inside_brackets
def tempifnow(doom_true, doom_false):
    with tempfile.NamedTemporaryFile(mode='w+', delete=False, encoding='utf-8') as temp_file2:
        temp2 = temp_file2.name
        temp_file2.write(doom_true)
    with tempfile.NamedTemporaryFile(mode='w+', delete=False, encoding='utf-8') as temp_file3:
        temp3 = temp_file3.name
        temp_file3.write(doom_false)
    file1 = build_start(temp2,1)
    file2 = build_start(temp3,1)
    with open(file1, 'r', encoding='utf-8') as file_one:
        temp2content = file_one.read()
    with open(file2, 'r', encoding='utf-8') as file_two:
        temp3content = file_two.read()
    return [temp2content, temp3content]
def tempifnow2(doom_true):
    with tempfile.NamedTemporaryFile(mode='w+', delete=False, encoding='utf-8') as temp_file2:
        temp2 = temp_file2.name
        temp_file2.write(doom_true)
    file1 = build_start(temp2,1)
    with open(file1, 'r', encoding='utf-8') as file_one:
        temp2content = file_one.read()
    return temp2content
def searchdef_def(file_path, keyword,whilenum):
    with open(file_path, 'r', encoding='utf-8') as file:
        lines = file.readlines()
    in_function = False
    in_block = False
    collecting = False
    function_content = []
    current_content = []
    block_start_line = -1
    in_if_block = False 
    for i, line in enumerate(lines):
        stripped_line = line.strip()
        if stripped_line.startswith(keyword) and '(' in stripped_line and ')' in stripped_line:
            last_close_parenthesis = stripped_line.rfind(')')
            if last_close_parenthesis != -1:
                if stripped_line[last_close_parenthesis + 1:].strip() == '{':
                    in_function = True
                    collecting = True
                    block_start_line = i
                    continue
        if collecting:
            if stripped_line == '{':
                in_block = True
            elif stripped_line == '}':
                in_block = False
                if in_if_block:
                    in_if_block = False 
                else:
                    collecting = False
                    function_content.append(''.join(current_content).strip() + '\n}')
                    current_content = []
            else:
                if 'if' in stripped_line and '(' in stripped_line and ')' in stripped_line:
                    in_if_block = True  
                current_content.append(line)
            if in_function and not in_block:
                in_block = True
    full_content2 = function_content[whilenum]
    dpmvcjd = full_content2.splitlines()
    doom23 = len(dpmvcjd) + 1
    return [doom23,full_content2]
def zddeget3(contentb):
    pattern = r'function\((.*?)\)'
    match = re.search(pattern, contentb)
    if match:
        value_inside_brackets = match.group(1)
        return value_inside_brackets
                elif 'while' in line:
                    while_meet+=1
                    num_chars = 5
                    random_chars = [random.choice(string.ascii_lowercase) for _ in range(num_chars)]
                    fivebl = ''.join(random_chars)
                    temp_file.write(f'{fivebl} = 0\n')
                    doom_while = searchdef2(filename,'while',2,while_meet-1)[0].strip('}')
                    get_keycontent_while = zddeget2(line)
                    temp_file.write(f'while({fivebl} <{get_keycontent_while}):\n   ')
                    temp_file.write(fivebl + ' += 1\n')
                    godit_while = tempifnow2(doom_while)
                    for i in godit_while.split('\n'):
                        temp_file.write('   ' + i + '\n')
                    doom = searchdef2(filename,'while',1,while_meet-1)
                elif 'if' in line:
                    newelseif_count +=1
                    doomn = searchdef(filename,'if',2)
                    doom2 = searchdef(filename,'if',1)
                    doom = doom2[newelseif_count-1]
                    doonmnew = doomn[newelseif_count-1][0].split('}else{')
                    doom_true = remove_empty_lines(doonmnew[0])
                    try:
                        doom_false = remove_empty_lines(doonmnew[1])
                    except IndexError:
                        doom_false = ''
                    get_keycontent = zddeget(line)
                    temp_file.write(f'if({get_keycontent}):\n')
                    godit = tempifnow(doom_true, doom_false)
                    goditonen = len(remove_empty_lines(godit[0]).split('\n'))
                    goditonen2 = len(remove_empty_lines(godit[1]).split('\n'))
                    goditnock = 0
                    for i in godit[0].split('\n'):
                        if(goditnock+1 == goditonen):
                            temp_file.write('   ' + i )
                        else:
                            temp_file.write('   ' + i + '\n')
                        goditnock+=1
                    goditnock = 0
                    if(doom_false != ''):
                        temp_file.write('else:\n')
                        for i in godit[1].split('\n'):
                            if(goditnock+1 == goditonen2):
                                temp_file.write('   ' + i )
                            else:
                                temp_file.write('   ' + i + '\n')
                            goditnock+=1
                elif 'function' in line:
                    fun_meet+=1
                    get_keycontent = zddeget3(line)
                    get_keycontent2 = searchdef_def(filename,'function',fun_meet-1)
                    doom = int(get_keycontent2[0])
                    temp_file.write(f'def {get_keycontent}():\n')
                    newgetcon = get_keycontent2[1].split('}')[0]
                    newconnow = tempifnow2(newgetcon)
                    doemlist.append(get_keycontent)
                    for i in newconnow.split('\n'):
                        temp_file.write('   ' + i + '\n')

库加入

如果你自己设置的函数有调用库的,那么在转换时也应该加入库的引用

但如果直接write写入临时文件,是非常不合适的

所以我们需要在临时文件顶行加入库引用

但我们需要先判断是否已经加入了引用

如果没有,我们就先移动文件指针到开头,并读内容

再加入新的内容,将模块引用添加到内容开头

接着再将文件指针移动到文件开头

最后用新内容覆盖原始内容,截断文件至当前写入位置

                elif 'sleep' in line:
                    if ('import time' not in temp_file.read()):
                        temp_file.seek(0)
                        original_content = temp_file.read()
                        new_content = 'import time\n' + original_content
                        temp_file.seek(0)
                        temp_file.write(new_content)
                        temp_file.truncate()  
                    wrtcontent = get_codekey2('sleep', line)
                    temp_file.write(f'time.sleep({wrtcontent})\n')

END

当源代码文件逐行解析完毕后,就返回临时文件路径

if(domu == ''):
    allpathin = temp
    return temp

打包下一次讲,Thank you

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要安装 python-ipopt,你需要先安装 Ipopt 库。这个库是用 C++ 编写的,所以你还需要安装一些 C++ 编译器。 在 Linux 系统上,你可以使用下面的命令来安装 Ipopt 和相关的依赖项: ``` sudo apt-get install g++ build-essential gfortran pkg-config wget https://www.coin-or.org/download/source/Ipopt/Ipopt-3.12.12.zip unzip Ipopt-3.12.12.zip cd Ipopt-3.12.12 ./configure make sudo make install ``` 然后,你可以使用 pip 安装 python-ipopt。 ``` pip install python-ipopt ``` 在 Windows 系统上,你可以在这里下载 Ipopt 的预编译二进制文件:https://www.coin-or.org/download/binary/Ipopt/。下载并安装后,你可以使用 pip 命令安装 python-ipopt。 ``` pip install python-ipopt ``` ### 回答2: 要安装python-ipopt,您可以按照以下步骤进行操作: 1. 首先,请确保您已经在您的计算机上安装了Python解释器。如果您还没有安装,您可以从Python的官方网站上下载并安装最新的Python版本。 2. 接下来,您需要安装IPOPT求解器的依赖库。这些依赖库包括Blas、Lapack、Mumps和HSL等。您可以从其官方网站或各种软件包管理器中获取并安装这些依赖库。 3. 现在,请下载并安装python-ipopt模块。您可以从其GitHub存储库上获取python-ipopt的源代码,并按照其中的指南进行安装。确保您下载和安装与您计算机上的Python版本兼容的最新版本的python-ipopt。 4. 安装完成后,您可以将python-ipopt模块导入到您的Python脚本中,然后开始使用它来解决您的优化问题。请确保您已经阅读了python-ipopt的文档,并了解如何使用其API来构建和求解优化问题。 请注意,安装python-ipopt可能会涉及一些特定于操作系统和计算机配置的步骤。因此,在您开始安装之前,最好阅读并遵循其官方文档中提供的详细安装指南。 ### 回答3: 要安装python-ipopt,你可以按照以下步骤进行操作: 1. 首先,确保你的计算机已经安装了Python。如果没有安装Python,请前往Python官方网站下载并安装最新的Python版本。 2. 然后,你可以选择使用pip或conda等工具来安装python-ipopt。打开命令行终端,并输入以下命令安装python-ipopt: - 如果你使用pip,可以输入命令:pip install python-ipopt - 如果你使用conda,可以输入命令:conda install -c conda-forge python-ipopt 3. 等待安装完成。安装过程可能需要一些时间,取决于你的网络速度和计算机配置。 4. 安装完成后,你可以在Python代码中导入python-ipopt模块,并使用它提供的功能。例如,你可以使用python-ipopt求解数学优化问题。 请注意,安装python-ipopt可能需要一些依赖项,如IPOPT求解器。如果安装过程中遇到任何错误或依赖项问题,请按照错误信息进行相应的调整和解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值