package main import ( "unsafe" "mxc/token" "mxc/syntax" ) //export write func cWrite(fd int32, buf unsafe.Pointer, count uint32) (n int32) //export mxc_readfile func cReadfile(path unsafe.Pointer, pathLen int32, buf unsafe.Pointer, bufCap int32) (n int32) //export mxc_filesize func cFilesize(path unsafe.Pointer, pathLen int32) (n int32) func out(s string) { if len(s) > 0 { cWrite(1, unsafe.Pointer(unsafe.SliceData(s)), uint32(len(s))) } } func err(s string) { if len(s) > 0 { cWrite(2, unsafe.Pointer(unsafe.SliceData(s)), uint32(len(s))) } } func readFile(path string) (data []byte, ok bool) { sz := cFilesize(unsafe.Pointer(unsafe.SliceData(path)), int32(len(path))) if sz < 0 { return nil, false } buf := []byte{:sz+1} n := cReadfile(unsafe.Pointer(unsafe.SliceData(path)), int32(len(path)), unsafe.Pointer(unsafe.SliceData(buf)), sz+1) if n < 0 { return nil, false } return buf[:n], true } func getArgs() (ss []string) { buf := []byte{:4096} n := cReadfile(unsafe.Pointer(&[]byte("/proc/self/cmdline")[0]), 18, unsafe.Pointer(&buf[0]), 4096) if n <= 0 { return nil } var args []string start := int32(0) for i := int32(0); i < n; i++ { if buf[i] == 0 { if i > start { args = append(args, string(buf[start:i])) } start = i + 1 } } return args } func escapeStr(s string) (r string) { r = "" for i := int32(0); i < int32(len(s)); i++ { c := s[i] switch c { case '\n': r = r | "\\n" case '\r': r = r | "\\r" case '\t': r = r | "\\t" case '\\': r = r | "\\\\" case ' ': r = r | "\\s" default: r = r | string(s[i:i+1]) } } return r } func main() { args := getArgs() if len(args) < 2 { err("usage: mxlex \n") return } path := args[1] data, ok := readFile(path) if !ok { err("error: cannot read " | path | "\n") return } errh := func(line, col uint32, msg string) { err("E " | token.ItoaU32(line) | ":" | token.ItoaU32(col) | " " | msg | "\n") } var s syntax.Scanner s.InitBytes(data, errh, 0) for { s.Next() ln := token.ItoaU32(s.Line) cl := token.ItoaU32(s.Col) tok := s.Tok if tok == token.EOF { out(ln | ":" | cl | " EOF\n") break } switch tok { case token.NameType: out(ln | ":" | cl | " NAME " | s.Lit | "\n") case token.Literal: k := "?" switch s.Kind { case token.IntLit: k = "INT" case token.FloatLit: k = "FLOAT" case token.ImagLit: k = "IMAG" case token.RuneLit: k = "RUNE" case token.StringLit: k = "STRING" } out(ln | ":" | cl | " LIT:" | k | " " | escapeStr(s.Lit) | "\n") case token.OperatorType, token.AssignOp, token.IncOp: out(ln | ":" | cl | " OP " | s.Op.String() | "\n") case token.Semi: out(ln | ":" | cl | " SEMI\n") case token.Assign: out(ln | ":" | cl | " ASSIGN\n") case token.Define: out(ln | ":" | cl | " DEFINE\n") case token.Arrow: out(ln | ":" | cl | " ARROW\n") case token.Star: out(ln | ":" | cl | " STAR\n") default: out(ln | ":" | cl | " " | tok.String() | "\n") } } }