在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

詞法分析-Antlr-1

汽車電子技術 ? 來源:程序猿搬磚 ? 作者:壞人 ? 2023-03-03 10:15 ? 次閱讀

在上一節中我們提到了,我們可以根據一種叫 有限自動機 的東西將字符串分割成多個Token。

下面是一段swift代碼,其中實現了一些基礎Token的解析,原理就是: 有限自動機

//
//  ScriptLexer.swift
//  MyScriptCompiler
//
//  Created by legendry on 2019/8/21.
//  Copyright ? 2019 legendry. All rights reserved.
//
import Foundation
/// 腳本語言詞法分析器
public class ScriptLexer {
    
    public enum ScriptLexer: Error {
        /// 源碼為空
        case SourceCodeEmpty
        /// 語法錯誤
        case SyntaxError(reason: String)
    }
    /// 詞法分析器的有限狀態機狀態
    var fsmType = FSMType.Initial
    /// 默認token為nil
    var token: ScriptToken? = nil
    var _tmpTokens = [ScriptToken]()
    /// 初始化新的token
    /// 將狀態機遷移到新的狀態
    private func initToken(_ c: UInt8) throws -> FSMType {
        var _fsmType = FSMType.Unknow
        if let _t = token {
            /// 將解析到的token保存起來
            _tmpTokens.append(_t)
            token = nil
        }
        if c.isLetter {
            /// 當我們解析到字符i時,當前認為他是一個標識符
            token = ScriptToken(type: .Identifier)
            token?.appendTokenText(c: c)
            if c.char == "i" {
                /// 狀態機狀態切換至標識符i,如果后續是nt并以空格結束,則解析成int
                /// 否則解析成標識符
                _fsmType = .Identifier_Int_i
            } else {
                _fsmType = .Identifier
            }
        } else if c.char == "=" {
            token = ScriptToken(type: .EQ)
            token?.appendTokenText(c: c)
            _fsmType = .EQ
        } else if c.isDigit {
            token = ScriptToken(type: .IntLiteral)
            token?.appendTokenText(c: c)
            _fsmType = .IntLiteral
        } else if c.char == ">" {
            token = ScriptToken(type: .GT)
            token?.appendTokenText(c: c)
            _fsmType = .GT
        } else if c.char == "<" {
            token = ScriptToken(type: .LT)
            token?.appendTokenText(c: c)
            _fsmType = .LT
        } else if c.char == "-" {
            token = ScriptToken(type: .Minus)
            token?.appendTokenText(c: c)
            _fsmType = .Minus
        } else if c.char == "*" {
            token = ScriptToken(type: .Star)
            token?.appendTokenText(c: c)
            _fsmType = .Star
        } else if c.char == "+" {
            token = ScriptToken(type: .Plus)
            token?.appendTokenText(c: c)
            _fsmType = .Plus
        } else if c.char == "/" {
            token = ScriptToken(type: .Slash)
            token?.appendTokenText(c: c)
            _fsmType = .Slash
        } else if c.char == "(" {
            token = ScriptToken(type: .LeftBracket)
            token?.appendTokenText(c: c)
            _fsmType = .LeftBracket
        } else if c.char == ")" {
            token = ScriptToken(type: .RightBracket)
            token?.appendTokenText(c: c)
            _fsmType = .RightBracket
        } else {
            if c.isValid {
                _fsmType = .Initial
            } else {
                throw ScriptLexer.SyntaxError(reason: "不支持: \\(c.char)")
            }
        }
        return _fsmType
        
    }
    
    
    /// 解析腳本,生成Token
    /// 利用有限狀態自動機在不同狀態之間遷移得到不同的Token
    /// int age = 45
    /// age >= 3
    public func analysis(script: String) throws -> ScriptTokenReader {
        _tmpTokens.removeAll()
        fsmType = FSMType.Initial
        token = nil
        
        guard script.count > 0 else {
            throw ScriptLexer.SourceCodeEmpty
        }
        let charReader = CharReader(script)
        /// 開始分析源碼
        while let c = charReader.read() {
            switch fsmType {
            case .Initial:
                self.fsmType = try initToken(c)
            case .Identifier_Int_i:
                /// 第一個字母是i,如果第二個字母是n則狀態機遷移至Identifier_Int_n
                /// 否則狀態機遷移至Identifier
                if c.char == "n" {
                    self.fsmType = .Identifier_Int_n
                    token?.appendTokenText(c: c)
                } else if c.isTail {
                    /// 當前token標識完成
                    /// 狀態機重置
                    self.fsmType = try initToken(c)
                } else {
                    /// 狀態機遷移至標識符狀態,繼續解析標識符token
                    self.fsmType = .Identifier
                    token?.appendTokenText(c: c)
                }
            case .Identifier_Int_n:
                if c.char == "t" {
                    self.fsmType = .IntLiteral
                    token?.appendTokenText(c: c)
                    /// 這里暫時將類型切換成Int,如果后面還有字符則表式是一個標識符,再切換類型
                    token?.type = .Int
                } else if c.isTail {
                    /// 當前token標識完成
                    /// 狀態機重置
                    self.fsmType = try initToken(c)
                } else {
                    /// 狀態機遷移至標識符狀態,繼續解析標識符token
                    self.fsmType = .Identifier
                    token?.appendTokenText(c: c)
                }
            case .IntLiteral:
                if c.isTail {
                    /// 當前token標識完成
                    /// 狀態機重置
                    self.fsmType = try initToken(c)
                } else if c.char == "+" || c.char == "-" || c.char == "*" || c.char == "/" /*|| c.char == "(" || c.char == ")"*/ {
                    self.fsmType = try initToken(c)
                } else if c.isLetter {
                    throw ScriptLexer.SyntaxError(reason: "非數字字面量")
                } else {
                    token?.appendTokenText(c: c)
                }
            case .Identifier:
                if c.isTail {
                    self.fsmType = try initToken(c)
                } else {
                    token?.appendTokenText(c: c)
                }
            case .EQ:
                if c.isTail {
                    token?.type = .Assignment
                    self.fsmType = try initToken(c)
                } else {
                    throw ScriptLexer.SyntaxError(reason: "語法異常")
                }
            case .GE, .LE:
                if c.isTail {
                    self.fsmType = try initToken(c)
                } else {
                    throw ScriptLexer.SyntaxError(reason: "語法異常")
                }
            case .LeftBracket, .RightBracket:
                self.fsmType = try initToken(c)
            case .GT:
                if c.isTail {
                    self.fsmType = try initToken(c)
                } else if c.char == "=" {
                    self.fsmType = .GE
                    token?.type = .GE
                    token?.appendTokenText(c: c)
                } else {
                    throw ScriptLexer.SyntaxError(reason: "語法異常")
                }
            case .LT:
                if c.isTail {
                    self.fsmType = try initToken(c)
                } else if c.char == "=" {
                    self.fsmType = .LE
                    token?.type = .LE
                    token?.appendTokenText(c: c)
                } else {
                    throw ScriptLexer.SyntaxError(reason: "語法異常")
                }
            case .Minus, .Plus, .Star, .Slash:
                if c.isTail || c.isDigit {
                    self.fsmType = try initToken(c)
                } else {
                    throw ScriptLexer.SyntaxError(reason: "語法異常")
                }
            default: break
            }
        }
        if let _t = token {
            /// 將解析到的token保存起來
            _tmpTokens.append(_t)
            token = nil
        }
        let tokenReader = ScriptTokenReader.init(_tmpTokens)
        return tokenReader
    }
}

如果要快速落地一個DSL原型Demo,全部都自己去寫似乎有點慢。所以我們需要借助于工具來幫我們解析Token, 這個工具叫做: Antlr https://www.antlr.org/

這個工具支持很多語言,C++,Swift,Java....,常用的編碼語言都可以。你可以選擇一個合適你的語言來實現DSL了。

下載并配置好Antlr,Antlr本身是Java實現的,所以你的環境要運行Antlr需要有Java運行時環境。

圖片

配置好Antlr之后,我們就可以借助Antlr來實現我們的詞法分析了。Antlr通過解析規則文件來分析我們要分割的Token的規則,規則則是用正則表達式來書寫。

lexer grammar FlexDSLLexer;
//關鍵字
If: 'if';
FOR: 'for';
WHILE: 'while';
IN: 'in';
/// 基礎數據類型
Int: 'int';
Double: 'double';
Float: 'float';
True: 'true';
False: 'false';
//字面量
IntLiteral: [0-9]+;
DoubleLiteral: [0-9] . [0-9]*;
StringLiteral: '"' .*? '"'; //字符串字面量
//操作符
AssignmentOP: '=';
RelationalOP: '>' | '>=' | '<' | '<=';
Star: '*';
Plus: '+';
Sharp: '#';
SemiColon: ';';
Dot: '.';
Comm: ',';
LeftBracket: '[';
RightBracket: ']';
LeftBrace: '{';
RightBrace: '}';
LeftParen: '(';
RightParen: ')';
//標識符
Id: [a-zA-Z_] ([a-zA-Z_] | [0-9])*;
//空白字符,拋棄
Whitespace: [ \\t]+ -> skip;
Newline: ( '\\r' '\\n'? | '\\n') -> skip;

以上的規則文件內容指定了我們要從字符串中解析出來的Token,每一個Token都有一個名字,后面對應的則是這個Token的規則。把這個文件保存到FlexDSLLexer.g4

然后通過命令來編譯

antlr4 FlexDSLLexer.g4

編譯完成得到如下文件

圖片然后使用

javac *.java

編譯完成之后,通過運行grun命令來解析并輸出對應的Token(s)

grun FlexDSLLexer tokens -tokens Hello.play

其中Hello.play內容如下

int name = "人\\n字";
true
false

最后得到如下輸出,不僅成功的解析出來了我們指定的Token,還把對應的行列都輸出了。這樣當我們在解析出錯時也可以報具體的錯誤信息了。圖片到此,我們的詞法解析就完成了,接下來我們將進行語法分析。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • SWIFT
    +關注

    關注

    0

    文章

    116

    瀏覽量

    23802
  • 原理
    +關注

    關注

    4

    文章

    550

    瀏覽量

    44898
  • 代碼
    +關注

    關注

    30

    文章

    4788

    瀏覽量

    68612
收藏 人收藏

    評論

    相關推薦

    #硬聲創作季 4.2.1 詞法分析器的結構

    編譯原理詞法分析
    Mr_haohao
    發布于 :2022年09月01日 06:50:51

    #硬聲創作季 4.1.1 詞法分析概述

    編譯原理詞法分析
    Mr_haohao
    發布于 :2022年09月01日 06:51:30

    #硬聲創作季 6.3.1 詞法分析程序自動生成——LEX

    編譯原理詞法分析
    Mr_haohao
    發布于 :2022年09月01日 06:56:34

    關于antlr詞法分析器的使用

    剛剛接觸antlr詞法分析器只略看了些基本理論知識,關于做實例就完全不懂了,我想知道他需要什么樣的環境和軟件,以及軟件的下載地址.多謝各位了
    發表于 11-12 16:29

    Hanlp分詞之CRF中文詞法分析詳解

    ,對應CRFNERecognizer。CRF詞法分析器訓練了1至3個模型后,可以構造CRF詞法分析器: /*** 構造CRF
    發表于 02-18 15:28

    postgreSQL命令的詞法分析和語法分析

    PostgreSQL查詢SQL的語法分析1)——詞法分析
    發表于 05-16 16:33

    詞法作用域和閉包

    #hello,JS:14閉包(詞法作用域)
    發表于 05-20 15:35

    手寫SQL編譯器詞法分析

    精讀《手寫 SQL 編譯器 - 詞法分析
    發表于 05-26 16:27

    C語言詞法分析器的代碼

    C語言詞法分析器的代碼#include #include #include #include <
    發表于 10-10 15:32 ?85次下載

    借助Lex和Yacc進行詞法語法分析

    實驗目的: 1.通過對實驗型程序設計語言C1的定義,掌握程序設計語言的基本語法和語義; 2.使用Lex及Yacc實現詞法分析和語法分析
    發表于 04-18 23:04 ?30次下載

    基于ANTLR的試卷識別和導入系統

    為了解決在線考試系統中手工錄入試題效率低下的問題,提出了一種基于ANTLR的自動化解決方案。該方案建立一個試卷識別器,把試卷內容作為源代碼,通過詞法、語法和語義分析來進
    發表于 04-27 10:54 ?0次下載
    基于<b class='flag-5'>ANTLR</b>的試卷識別和導入系統

    語言與編譯器設計課程之詞法分析程序源程序

    本文檔的主要內容詳細介紹的是語言與編譯器設計課程之詞法分析程序源程序。
    發表于 07-01 08:00 ?0次下載
    語言與編譯器設計課程之<b class='flag-5'>詞法</b><b class='flag-5'>分析</b>程序源程序

    語法分析-Antlr

    上一節,我們通過Antlr快速的落地實現了Token的解析,這一節我們還是基于Antlr來實現語法的解析。
    的頭像 發表于 03-03 10:14 ?684次閱讀
    語法<b class='flag-5'>分析</b>-<b class='flag-5'>Antlr</b>

    手寫詞法分析

    在開始手寫詞法分析器之前呢,我們得先準備好一些零件,規劃好將要使用哪些函數,如果函數沒有現成的,那還得自己寫。
    的頭像 發表于 05-23 11:20 ?720次閱讀
    手寫<b class='flag-5'>詞法</b><b class='flag-5'>分析</b>器

    自頂向下的語法分析器—采用遞歸下降方法

    在之前已經通過手寫的方式實現了一個詞法分析器,現在,我將利用之前手寫的詞法分析器,使用遞歸下降的方式,實現一個簡單的語法分析器。
    的頭像 發表于 05-23 11:24 ?2081次閱讀
    自頂向下的語法<b class='flag-5'>分析</b>器—采用遞歸下降方法
    主站蜘蛛池模板: 奇米影视亚洲四色8888| 性做久久久久久久久| 奇米影视欧美| 激情五月综合| 在线视频网址| 卡一卡二卡三国色天香永不失联| 亚洲狠狠操| 欧美性video精品| 成人特黄午夜性a一级毛片| 天天射天天拍| 午夜高清视频| 波多野结衣久久国产精品| 特黄aa级毛片免费视频播放| 性生活毛片| 成年女人毛片免费视频| 热门国产xvideos中文| 美女扒开尿口给男人爽免费视频| 欧美www| 在线播放91灌醉迷j高跟美女| 高清视频在线播放| 狠狠色噜噜狠狠狠97影音先锋| 四虎在线观看免费永久| 精品四虎免费观看国产高清午夜| 午夜寂寞影院视频观看| 美欧毛片| 欧美天堂色| 奇米影视9999| 亚洲第二色| 97玖玖| 亚洲啪啪网站| 我想看一级播放片一级的| 黄页网站在线播放| 久久久久久久久久免观看| 亚洲一区二区三区网站| 日韩毛片免费看| 亚洲黄色一区二区| 91大神网址| 日本xxxx色视频在线观看| 18视频免费网址在线观看| 欧美黄色精品| 三级黄色在线视频|