山东大学软件工程项目实训-2 项目稿件 关于potato-comp的实现纪要以及todo

1. 需求:

输入:对于/config文件夹下的front-end文件夹下的若干.page 文件和若干<name>.expose.ts,默认模板下会带一个app.page和global.expose.ts
最后所有的<name>.expose.ts在global.expose.ts中引入 import _ from 'xx'
之后即可生效

具体内容:
.json文件中将要包含 
1.路由信息( 以<name>.json为范例 router-name = name )
2.setup处理信息(在这里可以自由的使用js语法 同时会对带有meta标记的变量进行替换)

    meta标记: 实际上就是potato预处理时使用的标记 可以定义 变量 和 函数 
    关于变量和函数的声明形式: 在global-config.ts中
        defPRI代表定义一个预导入
        defSEC代表生成一个硬插入段落 这个段落会直接被生成在set-up逻辑中
        defTPL代表生成一个模板 往其中输入参数会生成响应的模板变量
        调用方法也是类似 #tplFn( myName, #tck ) 
        可以发现 #tplFn中传入的参数也是可以使用#tck这样的potato变量的
        
        defPRI 的第一个参数是preInclude:Array第二个参数是具有一个参数的函                数,传入的函数是它的第一个参数,也就是preInclude:Array,第二参数将在编            译时被调用,作为副作用,可以选择不定义
    
        defSec和defTpl都具有3个参数: sec/tpl标识符|名字,变量含义体(即本身的定            义) 和 preInclude(需要预加载的import语句-- 将不会对import语句进行校验)
        
        如果第一个参数为null|undefined 它们都将被视作单纯引入preInclude的过程
        
        关于import语句,针对的是page本身的路径而言,所以算是硬插值,
        但是开放一个代表src的语法糖@, 这个@将在预编译时自动被定义为page所在路径

        在我们的template中 不再使用<></>的标签式语法
        而使用函数式的声明 如声明App组件:
        /** age = 32 */
        p("App")( { age: _age,$onClick: "clickHandler" } )( "hello" )
        将会生成:    
            <App :name="32", onClick="clickHandler"> hello </App>
        
        注意: 如果需要绑定变量 则以$开头 且后续需要传入 <变量名的字符串>
        
    /** deprecated: 编译器将不再使用meta-expose机制 */
    关于meta-expose引入: 无论是否在preInclude中使用过该引入
    最后都会生成import * from __META_EXPOSE__ from '@/.potato/meta-expose.ts';
    这也意味着__META_EXPOSE__这个变量需要被保留 不能被别的变量名占用
    
3. 关于<set-up></set-up> 和 <view></view> 字段 
    
    set-up字段内的内容都会被处理为预处理set-up逻辑 可以有多个set-up段落
    preInclude和在上一段定义的逻辑都是可用的

    view字段也可以被拆成多段 它代表的是模板逻辑即形如:
    p("App")( { age: '_age',$onClick: "clickHandler" } )( "hello" )
    最后的view字段是所有这些view字段的拼接和

4. 注意 potato-compiler 生成的是<扁平化>多页面应用 这也意味着不会产生类似嵌套路由这样的东西,在没有额外配置或是自己编写的情况下

5. 关于特殊插件,这是在生成/config/front-end/global-expose.ts之前也就是非运行时(编译时)使用的, 它可以按照额外配置(如operation生成的接口对象)帮助你预先加入一些必要的potato变量,你可以在此基础上扩展你的expose


/***************************************************************************/

2.实现方针

1.初步理解:
    1. 关于实现 global-config.ts 这个文件需要在引入{defPr,...} 这些特殊方法的    情况下才能起作用,这个文件在*编译阶段 是不会被引入的,事实上,这些方法的作用    在于作为一个入口,用于把所需要的token导入内存中(一个存储变量)
    
    所以 实现global-config.ts的核心就是要实现defPr..这些函数和相应的token存    储机制 这个token存储器将被命名为 potato-token-collector.ts 具备收集依赖的功    能 利用导出的函数来收集依赖 并且给接下来的编译存储信息
    
    2. 关于编译阶段的先后顺序和插件问题
    显然 midEngine的启动应当在potatoEngine之前 midEngine需要提供额外的副作用来    帮助 potatoEngine生成所需要的插件( 事实上:没有必要再做一次IO ) 所以这种情况    下 midEngine需要进行改动,添加一个可用的副作用列表,来在生成model,operation    的情况下将这些信息导出用于新的计算 
    
    那么还需要用于根据operation生成插件的工具 这部分可以放在末尾进行 定义在    potatoEngine同目录下的yieldPlugin.ts下 之后或将根据读取的potato-meta进行
    额外的插件生成,用来提供routerPlugin(生成路由变量和路由控制器)
    
    3. 编译产物和存储目录

        1.    src目录下pages目录用于存放所用的vue文件
        2.    在上述步骤之后 生成一个router.ts 然后在app.ts中引用
        这一步其实只需生成router.ts,只不过要对现有的app.ts进行改动
    
    4. util的改进
        1. 新增existOrMkdir以在存在输入目录的情况下避免覆盖    

3. 实现问题:
    1.    读取和预编译.page文件的问题
    在读取.page文件后 需要对<setup>和<view>内容进行区分
    所要得到的无非是一个累加器的功能 把所有的setup内容加上 + \n +
    后连接起来
    预编译阶段 使用正则表达式对#部进行编译 不过需要注意的是
    对于Sec和Tpl的处理是不同的,sec的话只需同步进行转译,然后tpl的话
    得在所有的sec都处理完了之后才行 那么的话其实就比较简单了
    分2阶段处理#号 一阶段处理后的产物交给2阶段处理 这时在对tpl的内容进行处理
    2阶段得使用tpl专用的正则表达式进行处理( #<tpl>( a, b, c... ) )    

    2. 关于sec和tpl要生成什么,如何生成
    sec的话只需进行替换即可 replace => return
    而tpl的话需要先找出参数 然后再把参数传入生成函数中去 将生成的字符串传回去    return 所以tpl函数第一个参数的形式/Type应当是(...arg:string) => string
    
    3. 关于sec和tpl的解析规则
    sec和tpl声明或使用起来和一般的js变量/函数没有什么区别
    sec的话只需要是let a = #ROUTER_LOGIN
    而tpl的话需要考虑到参数列表带空格的情况 所以中断的办法应当是\n或;
    #<tpl>*(a, b,    c);
    这种还是比较好实现的 \n|;$ 结尾就行
    
    4. 关于view的解析
    这一部其实只要实现"p"函数然后再定义一下try...catch即可
    因为eval的过程中有可能出错 
    p函数实现在view解析器里即可 作用是解析完语句然后累加到生成语句中去
    <template></template>
    
    5. 关于第一步准备配置的插件
        1.operationPlugin 用于生成request模板函数 如RequestLogin:sec
        2.routerPlugin 由前一步解析得到的router信息进行解析和生成
        得到router的有关def(跳转函数和路径常量)
        3.sceneUIPlugin 用于引入scene-ui的相应组件(PRI)
    
    6. 关于文件结构和目录
lc_config/
    model.json
    operation.json
    front-end/
        <>.expose.ts
        <>.page
        global.expose.ts    
template_repo/
    src/
    /** 这个目录可以existOrMkdir */
        /pages/

    而potato和mid是同目录的编辑器
    
    
    7. 主要的任务分隔
    
    ---- 解析篇 ----
    0. 生成engine和potato文件夹
    1. Token类型的定义和格式(preInclude: Array<string>, variable: [{ type: "SEC" | "TPL", ... }] )    
    2. import global.expose.ts 路径 --创建函数defPRI defSEC.. 声明exposeToken和    getExposeToken( potato/potato-token-collector.ts ) ++ token可标注private 
    3. 经过依赖收集 已经拥有了token数据 采用getToken()注入对.page的处理方法
    4. 解析目录 并传回需要的 .page路径(.expose.ts直接采取引入的形式 故不用解析)
    5. 创建一个根据page名得到相应生成物page路径的方法
    5. 定义writeToPages方法(outputPath, rawPage) 它的作用使用    pageGenerator.boot( rawPage, token )
    生成相应的字符串 然后写入路径Path
    6. 根据pageRaw信息进行解析的方法的实现 并生成对TPL和sec的解析
    以及解析view数据的p函数的实现(拼接)

    ---- 插件篇 ----
    生成三个依赖插件 sceneUIPlugin requestPlugin<=operation routerPlugin<=path
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hot Potato是一种经典的并行计算算法,可以使用MPI实现。以下是一个基本的实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <mpi.h> int main(int argc, char** argv) { int size, rank, potato, rounds = 0; int tag = 0; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) { printf("请输入土豆初始值:"); scanf("%d", &potato); printf("请输入回合数:"); scanf("%d", &rounds); // 将土豆发送给随机进程 int dest = rand() % size; MPI_Send(&potato, 1, MPI_INT, dest, tag, MPI_COMM_WORLD); printf("进程0发送土豆%d到进程%d\n", potato, dest); // 循环发送土豆 while (rounds > 0) { MPI_Recv(&potato, 1, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status); printf("进程%d收到土豆%d\n", rank, potato); rounds--; if (rounds == 0) { printf("进程%d是最后一个持有土豆的进程,游戏结束!\n", rank); potato = -1; } else { dest = rand() % size; printf("进程%d发送土豆%d到进程%d\n", rank, potato, dest); } MPI_Send(&potato, 1, MPI_INT, dest, tag, MPI_COMM_WORLD); } } else { // 接收土豆并传递给下一个进程 MPI_Recv(&potato, 1, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status); printf("进程%d收到土豆%d\n", rank, potato); while (potato != -1) { int dest = rand() % size; printf("进程%d发送土豆%d到进程%d\n", rank, potato, dest); MPI_Send(&potato, 1, MPI_INT, dest, tag, MPI_COMM_WORLD); MPI_Recv(&potato, 1, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status); printf("进程%d收到土豆%d\n", rank, potato); } } MPI_Finalize(); return 0; } ``` 在这个实现中,进程0会将土豆发送给随机的进程,然后进入循环,每一轮接收土豆并将其发送给随机的进程,直到回合数减为0。最后,进程0会发送一个标记值-1,表示游戏结束。其他进程则在接收到土豆后将其传递给下一个进程,直到接收到结束标记。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值