一起用swift写一个词法分析器

发布于:2023-01-04 ⋅ 阅读:(238) ⋅ 点赞:(0)

首先我们要了解词法分析工作的原理:

编译简单的说,就是把源程序转化为另一种形式的程序,而其中关键的部分就是理解源程序所要表达的意思,才能转化为另一种源程序。

可以用一个比喻来说明问题:人A和人B想要交谈,但是他们都不知道彼此的语言,这就需要一个翻译C,同时懂得A和B的语言。有了C做中间层,A和B才能正常交流。C的作用就有点像编译器,它必须能理解源程序所要表达的意思,才能把信息传递给另一个。

编译器也一样,它的输入是语言的源文件(一般可以是文本文件)对于输入的文件,首先要分离出这个输入文件的每个元素(关键字、变量、符号、、)

然后根据语言的文法,分析这些元素的组合是否合法,以及这些组合所表达的意思。

程序设计语言和自然语言不一样,都是用符号来描述,每个特定的符号表示特定的意思,而且程序设计语言是上下文无关的。上下文无关就是某一个特定语句所要表达的意思和它所处的上下文没有关系,只有它自身决定。

这篇博文主要说的就是词法分析,也就是把输入的符号串整理成特定的词素。

 既然了解了,我们就开始吧

废话不多说,上代码!

旁边有注释大家可以看看

有点儿菜,不过新手可以试试看

这是针对命令行的!!!

到时就在main文件调用测试就行了

Lexer.swift

//
//  Lexer.swift
//  mhcinc
//
//  Created by Monkey hammer on 2022/8/26.
//  Copyright © 2022 mhcinc. All rights reserved.
//

import Foundation
func Lexer() {
    ///定义token空白数组
    var token:[String] = []
    ///获取用户输入的字符
    var character = readLine()!
    ///封装getbe()方法,如果character是空白,则继续获取用户输入
    func getbe() {
        while character.isEmpty {
            character = readLine()!
        }
    }
    ///用于判断用于用户输入的是否是字母,并且是单个字母(即项目数(count)等于1)返回true并打印
    func letter() -> Bool{
        ///character(用户输入)不等于结束
        if character != "结束" && character != "" {
            ///character(用户输入)的项目数(count)等于1,Character类型有个isLetter(是否是字母)的方法,只有character的项目数等于1才能转换为Character类型
            if character.count == 1 {
                ///将character(用户输入)转为characterSet(Character类型转换)
                let characterSet:Character = Character(character)
                ///判断是否是字母
                while characterSet.isLetter == true {
                    ///通知用户输入成功
                    print("(Bool:true)(if you want to break please input the \"结束\" of Enter)")
                    ///继续执行
                    return true
                }
            } else {
                ///通知用户输入失败
                error()
            }
        }
        ///最后停止执行
        return false
    }
    ///用于判断用于用户输入的是否是数字,并且是单个字母(即项目数(count)等于1)返回true并打印
    func dight() -> Bool {
        ///character(用户输入)不等于结束
        if character != "结束" && character != "" {
            ///character(用户输入)的项目数(count)等于1,Character类型有个isNumber(是否是数字)的方法,只有character的项目数等于1才能转换为Character类型
            if character.count == 1 {
                ///将character(用户输入)转为characterSet(Character类型转换)
                let characterSet:Character = Character(character)
                ///判断是否是数字
                while characterSet.isNumber == true {
                    ///通知用户输入成功
                    print("(Bool:true)(if you want to break please input the \"结束\" or Enter)")
                    ///继续执行
                    return true
                }
            } else {
                ///通知用户输入失败
                error()
            }
        }
        ///最后停止执行
        return false
    }
    ///定义符号表
    var Symbols:[String] = []
    ///concatenation()将character与token数组连接,并且作为新的字符
    func concatenation() {
        token.append(character)
    }
    ///retarct()置空character
    func retract() {
        character = ""
    }
    ///reserve()方法返回int值是为了返回保留字的种别编码,如果不是保留字返回0值
    func reserve() -> Int {
        if token.joined(separator: "") == "while" {
            return 1
        }
        if token.joined(separator: "") == "if" {
            return 2
        }
        if token.joined(separator: "") == "else" {
            return 3
        }
        if token.joined(separator: "") == "switch" {
            return 4
        }
        if token.joined(separator: "") == "case" {
            return 5
        }
        else {
            return 0
        }
    }
    ///buildlist()将符号、常数登记到符号表
    func buildlist() {
        Symbols.append(character)
    }
    func error() {
        print("illegal character:\(character)")
    }
    switch character {
    ///串连case
    case "a":
        fallthrough
    case "b":
        fallthrough
    case "c":
        fallthrough
    case "d":
        fallthrough
    case "e":
        fallthrough
    case "f":
        fallthrough
    case "g":
        fallthrough
    case "h":
        fallthrough
    case "i":
        fallthrough
    case "j":
        fallthrough
    case "k":
        fallthrough
    case "l":
        fallthrough
    case "m":
        fallthrough
    case "n":
        fallthrough
    case "o":
        fallthrough
    case "p":
        fallthrough
    case "q":
        fallthrough
    case "r":
        fallthrough
    case "s":
        fallthrough
    case "t":
        fallthrough
    case "u":
        fallthrough
    case "v":
        fallthrough
    case "w":
        fallthrough
    case "x":
        fallthrough
    case "y":
        fallthrough
    case "z":
        while letter() || dight() {
            concatenation()
            character = readLine()!
        }
        retract()
        let c = reserve()
        if c == 0 {
            buildlist()
            print("(id:\(Int(Symbols.firstIndex(of: character)!)))")
        } else {
            print("(\(c):null)")
        }
        break
    case "0":
        fallthrough
    case "1":
        fallthrough
    case "2":
        fallthrough
    case "3":
        fallthrough
    case "4":
        fallthrough
    case "5":
        fallthrough
    case "6":
        fallthrough
    case "7":
        fallthrough
    case "8":
        fallthrough
    case "9":
        while dight() {
            concatenation()
            character = readLine()!
        }
        retract()
        buildlist()
        print("(num:\(Int(Symbols.firstIndex(of:character)!)))")
        break
    case "+":
        print("('+':null)")
        break
    case "-":
        print("('-':null)")
        break
    case "*":
        print("('*':null)")
        break
    case "<":
        character = readLine()!
        if character == "=" {
            print("(relop:LE)")
        } else {
            retract()
            print("(relop:LT)")
        }
        break
    case "=":
        character = readLine()!
        if character == "=" {
            print("(relop:EQ)")
        } else {
            retract()
            print("('=':null)")
        }
        break
    case ";":
        print("(';':null)")
        break
    default:
        error()
    }
}

main.swift 

//
//  main.swift
//  mhcinc
//
//  Created by Monkey hammer on 2022/8/26.
//  Copyright © 2022 mhcinc. All rights reserved.
//

import Foundation
Lexer()

接着我们来调试一下

xcode内调试最好复制一下打印的"结束"这个字或直接回车,否则Xcode会检查你输入的所有字符

例如像这样输入:

会打印输入字母错误的字样,不过不影响就是了

但是强迫症患者(像我这种的)肯定会不舒服

​​​​​​​​​​​​​​

 第二种调试方法:

在Xcode设置中查找:

接着添加frameworks and libraries

点击加号

 随便选一个

 便会多出文件夹

那么接着我们按右键

选择show in finder

 

出现页面

双击就能运行啦!!!

这时不用复制

 直接打字就行了

学废了吗😜

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到