自制Web编程语言KamitaTomoe(基本架构)

我做这个东西为了解决自己的一些小项目(顺便找找趣味),方便自己写东西,所以在兼容python语法加一些东西

我们先来写出这个语言的第一个代码段:

#hello.py
def search(self, nums: list, target: int) -> int:
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = (right - left) // 2 + left
        num = nums[mid]
        if num == target:
            return mid
        elif num > target:
            right = mid - 1
        else:
            left = mid + 1
    return -1

# 作者:LeetCode-Solution
# 链接:https://leetcode.cn/problems/binary-search/solution/er-fen-cha-zhao-by-leetcode-solution-f0xw/
# 来源:力扣(LeetCode)
# 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
<!--deon.kt-->
<%

import hello
import KamitaTomoe.output as output

def main():
    output.echo('<h1>Hello World!</h1>')
    output.echo("我们输出了Hello World!,它将在网页上显示")
    output.echo(f'<h2>我们二分查找了[1,2,3,7,21,10,32,22,543,111]中的7</h2>,结果\
    下标:{hello.search(nums=[1,2,3,7,21,10,32,22,543,111],target=7)}')

%>

<html>
<h1>它可以正确输出Hello World!吗,请拭目以待</h1><br>
<% 
main()
%>
</html>

因为py来写web,我觉得不方便(不够php),但是php又太难看了,功能也不如py,所以,我就打算自制一个兼容py语法的KamitaTomoe(本身就是用py写的,所以当然要兼容)

前期,我打算用一行一行解释运行的方式来运行代码,但是因为py的特殊,需要用缩进代替掉大括号的作用,就感觉不舒服,于是就改变想法,直接使用一段代码来进行解释,抛弃掉一行一行的解释,解释成我们熟悉的python代码来运行,我们就使用exec函数来运行代码

首先要支持的肯定是解释器的调用,我这里在采用命令行传参的调用方式,例子:

python KamitaTomoe.py -f D:\Tsuki Hikari\Kamita_Tomoe\deon.kt

目前只支持绝对路径

首先我使用下面的代码来进行接收参数

arg = getopt.getopt(sys.argv[1:],'-f',['file'])

然后我也需要挑出文件的格式和文件所在路径

Extension = file.split('.')[-1] #获取文件格式
file = ''.join(arg[1])

这样子整合起来就是:

file = ''.join(getopt.getopt(sys.argv[1:],'-f',['file'])[1])
Extension = file.split('.')[-1]

然后要切换python的工作路径

os.chdir('/'.join(file.split('/')[0:-1])) #更换运行路径

然后我们定义一个类,代码的运行均在这个类里面完成

class move:

    def __init__(self): 
        pass
    def parse(self,code:str): #语法分析并且运行
        '''代码'''
        for i in code.split('\n'):
            i = i.split(' ')
            if(i == ''):
                continue
            if(i.startswith('#')):
                continue
            if(i.startswith('import')):
                continue
            if(i.startswith('class')):
                continue

于是我们就可以在切换工作路径之前加载一些语言默认加载的类库,比如output库,用来输出内容到网页

Class_library = '\n'.join([f'import KamitaTomoe.{i} as {i}' for i in ['output','html']])  #需要提前加载的类库
'''['output','html'] -> import KamitaTomoe.output as output \n import KamitaTomoe.html as html'''
self.exec_move(self.Class_library) #提前加载类库

接下来我们代码的运行靠着move类就可以了

首先我们要学会运行一个文件,首先就要把文件读出来

这个很简单,直接使用open方法读取即可

self.file_content = open(file,mode='r',encoding='utf-8').read() #读取文件

我记得我之前定义了一个成员方法parse,用于传入代码,进行语法分析转换成python代码并且运行,现在就可以书写这个方法

首先我们要根据<%开始,%>结束的字符来判断什么是python代码,什么是html代码,并且把html当作正常输出

那么,根据这个需求,我们当然是用正则表达式最简单的字符串切割

我们先使用print(self.file_content.split(‘<%’)) 切割并且输出内容(self.file_content是代码文件的内容):

>>>print(self.file_content.split('<%'))
PS D:\Downloads\TsukiHikari> & C:/Users/Administrator/AppData/Local/Programs/Python/Python310/python.exe d:/Downloads/TsukiHikari/Kamita_Tomoe/KamitaTomoe.py -f D:\Downloads\TsukiHikari\Kamita_Tomoe\deon.kt
['', '\nimport time\nimport hello\nimport KamitaTomoe.output as output\n\ndef main():\n    output.echo(\'<h1>Hello 
World!</h1>\')\n    print("我们输出了Hello World!,它将在网页上显示")\n    output.echo(f\'<h2>我们二分查找了[1,2,3,7,21,10,32,22,543,111]中的7</h2>,结果\\\n    下标:{hello.search(nums=[1,2,3,7,21,10,32,22,543,111],target=7)}\')\n 
   output.Web_output()\n\n%>\n\n<html>\n<h1>它可以正确输出Hello World!吗,请拭目以待</h1><br>\n', ' main() %>\n</html>']

可以看见这是一个列表,然后我们遍历这个列表,并且对里面每个元素再次切割’%>’

>>>print([i.split('%>') for i in self.file_content.split('<%')][1:])
[['\nimport time\nimport hello\nimport KamitaTomoe.output as output\n\ndef main():\n    output.echo(\'<h1>Hello Wor1,10,32,22,543,111]中的7</h2>,结果\\\n    下标:{hello.search(nums=[1,2,3,7,21,10,32,22,543,111],target=7)}\')\n    
output.Web_output()\n\n', '\n\n<html>\n<h1>它可以正确输出Hello World!吗,请拭目以待</h1><br>\n'], [' main() ', '\n</html>']]

于是我们可以发现,这个输出的列表一维每个元素代表每一个代码段,二维的第一个元素代表kt的程序代码,第二个元素代表html代码,注意:这个非常重要,决定了代码运行的顺序

code = [i.split('%>') for i in self.file_content.split('<%')][1:] #list[list['程序代码','html代码']]

但是二维数组看起来太费力了,所以我们可以转换一下,减慢一下运行速度,变成一维数组(呸,是列表,这样子就可以多执行一个for循环)

code = [ x for y in [i.split('%>') for i in self.file_content.split('<%')][1:] for x in y] #list[list['程序代码','html代码']]
''' vec = [[1,2,3], [4,5,6], [7,8,9]]
[num for elem in vec for num in elem],更加详细的例子:https://zhuanlan.zhihu.com/p/344114093'''

还需要解决如何运行代码的问题,因为exec函数的特殊性,所以exec函数的调用均在__init__成员方法内调用,其他的成员方法就负责修改解释出来的代码即可,到时候运行时直接把所有代码运行

在切换工作目录之前呢,我们可以提前加载一些该语言的类库,方便写代码的时候调用,但是这个不是必须的(可以开发的时候手动导入)

exec('\n'.join([f'import KamitaTomoe.{i} as {i}' for i in ['output','html']])) #提前加载类库
'''['output','html'] -> import KamitaTomoe.output as output \n import KamitaTomoe.html as html'''

我这里提前加载了output和html两个类库

然后在类里面创建一个成员变量,存放类方法解释出来可以运行的python代码

OK,我们开发的基本架构就完成了,我们已经可以运行代码了,也可以轻松的在这个基础上更改解释器的代码

解释器核心源码:

import sys
import getopt
import os
class move:
    Final_code = '' #最后生成的代码
    def __init__(self): 
        self.file_content = open(file,mode='r',encoding='utf-8').read() #读取文件
        luj = '\\'.join(file.split('\\')[0:-1])  #更换运行路径
        self.parse() #语法分析
        self.Final_code = '\n'.join([f'import KamitaTomoe.{i} as {i}' for i in ['output','html']])+'\n' \
        +f'import os \nos.chdir(\'{luj}\')' \
        +self.Final_code.replace('import KamitaTomoe.output as output','').replace('import KamitaTomoe.html as html','')
        self.Final_code += '\noutput.Web_output()' #返回生成的HTML
        print(self.Final_code)
    def Program_parse(self,code:str): #程序代码部分语法分析
        self.Final_code += (code+'\n')
    def parse(self): #语法分析
        '''语法解析'''
        code =[i.split('%>') for i in self.file_content.split('<%')][1:] #list[list['程序代码','html代码']]
        for i in code:
            for i1 in range(2):
                if(i1 == 0): #执行程序代码代码
                    self.Program_parse(i[0])
                else:
                    self.Final_code += f'output.echo(\'\'\'{i[1]}\'\'\')\n'
if __name__ == '__main__':
    file = ''.join(getopt.getopt(sys.argv[1:],'-f',['file'])[1])
    Extension = file.split('.')[-1]
    if(Extension != 'py' and Extension != 'kt'): #判断扩展名
        print('Illegal file format')
    else:
        try:
            moves = move()
            exec(moves.Final_code) #运行代码
        except Exception as e:
            print('Exception:', e)
        except: #如果不传入文件,那就使用交互式
            print('已经对交互式编程停止支持')

生成的python代码:

import KamitaTomoe.output as output
import KamitaTomoe.html as html
import os
os.chdir('D:\Downloads\TsukiHikari\Kamita_Tomoe')
import time
import hello


def main():
    output.echo('<h1>Hello World!</h1>')
    print("我们输出了Hello World!,它将在网页上显示")
    output.echo(f'<h2>我们二分查找了[1,2,3,7,21,10,32,22,543,111]中的7</h2>,结果\
    下标:{hello.search(nums=[1,2,3,7,21,10,32,22,543,111],target=7)}')


output.echo('''

<html>
<h1>它可以正确输出Hello World!吗,请拭目以待</h1><br>
''')

main()

output.echo('''
</html>''')

output.Web_output()

注意:output.echo方法用来给网页输出东西(类似于php的echo函数),在最后调用output.Web_output()用来整合echo的东西,给最后生成html

说实话这个不算一个难的东西,只要肯学,就只是一个语法分析而已,毕竟没有用到编译之类的

自制Web编程语言KamitaTomoe(基本架构)
当前页面https://www.df100.ltd/331.asp,文章作者星姮十织
维度前沿|Dimension Frontier © 2022. 版权所有

评论

  1. 钟意
    1周前
    2023-1-22 21:46:44

    页尾该2023年了

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇