Tag: 编程语言

控制流…

快速地,对于条件需求,我们有“ if ”和“ switch ”语句,对于循环需求,我们有“ for-in ”,“ while ”,“ repeat-while ”,“ stride ”语句。 如果: 如果,否则,如果,嵌套if语句… 在“ if”语句中,条件必须是布尔表达式。 迅速地,我们使用“ if let”语句来检查可选变量是否具有值。如果存在nil值,则大括号中的代码将被跳过。 示例2显示了如何使用嵌套的ifs和else-if语句。 例如: var myName:字符串? =“达里奥” //如果存在名字,请用他的名字打招呼 如果让名称= myName { print(“ Hello!\(name)”)//打印“ Hello! 达里奥” } 范例2: var totalMarks = 780 var isPassedInAllSubjects:Bool = true 如果totalMarks> 900 { 如果isPassedInAllSubjects { 打印(“获得第一名”) }其他{ 打印(“失败”) } }否则,如果totalMarks> 700 { […]

在Swift中实现编程语言—第6部分:解析变量

注意:这是“用Swift编写编程语言”教程系列的第六部分。一定要检查 以前的内容 。 在之前的教程中,我们创建了第一个解释器。 现在是时候使用一些真正的编程语言功能来启动它,首先是对变量的支持。 为了提供可变支持,我们的语言需要两个附加功能: 支持解析变量名 支持声明变量 本教程全部关于第一(“支持解析变量名”)。 解析变量名。 此功能会创建两种错误情况,首先将它们添加到Parser.Error枚举中: 枚举错误:Swift.Error { 预期情况 预期大小写 预期情况 预期情况 预期大小写(字符串) case notDefined(String) } 添加对解析变量的支持相当简单,只需执行几个简单的步骤。 首先,我们需要在Lexer中添加对变量名称的支持。 为此,我们要做的就是将一个案例identifier添加到我们的Token枚举以及一个生成器: 枚举令牌{ typealias Generator =(String)->令牌? 案例操作员(操作员) 案例号(浮点数) 案例解析 案例解析 案例标识符(字符串) 静态var生成器:[String:Generator] { 返回[ “ \\ * | \\ / | \\ + | \\-”:{.op(Operator(rawValue:$ 0)!)}, “ \\-?([0-9] * \\。[0-9] + | [0-9] […]

在Swift中实现编程语言—第7部分:声明变量

注意:这是“用Swift编写编程语言”教程系列的第七部分。一定要检查 以前的内容 。 上一次我们完成编写用于解析变量名称的功能,并使用了一个预先用变量初始化的全局字典来测试我们的代码。 因此,实现我们的语言自然而然的下一步就是增加声明变量的能力。 到目前为止,我们仅实现了表达式解析,例如,我们可以在单个语句中解析标识符,运算符和数字( x + 5 * 6 ),并且缺乏解析多个表达式的能力。 表达式解析是从解析器的parse()方法开始的。 我们想要将该方法的名称更改为parseExpression() ,因为我们仍然希望parse()代表解释器的入口点。 因此,在解析器中,我们要替换几行: func parseExpression()throws- > Node { //是:func parse() throws- > Node … } 和: func parseParens()引发->节点{ … let expressionNode = try parseExpression()//是:try parse() … } 这个想法是让新的parse方法支持两种语句类型,分别由parseExpresssion()方法和parseVariableDeclaration()方法表示。 后者我们尚未实施。 在准备实现parseVariableDeclaration() ,我们必须首先做两件事 为新的关键字var添加TokenGenerators,该关键字代表变量声明的开始以及=符号,用于声明变量声明的表达式的开始。 为变量声明添加一个名为VariableDeclaration的节点 首先,我们导航到Token枚举并添加以下内容: 枚举令牌{ typealias Generator =(String)->令牌? 案例操作员(操作员) 案例号(浮点数) 案例标识符(字符串) 案例解析 […]

在Swift中实现编程语言—第5部分:Main函数

这是“用Swift编写编程语言”教程系列的第五部分。请务必阅读第4部分。 在之前的教程中,我们完成了为计算器实现Lexer和Parser的工作。 现在,剩下的一切我都可以简单地遍历AST并“解释”一些输出。 所以……快到了! 您可能已经注意到,我们在解析时创建的Nodes ( Float和InfixOperation )很容易将两个值都评估为Float值。 因此,要评估AST,我们要做的就是向Node协议添加一种协议方法,以解释每个单个Node并在Node结构中实现它: 协议节点{ func interpret()throws-> Float } // … 扩展浮动:节点{ func interpret()throws-> Float { 返回自我 } } struct InfixOperation:节点{ // … func interpret()throws-> Float { 让左=尝试lhs.interpret() 让权利=尝试rhs.interpret() 切换op { 案例.divideBy: 返回左/右 案例时间: 返回左*右 大小写减号: 返回左-右 案例.plus: 返回左+右 } } } 就是这样,现在我们已经准备好创建我们的main函数,让我们称之为run : func run(code:String)抛出{ let令牌= Lexer(代码:代码).tokens 让解析器=解析器(令牌:令牌) 让ast […]

在Swift中实现编程语言—第1部分:简介

欢迎! 这是关于“在Swift中实现编程语言”的系列教程的第一部分。 通常,创建新的编程语言不是很实用。 实际上,在大多数情况下,它甚至被认为是浪费时间。 不够务实。 值得庆幸的是,在大多数情况下都是如此,几乎所有利基市场都存在开源语言。 但是尽管如此,当解决众多问题时,了解一两个解释器的实现方法实际上可以派上用场。 了解内部机制甚至可能像我一样改变您的软件开发方法。 当我写第一语言(Zolang)时,驱动因素是工作中的挑战。 对我来说,这是第一次实现一个口译员,这似乎是一个好方法。 我不希望这是最后一个。 当时,我们需要使用多种编程语言分别实现的各种业务逻辑的单一来源。 我们使用了脚本语言(Ruby),然后使用了每种平台的单独语言:iOS(Swift),Android(Kotlin)和服务器(TypeScript)。 通过实现一个简单的解释器,我们能够为所有这些接口创建一个接口,并且比我预期的要容易得多。 德怀特同意! 如您所见,我发现用自己的语言写作绝对是值得的。 一种实现的灵感促使我与大家分享了本教程系列。 在本系列中,我们将从为计算器创建一个简单的解释器开始,然后将该实现扩展为一种简单的编程语言。 这是本系列前六部分的粗略计划: 第1部分:简介 第2部分:语法-设计我们的第一语言(01/28/19) 第3部分:Lexer(02/04/19) 第4部分:解析器(02/11/19) 第5部分:主要功能(02/18/19) 第6部分:解析变量(02/25/19) 第7部分:声明变量(19/04/19) 第8部分:函数(03/11/19) 第9部分:定义函数(03/18/19) 第10部分:If陈述(03/25/19) 我希望你们对此充满期待,我知道。 在接下来的几周中,您将在每个星期一早上看到我发来的帖子。 我想添加比我已经计划好的更多的教程,但这将取决于您的反馈,所以请不要犹豫评论或鼓掌。 反馈的每一点都非常感谢。 接下来:语法! PS随时在Twitter(valdi101)上或在Medium上随时关注我,以获取有关将来教程的通知和讨论。

Swift中的错误处理…

Swift错误处理就是关于优雅地处理失败情况的一切。 良好的错误处理可增强最终用户和开发人员的体验。 这对于轻松识别错误/问题及其原因非常有用。 此外,如果最终用户在使用您的应用程序时发生任何系统故障,它还可以让最终用户以适当的方式了解有关故障/问题的信息。 可恢复与不可恢复的错误: 可恢复的错误是可能会暂时停止正常程序执行的错误,但是程序应该能够正常恢复并继续执行而不会丢失任何重要功能。 不可恢复的错误是程序无法从中恢复并且必须关闭的错误。 这些可能是由于程序逻辑中的错误或其他意外情况(例如资源不可用)导致的,否则,程序将无法以有意义的方式执行。 运行时可能会发生错误,并且可能会更改程序的流程。 我们在软件开发中遇到各种错误。 例如: 逻辑错误 类型转换错误 外部错误,例如FileNotFound等。 我们项目中的错误处理越具体,维护起来就越容易诊断问题。 “ Swift为投掷,捕捉,传播和操纵提供一流的支持 运行时可恢复的错误。” – Swift编程语言(Swift 3) 在过去,对不起,在古代,开发人员通常通过编写嵌套的if-else语句来处理错误,以捕获错误并加以处理。 这种方法导致带有很多嵌套条件的胖代码文件,而且,不仅如此,在使用那些可能导致错误的函数时,它并不表示会导致错误,除非我们记得或以类似的方式命名该函数。例如: func retrievingFileFromServerCanThrowAnError(fileName:String){} 快速错误协议: 错误协议只是一种表示可以抛出的错误值的类型。 在Swift中,所有可能引发错误的对象,类,结构,枚举都必须通过错误协议进行确认。 如果不是,编译器将无法理解,因此会引发警告和错误。 因此,我们可以使用任何类型的错误来表示错误,这些错误可以向错误协议确认。 通常,我们通过与Error协议进行确认来使用枚举 。 扔…? 扔……? 与其他许多现代编程语言一样,在Swift中,我们使用“ throws ”标记可能引发错误的函数。 这样,无论在何处调用该函数,编译器/ SDK都会告诉我们该函数可能导致错误,因此也要处理这些异常。 这样,我们可以增强可用性和项目可维护性。 “ throw ”仅用于在函数内部引发错误,该错误可能引发错误。 我们可以将此“ throw”与“ return”进行比较,因为当您抛出函数时,函数将返回。 我们在参数的末尾放置“ throws”关键字,以将该功能标记为可抛出。 例如: func selfDriving(车辆:Vehivle)引发 func GiveSpecificationsOf((车辆车辆:车辆)引发->规格 我们可以处理这类功能,这些功能可能会在许多方面导致错误。 在下面我们将看到它们,我们可以迅速执行此操作,以避免嵌套条件,函数中的代码code肿。 […]

#33 Swift故事周

对于我们所有人来说,这是又一个了不起的一周。 我们达到了新的里程碑,新作家也加入了团队。 在我们短暂的生存期间,我可以说人们只是喜欢阅读Swift的故事。 原因如下: 在短短2周内,Swift2Go已达到500多名关注者。 每天阅读出版物故事超过2000分钟(33.3小时)。 有20位作家在Swift2Go下发表故事。 和往常一样,我想介绍一下本周加入Swift2Go的新作家以及他们发表的一些Swift故事: SwiftBits:缓存图像 在Swift中编写自定义模式匹配 我如何停止内存泄漏并回收150MB的内存— Swift 带有RxSwift的MVVM:用户登录 使用构建器模式进行下一级Swift单元测试 可解码的JSON解析—迅速的爱情故事 请为这些出色的作家提供一本书,以感谢他们对Swift2Go出版物的贡献。 任何愿意在Medium上编写Swift故事的人都应邀以作家的身份加入Swift2Go出版物,并为社区做出贡献。 您可以通过发送电子邮件至 info@swift2go.com 进行 申请 。 如果您想帮助发展这个社区,可以通过与您的朋友分享出版物或其中的故事来做到这一点。 🚀 关注我们并继续关注更多Swift故事。 👇

第32周Swift故事

我对得到的积极回应感到惊讶。 人们只是喜欢为Swift社区做出贡献。 这就是为什么这封信献给本周加入Swift2Go的所有新作家的原因。 鲍勃·罗布林 马丹·阿布拉瓦内尔(Matan Abravanel) 乔吉·古纳万(Giorgy Gunawan) 詹姆斯·马利森 布鲁诺·穆尼兹(Bruno Muniz) 阿林德·阿留(Arlind Aliu) 阿尔菲安·洛萨里(Alfian Losari) 亚尔辛·奥兹迈德(Yalcin Ozdemir) 莫滕·贝克·迪特列夫森 请为这些出色的作家提供一本书,以感谢他们对Swift2Go出版物的贡献。 您可以通过与社交媒体上的朋友共享出版物或其中的故事来直接帮助发展该社区。 🚀

在Swift中实现编程语言-第2部分:语法-设计我们的第一语言

这是“用Swift编写编程语言”教程系列的第二部分。请务必阅读 第1部分 。 如本系列的介绍中所述,我们将首先创建尽可能最小的“实用”解释器之一,即我们自己的计算器,仅包括数字*,/,+和-。 不够激动? 不用担心,因为稍后,我们将把它用作我们自己的编程语言的基础。 为什么我们关心语法? 在接下来的教程中,我们实际上将使用3个核心模块来实现我们的解释器,每个模块都在自己的教程中。 词法分析器 :执行词法分析。 这是关于将输入的字符串转换为令牌列表,令牌的信息结构比简单的字符或单词还丰富。 解析:关于将令牌转换为称为抽象语法树的树结构。 主要功能(解释过程):该函数使用我们的Lexer和Parser创建抽象语法树 ,然后通过遍历它来“解释”输出。 在执行之前,我提到的所有步骤都不需要正式的语法。 但是我还是出于某种原因决定将本章包括在语法中: 当我学习计算机科学时,我发现关于形式语言的教科书很少能轻松地解释语法。 对我来说,他们对这个问题有太多的满足感,这反过来又使这个概念过于艰巨。 维基百科也是如此。 实际上,可以使用OysterKit和ANTLR4等工具从语法(半)自动生成前两个步骤(Lexer和Parser)的高度优化的实现。 因此,我发现有必要在我们开始手动实现此功能之前引入这些选项(不过,请保证,我发誓我会使其易于理解)。 “上下文”一词并没有太多上下文 在实现我们的计算器之前,毋庸置疑,我们必须从设计语言的结构开始。 为此,我们将为我们的语言创建上下文无关的语法 。 上下文无关的语法是一组生产规则,它们以给定的形式语言描述所有可能的字符串。 生产规则是简单的替代。 例如,规则 A⇒α 用α代替A (维基百科) 现在是一些定义的时候了: 非终结符是可以用其他符号代替的符号,例如“α”。但是,如果“A⇒α”是我们唯一的规则,则这意味着“α”无法用某些东西代替其他。 因此,它是一个终端符号。 但是,“上下文无关”到底是什么意思? 所谓“上下文”,是指符号在文本中出现的位置。 更具体地说,在特定符号之前或之后的符号。 可以根据上下文将语法分为两类:上下文无关和鼓声…上下文相关。 我发现区分两者的最佳方法是简单地比较两个示例。 每种类型一个。 请考虑以下两个语法: :: = 0 1 | 01 和… :: = 0 1 :: = 0 […]

在Swift中实现编程语言—第4部分:解析器

这是“用Swift编写编程语言”教程系列的第四部分。请务必查看 第3部分 。 语言解析被广泛认为是只有经验丰富的程序员才能做的事情。 这是几乎在任何领域都常见的误解。 当然,作为Swift等广泛使用的语言的核心贡献者,意味着您必须在该主题上拥有丰富的经验。 但这适用于每种类型的编程,并且不应使我们害怕创建自己的解析器。 什么是解析器? 解析器的主要目标是将Lexer生成的令牌列表转换成我们语言语法的数据结构,通常,这种“数据结构”是类似树的结构,例如“抽象语法树”。 像计算机科学中的所有内容一样,最好使用Wikipedia(:)来定义这种树。 抽象语法树是用编程语言编写的源代码抽象句法结构的树表示。 哇,这是很多定义不正确的概念。 让我们分解一下: 摘要—事实证明,我们并不关心解析器收到的所有令牌。 考虑表达式2 * (2 + 3) ,这里的树实际上不需要关于左括号和右括号的信息。 只是在其中表达的优先级。 括号已被抽象出来。 语法结构—用Swift的术语来说,这通常意味着任何表示struct , enum或class struct ,它们表示源代码如何以我们的语言语法形成。 自顶向下解析 实现解析器的方法有很多,但是我们今天要看的是自上而下的解析。 在自上而下的解析中,在继续进行更详细的部分之前,将生成语法语法树的最高级别的结构。 通常认为它比同等技术(自下而上)要慢一些,但更容易掌握,因此非常适合本教程。 递归体面解析 自上而下解析的一种非常流行的方法称为递归体面解析。 这种流行并不是巧合,因为它们最容易实现。 正如您可能假设的那样,这种简单性需要付出一定的代价,而您将是对的,因为它们也是性能最低的。 但是我们还是会选择递归体面的方法,以使本教程尽可能简单。 实作 对于我们的解析器,让我们从简单的类定义开始: 类解析器{ 让令牌:[令牌] var index = 0 init(令牌:[令牌]){ self.tokens =代币 } } 在全面实施之前,有必要回顾一下我们的语法: E⇒ | | () 运算符⇒ […]