编译器学习之词法分析
根据《编译器设计之路》中的neopascal实现,书中是用c++实现的。我计划改为go语言版,以下是用go实现的词法分析部分。https://github.com/kekemuyu/neopascalpackage main
import (
"fmt"
"io/ioutil"
"strconv"
log "github.com/donnie4w/go-logger/logger"
"strings"
)
type CToken struct {
m_iKind int
m_szContent string
m_iRow int
}
var (
m_szLexTbl int
m_szSource string
m_szFileName string
m_KeywordTbl mapint
m_szBuffer string
m_iRow int
m_iPos int
m_iNonterminal int
m_pTokenList []CToken
)
func init() {
LexInit()
}
func LexInit() {
m_pTokenList = make([]CToken, 0)
m_KeywordTbl = make(mapint)
SetLexTbl(FileToString("lex.txt"))
SetKeywords(FileToString("KEYWORDS.txt"))
// for i := 0; i < 50; i++ {
// fmt.Println(m_szLexTbl)
// }
// fmt.Println(m_KeywordTbl)
}
func main() {
GetToken(FileToString("test.p"))
log.Debug(m_pTokenList)
}
func FileToString(filename string) string {
bs, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println(err)
return ""
}
return string(bs)
}
func SetLexTbl(szStr string) {
iTmp := 0
// szs := strings.TrimSpace(szStr)
szs := strings.Replace(szStr, "\r\n", "", -1)
for iRow := 0; iRow <= 36; iRow++ {
for iCol := 0; iCol <= 128; iCol++ {
t, _ := strconv.Atoi(szs)
// fmt.Println(iTmp, iTmp+3, szs)
m_szLexTbl = t
iTmp = iTmp + 3
}
}
}
func SetKeywords(szSource string) {
var szTmp string
cnt := 0
for i := 0; i < len(szSource); i++ {
if szSource != '\n' {
szTmp += string(szSource)
} else {
if szTmp != "" {
m_KeywordTbl = cnt
szTmp = ""
cnt++
}
}
}
if szTmp != "" {
m_KeywordTbl = cnt
}
}
func GetToken(zsStr string) bool {
bTag := true
m_iPos = 0
zss := zsStr + ""
m_iRow = 1
TmpPos := 0
for (m_iPos < len(zss)) && (bTag) {
if string(zss) == "\n" && TmpPos != m_iPos {
m_iRow++
TmpPos = m_iRow
}
m_szBuffer += string(zss)
col := zss
if zss >= 128 {
col = 128
}
bTag = Process(m_szLexTbl)
if !bTag {
fmt.Println(m_iRow, ":", "词法分析错误,请检查单词")
return false
}
m_iPos++
}
return bTag
}
func Process(iTag int) bool {
iTmp := 0
if iTag == -99 {
return false
}
if iTag < 0 {
// log.Debug(m_szBuffer)
m_szBuffer = m_szBuffer[:len(m_szBuffer)-1]
m_iPos--
m_szBuffer = strings.TrimSpace(m_szBuffer)
// log.Debug(m_szBuffer)
if iTag == -1 {
m_szBuffer = strings.ToUpper(m_szBuffer)
if SearchKeyword(m_szBuffer) {
EmitToken(iTmp+40, "", m_iRow)
} else {
if m_szBuffer == "TRUE" || m_szBuffer == "FALSE" {
EmitToken(3, m_szBuffer, m_iRow)
} else {
EmitToken(1, m_szBuffer, m_iRow)
}
}
}
if iTag >= -6 && iTag <= -2 {
EmitToken(-iTag, m_szBuffer, m_iRow)
}
if iTag >= -15 && iTag <= -7 {
EmitToken(-iTag, m_szBuffer, m_iRow)
}
if iTag >= -28 && iTag <= -16 {
EmitToken(-iTag, m_szBuffer, m_iRow)
}
if iTag == -42 {
m_szBuffer := m_szBuffer[:len(m_szBuffer)-1]
m_iPos--
EmitToken(3, m_szBuffer, m_iRow)
}
m_szBuffer = ""
m_iNonterminal = 0
} else {
m_iNonterminal = iTag
}
return true
}
func SearchKeyword(szKey string) bool {
if _, ok := m_KeywordTbl; ok != true {
return false
} else {
return true
}
}
func EmitToken(iKind int, iContent string, iRow int) {
ct := CToken{
m_iKind: iKind,
m_szContent: iContent,
m_iRow: iRow,
}
m_pTokenList = append(m_pTokenList, ct)
}
点赞,而且 go 语言写出 MFC 风格的我也是第一次见。 yoz 发表于 2019-12-1 12:37
点赞,而且 go 语言写出 MFC 风格的我也是第一次见。
是的,很难看,因为是照搬的c++代码还没go化,后续会用gostyle模块化。 不明觉厉 本帖最后由 RAMILE 于 2019-12-1 19:08 编辑
lz 你咋不试试 rust,现在rust被吹上天了 本帖最后由 FireBrain 于 2019-12-1 20:35 编辑
RAMILE 发表于 2019-12-1 19:05
lz 你咋不试试 rust,现在rust被吹上天了
我喜欢简单的语言,尝试过rust,被rust的语言语法搞得头大,放弃了.最近发现一个新的类似go的语言vlang,没有gc,可能会尝试用这个.
页:
[1]