成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

ChatGPT | AI自制編程語言-從0開始

發布于 2025-6-20 06:58
瀏覽
0收藏

最近在看編譯器的書籍,想從0開始寫一個簡單的自制編程語言練練手,但是同時想到自己現在手頭有ChatGPT,于是萌生想法:如果我了解編譯器整個設計過程,為什么我還需要重頭開始寫編譯器呢?為何不直接將整個實現思路給到GPT,讓GPT幫我實現代碼,我只需要考慮如何設計詞法和語法,如何優化等過程即可,說干就干,于是開始《ChatGPT|AI自制編程語言》系列文章。

1、試驗

在驗證《AI自制編程語言》之前,我在想整個流程是否按照想法執行,于是想到??golang??實現一個表達式引擎(自制編程語言的第一步就是要實現表達式引擎),如果表達式引擎能按照要求實現,那自制編程語言應該用GPT也可以實現。

(1)需求拆解

先將表達式引擎需求的拆解如下:

  • 主功能是用golang實現表達式引擎
  • 使用逆波蘭表達運算規則的先后順序
  • 支持操作符可以定義為+,-,*,/,(,)
  • 支持數據類型可以定義為:number,string

以上需求考慮的如果一次將需求輸入給GPT,代碼會比較長,而且一旦某個步驟出問題,不得不重新檢查或者,所以我們將需求分為三個子步驟:

  • 先讓GPT幫我們通過字符串表達式生成逆波蘭表達式
  • 然后GPT幫我們實現逆波蘭表達式再計算結果
  • 最后GPT幫我們生成字符串表達式計算的測試樣例

(2)定義prompt

步驟一:先讓GPT幫我們通過字符串表達式生成逆波蘭表達式

輸入到GPT3.5:

你是一個使用golang開發的資深的程序員,正在開發一個表達式引擎功能,功能需求如下:
- 實現將字符串表達式轉換為逆波蘭表達式
- 輸入是字符串表達式,輸出是帶空格的逆波蘭表達式字符串,同時輸出不需要帶`(`,`)`,`[`,`]`
- <切記>:只需要支持+,-,*,/,(,)操作符
- 數據類型只包含兩種:number,string
- 給出測試用例和main函數
- 代碼量控制在最精簡的范圍

步驟二:然后GPT幫我們實現逆波蘭表達式再計算結果

輸入到GPT3.5:

你是一個golang開發的資深的程序員,正在開發一個表達式引擎功能,功能需求如下:
- 實現計算逆波蘭式字符串表達式的結果
- 輸入是逆波蘭式字符串表達式,輸出是表達式計算的字符串結果
- <切記>:支持+,-,*,/操作
- <切記>:數據類型只包含兩種:number,string,需要注意string類型也需要支持+,-,*,/操作
- 代碼行增加一些注釋
- 給出測試用例和main函數
- 代碼量控制在最精簡的范圍

步驟三:最后GPT幫我們生成字符串表達式計算的測試樣例

輸入到GPT3.5:

用+,-,*,/,(,)給出一些計算表達式樣例和計算結果,要求如下:

- 只用給出整數計算
- 格式如下:fmt.Println(calculate("<表達式>") == "<結果>")

(3)輸出代碼

步驟一生成的代碼如下

// 運行的代碼:
package main

import (
    "fmt"
    "strings"
)

func isOperator(ch byte) bool {
    return ch == '+' || ch == '-' || ch == '*' || ch == '/'
}

func isDigit(ch byte) bool {
    return ch >= '0' && ch <= '9'
}

func isLetter(ch byte) bool {
    return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
}

func isSpace(ch byte) bool {
    return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
}

func precedence(ch byte) int {
    if ch == '+' || ch == '-' {
        return 1
    } else if ch == '*' || ch == '/' {
        return 2
    } else {
        return 0
    }
}

func toRPN(expr string) string {
    var stack []byte
    var output []string

    for i := 0; i < len(expr); {
        if isSpace(expr[i]) {
            i++
        } else if isOperator(expr[i]) {
            for len(stack) > 0 && isOperator(stack[len(stack)-1]) && precedence(stack[len(stack)-1]) >= precedence(expr[i]) {
                output = append(output, string(stack[len(stack)-1]))
                stack = stack[:len(stack)-1]
            }
            stack = append(stack, expr[i])
            i++
        } else if expr[i] == '(' {
            stack = append(stack, expr[i])
            i++
        } else if expr[i] == ')' {
            for len(stack) > 0 && stack[len(stack)-1] != '(' {
                output = append(output, string(stack[len(stack)-1]))
                stack = stack[:len(stack)-1]
            }
            if len(stack) > 0 && stack[len(stack)-1] == '(' {
                stack = stack[:len(stack)-1]
            }
            i++
        } else if isDigit(expr[i]) {
            start := i
            for i < len(expr) && isDigit(expr[i]) {
                i++
            }
            output = append(output, expr[start:i])
        } else if isLetter(expr[i]) {
            start := i
            for i < len(expr) && (isLetter(expr[i]) || isDigit(expr[i])) {
                i++
            }
            output = append(output, expr[start:i])
        } else {
            panic("Invalid character")
        }
    }

    for len(stack) > 0 {
        output = append(output, string(stack[len(stack)-1]))
        stack = stack[:len(stack)-1]
    }

    return strings.Join(output, " ")
}

func main() {
    expr := "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3"
    rpn := toRPN(expr)
    fmt.Println(rpn) // Output: 3 4 2 * 1 5 - 2 3 ^ ^ / +
}

// 測試代碼:
func TestToRPN(t *testing.T) {
    testCases := []struct {
        expr string
        rpn  string
    }{
        {"3 + 4", "3 4 +"},
        {"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3", "3 4 2 * 1 5 - 2 3 ^ ^ / +"},
        {"( 1 + 2 ) * 3 - 4 / 5", "1 2 + 3 * 4 5 / -"},
        {"a + b * c - d / e", "a b c * + d e / -"},
    }

    for _, tc := range testCases {
        rpn := toRPN(tc.expr)
        if rpn != tc.rpn {
            t.Errorf("toRPN(%v) = %v, want %v", tc.expr, rpn, tc.rpn)
        }
    }
}

步驟二生成的代碼的如下:

// 運行的代碼:
package main

import (
 "fmt"
 "strconv"
 "strings"
)

func main() {
 expr := "5 1 2 + 4 * + 3 -"
 result := calculate(expr)
 fmt.Println(result)
}

func calculate(expr string) string {
 stack := make([]string, 0)
 operators := map[string]bool{"+": true, "-": true, "*": true, "/": true}

 for _, token := range strings.Split(expr, " ") {
  if !operators[token] {
   stack = append(stack, token)
  } else {
   b, _ := strconv.Atoi(stack[len(stack)-1])
   a, _ := strconv.Atoi(stack[len(stack)-2])
   stack = stack[:len(stack)-2]
   switch token {
   case "+":
    stack = append(stack, strconv.Itoa(a+b))
   case "-":
    stack = append(stack, strconv.Itoa(a-b))
   case "*":
    stack = append(stack, strconv.Itoa(a*b))
   case "/":
    stack = append(stack, strconv.Itoa(a/b))
   }
  }
 }

 return stack[0]
}

// 測試代碼: 
func TestCalculate(t *testing.T) {
 expr1 := "5 1 2 + 4 * + 3 -"
 result1 := calculate(expr1)
 if result1 != "14" {
  t.Errorf("Expected result to be 14, but got %s", result1)
 }

 expr2 := "2 3 4 + *"
 result2 := calculate(expr2)
 if result2 != "14" {
  t.Errorf("Expected result to be 14, but got %s", result2)
 }

 expr3 := "5 2 /"
 result3 := calculate(expr3)
 if result3 != "2" {
  t.Errorf("Expected result to be 2, but got %s", result3)
 }

 expr4 := "hello world +"
 result4 := calculate(expr4)
 if result4 != "helloworld" {
  t.Errorf("Expected result to be helloworld, but got %s", result4)
 }

 expr5 := "5 hello *"
 result5 := calculate(expr5)
 if result5 != "hellohellohellohellohello" {
  t.Errorf("Expected result to be hellohellohellohellohello, but got %s", result5)
 }
}

步驟三輸出如下:

fmt.Println(calculate("1+2") == "3")
fmt.Println(calculate("3-4") == "-1")
fmt.Println(calculate("5*6") == "30")
fmt.Println(calculate("8/4") == "2")
fmt.Println(calculate("(1+2)*(3-4)") == "-3")
fmt.Println(calculate("10/(2+3)*4") == "8")
fmt.Println(calculate("2*3+(4-1)/5") == "6")
fmt.Println(calculate("(2+3)*(4-1)/5") == "3")
fmt.Println(calculate("1+2*3+4") == "11")
fmt.Println(calculate("1+(2*3)+4") == "11")
fmt.Println(calculate("1+2*(3+4)") == "15")
fmt.Println(calculate("(1+2)*3+4") == "13")
fmt.Println(calculate("(1+2)*(3+4)") == "21")

(4)合并代碼并測試

package main

import (
    "fmt"
    "strings"
)

func isOperator(ch byte) bool {
    return ch == '+' || ch == '-' || ch == '*' || ch == '/'
}

func isDigit(ch byte) bool {
    return ch >= '0' && ch <= '9'
}

func isLetter(ch byte) bool {
    return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
}

func isSpace(ch byte) bool {
    return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
}

func precedence(ch byte) int {
    if ch == '+' || ch == '-' {
        return 1
    } else if ch == '*' || ch == '/' {
        return 2
    } else {
        return 0
    }
}

func toRPN(expr string) string {
    var stack []byte
    var output []string

    for i := 0; i < len(expr); {
        if isSpace(expr[i]) {
            i++
        } else if isOperator(expr[i]) {
            for len(stack) > 0 && isOperator(stack[len(stack)-1]) && precedence(stack[len(stack)-1]) >= precedence(expr[i]) {
                output = append(output, string(stack[len(stack)-1]))
                stack = stack[:len(stack)-1]
            }
            stack = append(stack, expr[i])
            i++
        } else if expr[i] == '(' {
            stack = append(stack, expr[i])
            i++
        } else if expr[i] == ')' {
            for len(stack) > 0 && stack[len(stack)-1] != '(' {
                output = append(output, string(stack[len(stack)-1]))
                stack = stack[:len(stack)-1]
            }
            if len(stack) > 0 && stack[len(stack)-1] == '(' {
                stack = stack[:len(stack)-1]
            }
            i++
        } else if isDigit(expr[i]) {
            start := i
            for i < len(expr) && isDigit(expr[i]) {
                i++
            }
            output = append(output, expr[start:i])
        } else if isLetter(expr[i]) {
            start := i
            for i < len(expr) && (isLetter(expr[i]) || isDigit(expr[i])) {
                i++
            }
            output = append(output, expr[start:i])
        } else {
            panic("Invalid character")
        }
    }

    for len(stack) > 0 {
        output = append(output, string(stack[len(stack)-1]))
        stack = stack[:len(stack)-1]
    }

    return strings.Join(output, " ")
}

func calculate(expr string) string {
    expr = toRPN(expr) // 新增轉換的代碼
 stack := make([]string, 0)
 operators := map[string]bool{"+": true, "-": true, "*": true, "/": true}

 for _, token := range strings.Split(expr, " ") {
  if !operators[token] {
   stack = append(stack, token)
  } else {
   b, _ := strconv.Atoi(stack[len(stack)-1])
   a, _ := strconv.Atoi(stack[len(stack)-2])
   stack = stack[:len(stack)-2]
   switch token {
   case "+":
    stack = append(stack, strconv.Itoa(a+b))
   case "-":
    stack = append(stack, strconv.Itoa(a-b))
   case "*":
    stack = append(stack, strconv.Itoa(a*b))
   case "/":
    stack = append(stack, strconv.Itoa(a/b))
   }
  }
 }

 return stack[0]
}

func main() {
 fmt.Println(calculate("1+2") == "3")
    fmt.Println(calculate("3-4") == "-1")
    fmt.Println(calculate("5*6") == "30")
    fmt.Println(calculate("8/4") == "2")
    fmt.Println(calculate("(1+2)*(3-4)") == "-3")
    fmt.Println(calculate("10/(2+3)*4") == "8")
    fmt.Println(calculate("2*3+(4-1)/5") == "6")
    fmt.Println(calculate("(2+3)*(4-1)/5") == "3")
    fmt.Println(calculate("1+2*3+4") == "11")
    fmt.Println(calculate("1+(2*3)+4") == "11")
    fmt.Println(calculate("1+2*(3+4)") == "15")
    fmt.Println(calculate("(1+2)*3+4") == "13")
    fmt.Println(calculate("(1+2)*(3+4)") == "21")
}

在??https://go.dev/play/??上運行,得到的輸出結果看上去沒問題。

ChatGPT | AI自制編程語言-從0開始-AI.x社區

運行結果

注意:以上代碼有一些bug,需要我們用GPT調整或者修改prompt,不過從自制編程語言這塊看來用GPT是可以行的通的。

2、如何自制編程語言?

既然GPT在程序員的輔助下能實現自制語言,那我們從0開始,分為兩個部分:定義特性和架構設計

(1)特性

自制的編程語言需要支持如下特性:

  • 類JS語法
  • 變量綁定
  • 支持整型,布爾,浮點,字符串,數組,哈希等數據結構
  • 支持算數表達式
  • 內置函數
  • 內置eval,支持自舉
  • 閉包
  • 考慮性能,使用字節碼和實現簡單虛擬機
  • 支持正則表達式
  • 支持調試器
  • ...

(2)架構

ChatGPT | AI自制編程語言-從0開始-AI.x社區

架構

  • 編寫源代碼
  • 詞法解析器解析源代碼
  • 語法解析器生成AST
  • AST轉換為字節碼
  • 插入調試代碼到字節碼中
  • 加載系統庫
  • 加載binding模塊
  • 字節碼虛擬機加載字節碼
  • 運行獲得結果

除了基于上面的必備的模塊以外,還需要增加優化器,解決字節碼中一些不必要的循環,調整字節碼的順序和一些尾遞歸優化等。好了,既然架構已經定了,那我們就開始把,接下來3-4個月內將會更新《ChatGPT|AI自制編程語言》系列文章?。ㄏM粫窨觺~)

參考

(1)《用Go語言自制解析器》
(2)https://zhuanlan.zhihu.com/p/96969423
(3)《自己動手實現Lua:虛擬機、編譯器和標準庫》

本文轉載自??周末程序猿??,作者:周末程序猿

已于2025-6-20 10:46:03修改
收藏
回復
舉報
回復
相關推薦
主站蜘蛛池模板: 欧美精品一区二区三区蜜桃视频 | 日本成人福利视频 | 久久久久一区二区三区 | 久久精品亚洲 | 亚洲在线免费观看 | 国产精品免费一区二区三区 | 国产视频一视频二 | 欧美中文在线 | 国产成人福利视频 | 免费在线国产视频 | 欧美a在线看 | 欧美久久久电影 | 在线一区 | 久久久欧洲 | 日韩精品999 | 国产主播第一页 | 久久精品亚洲 | 免费在线黄色av | 日本久久精品视频 | 中文字幕一区二区三区精彩视频 | 亚洲国产二区 | 欧美一区二区三区视频在线观看 | 97色在线视频 | 中文字幕一区二区三区在线观看 | 99亚洲精品 | 99re视频在线观看 | 国产综合久久 | 色爱综合 | 情侣酒店偷拍一区二区在线播放 | 国产成人精品一区二区三区四区 | 毛片免费视频 | 毛片毛片毛片毛片 | 日本欧美视频 | 在线播放亚洲 | 在线观看黄色电影 | 国产美女久久 | 亚洲欧美第一视频 | 国产aⅴ爽av久久久久久久 | 中文字幕亚洲一区二区三区 | 天天色天天射天天干 | 黄视频免费在线 |