《Scratch3.0代码生成器编写启示录》

《Scratch3.0代码生成器编写启示录》

1、前言

对于想要二次开发scratch3.0 的同学来说,多语言(Python、Javascript、Arduino等等)代码生成或许是很多人面临的一个难题,因为scratch3.0在参照谷歌的blockly进行scratch-blocks模块研发的时候摒弃了代码生成这一环节,导致现在很多scratch二次开发者在代码生成这一环节犯难。那么我们今天就要讲一讲,Blockly是如何进行代码生成的,这对Scratch的代码生成又将有着什么样的意义。

2、Code Generators <代码生成器>

大多数的Blockly应用程序都需要将用户的程序翻译成JavaScript、Python、PHP、Lua、Dart或其他一些语言。这都是通过Blockly的客户端执行去完成的。例如:
blockly展示界面

代码生成

第一步是去包裹你想要的语言生成器,Blockly自带以下几种代码生成器:

  • javascript_compressed.js
  • python_compressed.js
  • php_compressed.js
  • lua_compressed.js
  • dart_compressed.js

代码生成器的js文件应该放置在blockly_compressed.js之后,例如:

<script src="blockly_compressed.js"></script>
<script src="javascript_compressed.js"></script>

在你的应用中,想要拖拽出的积木随时转换成代码,需要这样调用:

var code = Blockly.JavaScript.workspaceToCode(workspace);

上面这行代码中,只需要将JavaScript字段 修改成 Python, PHP, Lua, Dart 中的任意一个,就可转换代码生成器的语言。’

实时生成

生成代码是一个非常快的操作,因此系统会频繁地调用这个功能,且不能产生异常。通常的做法是,在Blockly的状态变更期间去添加一个监听器,从而做到代码的生成和展示实时进行。代码如下:

function myUpdateFunction(event) {
  var code = Blockly.JavaScript.workspaceToCode(workspace);
  document.getElementById('textarea').value = code;
}
workspace.addChangeListener(myUpdateFunction);

3、Generating Code <生成代码>

大部分Blockly应用需要将前台的积木转换成后台的代码去执行,本章节讲述的是如何给一个定制的积木添加一个代码生成器。
首先到generators/ 目录下,选择你想生成的语言(JavaScript, Python, PHP, Lua, Dart,等等)的子目录,如果你的积木运行不是这几类的语言,那么需要你创建一个新的js文件。这个新的js文件在HTML编辑器中需要被包裹在<script ...>标签中。
下面是一个典型的代码生成器结构:

Blockly.JavaScript['text_indexOf'] = function(block) {
  // 搜索文本中的子字符串
  var operator = block.getFieldValue('END') == 'FIRST' ? 'indexOf' : 'lastIndexOf';
  var subString = Blockly.JavaScript.valueToCode(block, 'FIND',
      Blockly.JavaScript.ORDER_NONE) || '\'\'';
  var text = Blockly.JavaScript.valueToCode(block, 'VALUE',
      Blockly.JavaScript.ORDER_MEMBER) || '\'\'';
  var code = text + '.' + operator + '(' + subString + ')';
  return [code, Blockly.JavaScript.ORDER_MEMBER];
};

收集参数

绝大多数的代码生成器的第一项任务就是收集所有参数和字段的数据。其中最常用的是以下介个方法:

  • getFieldValue
  • valueToCode
  • statementToCode
1. getFieldValue
block.getFieldValue('END')

这个方法从一个指定的名称字段返回一个值:

  • 对于文本字段,此函数返回键入的文本。如。“Hello World”。
  • 对于下拉框,此函数返回跟选择项有关的中性语言文本。一个英语的积木可能有一个选择“first”单词的下拉框,然而同样的下拉框在德语中可能会展示位“erste”。代码生成器不能够识别所有的人类语言,因此getFieldValue函数会返回一个在下拉框被创建时指定的中性语言文本(Blockly的核心积木通常使用大写的英文单词,例如‘FIRST’)。
  • 对于一个可变的下拉框,这个函数返回面向用户名称的变量下拉框。请务必注意,此名称不一定与生成的代码中使用的变量名称相同。例如,变量名“ for”在Blockly中是合法的,但在大多数语言中会与保留字冲突,因此会重命名为“ for2”。同样,阿拉伯语变量名“ متغير”在Blockly中是合法的,但在大多数语言中都是非法的,因此将重命名为“ _D9_85_D8_AA_D8_BA_D9_8A_D8_B1”。要获取可能在生成的代码中使用的名称的Blockly变量名称,请使用以下调用:
Blockly.JavaScript.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
2. valueToCode
Blockly.JavaScript.valueToCode(block, 'FROM', Blockly.JavaScript.ORDER_ADDITION) || '0'

此函数查找连接到命名值输入(‘FROM’)的积木,生成该积木的代码,并将代码作为字符串返回。如果未连接输入,则此函数返回null,这就是为什么通常使用布尔’或’和默认值来跟随函数。因此,在上面的示例中,如果没有附加到名为’FROM’的输入的积木,则此输入的默认代码将是字符串’0’。

第三个参数指定嵌入所需的操作信息的顺序。每个语言生成器都有一个有序的优先级列表。valueToCode函数需要通过顺序值去给返回的代码添加优先顺序。valueToCode如果需要,这允许 将代码包装在括号中。有关详细信息,请参阅**运算符优先级**页面。

请注意,JavaScript应改为相应的语言(Python,PHP,Lua,Dart,等)。

3. statementToCode
Blockly.JavaScript.statementToCode(block, 'DO')

此函数查找连接到指定语句输入的嵌套块堆栈,生成该堆栈的代码,缩进代码,并将代码作为字符串返回。如果未连接输入,则此函数返回空字符串。

请注意,JavaScript应改为相应的语言(Python,PHP,Lua,Dart,等)。

组装代码

一旦收集了所有参数,就可以组装最终代码。这对于大多数积木来说都是很简单的。下面是while循环的一个例子:

var code = 'while (' + argument0 + ') {\n' + branch0 + '}\n';

那些没有返回值的状态积木,可以立即返回代码:

return code;

那些返回一个值的值积木会更难一点,下面是一个基本算术运算符(加减等)的例子:
在这里插入图片描述

var code = argument0 + ' ' + operator + ' ' + argument1;

这个例子表明了一个操作顺序的问题,从表达式(2*(3+4))看,有2种积木的连接方式。使用上面的代码片段,加法积木将返回字符串“3 + 4”,而乘法积木将使用这个作为输入,返回“2 * 3 + 4”。这个结果是不正确的,因为3在执行时被绑定到乘法上了。
为了解决这个问题,值积木必须返回一个包含2个值(代码和优先级顺序值)的列表。

return [code, Blockly.JavaScript.ORDER_ADDITION];

每种生成器语言都有一个优先级顺序列表。返回的顺序值将以最小的优先级跟代码绑在一起。有关详细信息,请参阅**运算符优先级**页面。
如果生成的代码要求包含子块的代码两次,则应该缓存参数以提高效率并防止副作用。

实现效果:在这里插入图片描述

  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 20
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值