├── README.md ├── example ├── benri.ujm ├── fibonacci.ujm └── fizzbuzz.ujm ├── ujihisa.go └── ujm └── ujm.go /README.md: -------------------------------------------------------------------------------- 1 | # ujihisa 2 | 3 | 便利 4 | 5 | ## Technique Description 6 | 7 | This is clone of whitespace language. A space character is replaced to `便利`. A tab character is replaced to `感極まってきました`. 8 | 9 | ## Requirements 10 | 11 | golang 12 | 13 | ## Installation 14 | 15 | ``` 16 | $ go get github.com/mattn/ujihisa/ujm 17 | ``` 18 | 19 | ## Usage 20 | 21 | This code should display `1`. 22 | 23 | ``` 24 | 便利便利便利感極まってきました 25 | 感極まってきました 26 | 便利感極まってきました 27 | 28 | 29 | ``` 30 | 31 | 32 | ## License 33 | 34 | MIT 35 | 36 | ## Author 37 | 38 | Yasuhiro Matsumoto (a.k.a mattn) 39 | -------------------------------------------------------------------------------- /example/benri.ujm: -------------------------------------------------------------------------------- 1 | 便利便利便利感極まってきました感極まってきました感極まってきました感極まってきました便利便利感極まってきました 便利 便利 感極まってきました 便利 感極まってきました 便利 感極まってきました 2 | 便利便利便利感極まってきました 便利 便利感極まってきました便利便利便利 便利 感極まってきました 感極まってきました 便利 便利 便利 3 | 便利便利便利便利便利感極まってきました感極まってきました感極まってきました感極まってきました便利便利感極まってきました 4 | 便利便利 便利便利便利感極まってきました 便利便利便利感極まってきました 5 | 便利便利便利感極まってきました 感極まってきました便利便利便利 6 | 感極まってきました便利便利便利 感極まってきました便利便利便利感極まってきました便利便利便利感極まってきました便利便利便利 便利便利便利感極まってきました 便利 感極まってきました 感極まってきました 感極まってきました 感極まってきました 便利 7 | 便利便利便利 感極まってきました 便利 便利 8 | 感極まってきました便利便利便利 便利便利便利感極まってきました 感極まってきました 感極まってきました 便利 9 | 感極まってきました便利便利便利 便利便利便利感極まってきました 10 | 感極まってきました便利便利便利 感極まってきました便利便利便利 便利便利感極まってきました 感極まってきました 11 | 感極まってきました便利便利便利 感極まってきました 12 | 便利便利 便利便利便利感極まってきました 感極まってきました 感極まってきました 便利 便利 便利 感極まってきました 便利 便利感極まってきました 便利 便利 便利 便利 13 | 便利便利便利感極まってきました 便利便利感極まってきました 便利便利 便利感極まってきました 便利 便利 感極まってきました 便利 便利 14 | 便利便利便利 便利便利 感極まってきました便利感極まってきました便利 感極まってきました 便利便利 便利 便利便利 15 | 感極まってきました便利便利便利 便利便利便利感極まってきました 便利便利便利感極まってきました 便利 便利 感極まってきました 便利 便利 便利 16 | 便利便利便利感極まってきました 便利 便利 便利 感極まってきました便利 便利 便利 17 | 感極まってきました便利便利便利 便利便利便利感極まってきました便利 便利 18 | 感極まってきました便利便利便利便利便利便利感極まってきました 19 | 感極まってきました便利便利便利 感極まってきました便利便利便利 感極まってきました便利便利便利 感極まってきました 20 | 便利便利 21 | 22 | 23 | -------------------------------------------------------------------------------- /example/fibonacci.ujm: -------------------------------------------------------------------------------- 1 | 便利便利便利感極まってきました便利便利感極まってきました便利便利便利 2 | 感極まってきました 3 | 便利便利便利便利便利感極まってきました感極まってきました便利感極まってきました感極まってきました感極まってきました感極まってきました 4 | 感極まってきました 5 | 便利便利便利便利便利.感極まってきました感極まってきました感極まってきました便利感極まってきました感極まってきました感極まってきました 6 | 感極まってきました 7 | 便利便利便利便利便利感極まってきました便利便利便利便利便利 8 | 感極まってきました 9 | 便利便利便利便利便利感極まってきました感極まってきました便利感極まってきました感極まってきました便利感極まってきました 10 | 感極まってきました 11 | 便利便利便利便利便利感極まってきました感極まってきました便利便利便利便利感極まってきました 12 | 感極まってきました 13 | 便利便利便利便利便利感極まってきました感極まってきました便利感極まってきました感極まってきました感極まってきました便利 14 | 感極まってきました 15 | 便利便利便利便利便利感極まってきました感極まってきました感極まってきました感極まってきました便利便利感極まってきました 16 | 感極まってきました 17 | 便利便利便利便利便利感極まってきました感極まってきました感極まってきました感極まってきました感極まってきました感極まってきました 18 | 感極まってきました 19 | 便利便利便利便利便利感極まってきました便利便利便利便利便利 20 | 感極まってきました 21 | 便利便利便利便利便利感極まってきました便利 22 | 感極まってきました 23 | 感極まってきました感極まってきました便利便利便利便利 24 | 便利便利便利感極まってきました 25 | 便利 26 | 便利感極まってきました 27 | 便利感極まってきました便利便利便利感極まってきました便利感極まってきました便利 28 | 感極まってきました 29 | 便利便利 30 | 便利便利感極まってきました 31 | 便利 32 | 便利便利便利便利感極まってきました 33 | 便利 34 | 感極まってきました感極まってきました感極まってきました便利感極まってきました便利便利便利便利便利便利感極まってきました 35 | 感極まってきました感極まってきました感極まってきました便利 36 | 感極まってきました便利 37 | 便利感極まってきました 38 | 便利感極まってきました便利便利便利感極まってきました便利感極まってきました便利 39 | 感極まってきました 40 | 便利便利便利便利便利感極まってきました便利 41 | 感極まってきました感極まってきました感極まってきました便利便利便利感極まってきました 42 | 感極まってきました便利便利感極まってきました便利 43 | 便利便利便利便利感極まってきました便利 44 | 便利 45 | 感極まってきました感極まってきました感極まってきました便利 46 | 感極まってきました感極まってきました感極まってきました便利 47 | 48 | 便利 49 | 感極まってきました 50 | 51 | 便利便利感極まってきました便利 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /example/fizzbuzz.ujm: -------------------------------------------------------------------------------- 1 | 便利便利便利 2 | 3 | 便利便利便利 4 | 便利便利便利感極まってきました 5 | 感極まってきました便利便利便利便利 6 | 便利便利便利便利感極まってきました感極まってきました 7 | 感極まってきました便利感極まってきました感極まってきました 8 | 感極まってきました便利便利感極まってきました 9 | 便利 10 | 便利便利便利便利感極まってきました便利感極まってきました 11 | 感極まってきました便利感極まってきました感極まってきました 12 | 感極まってきました便利便利感極まってきました便利 13 | 便利 14 | 便利感極まってきました 15 | 便利感極まってきました 16 | 便利便利便利感極まってきました感極まってきました 17 | 便利便利便利感極まってきました便利感極まってきました便利 18 | 感極まってきました 19 | 便利便利便利 20 | 便利便利便利便利感極まってきました感極まってきました便利便利感極まってきました便利便利 21 | 感極まってきました便利便利感極まってきました 22 | 感極まってきました感極まってきました便利 23 | 24 | 25 | 26 | 27 | 便利便利便利感極まってきました 28 | 便利便利便利感極まってきました便利便利便利感極まってきました感極まってきました便利 29 | 便利 30 | 便利感極まってきました 31 | 便利便利便利便利便利感極まってきました便利便利便利感極まってきました感極まってきました 32 | 感極まってきました便利便利便利便利 33 | 便利感極まってきました 34 | 便利便利便利便利便利感極まってきました便利便利便利感極まってきました 35 | 感極まってきました便利便利便利便利 36 | 便利感極まってきました 37 | 便利便利感極まってきました 38 | 便利便利便利 39 | 便利便利便利便利感極まってきました便利感極まってきました 40 | 感極まってきました便利感極まってきました感極まってきました 41 | 感極まってきました便利便利感極まってきました便利 42 | 43 | 便利 44 | 便利感極まってきました感極まってきました 45 | 46 | 便利便利便利感極まってきました便利 47 | 便利便利便利感極まってきました便利便利便利便利感極まってきました便利 48 | 便利 49 | 便利感極まってきました 50 | 便利便利便利便利便利感極まってきました感極まってきました便利便利感極まってきました感極まってきました 51 | 感極まってきました便利便利便利便利 52 | 便利感極まってきました 53 | 便利便利便利便利便利感極まってきました便利感極まってきました 54 | 感極まってきました便利便利便利便利 55 | 便利感極まってきました 56 | 便利便利感極まってきました 57 | 便利便利 58 | 便利 59 | 便利感極まってきました感極まってきました 60 | -------------------------------------------------------------------------------- /ujihisa.go: -------------------------------------------------------------------------------- 1 | package ujihisa 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "fmt" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | type value interface{} 12 | 13 | func toInt(v value) int { 14 | if v, ok := v.(int); ok { 15 | return v 16 | } 17 | return 0 18 | } 19 | 20 | func toChar(v value) string { 21 | if v, ok := v.(int); ok { 22 | return string(rune(v)) 23 | } 24 | if v, ok := v.(rune); ok { 25 | return string(rune(v)) 26 | } 27 | return "" 28 | } 29 | 30 | func toString(v value) string { 31 | if v, ok := v.(string); ok { 32 | return v 33 | } 34 | if v, ok := v.(int); ok { 35 | return fmt.Sprint(v) 36 | } 37 | return "" 38 | } 39 | 40 | type VM struct { 41 | done bool 42 | code []byte 43 | pc int 44 | result value 45 | Debug bool 46 | } 47 | 48 | func NewVM() *VM { 49 | return &VM{ 50 | done: false, 51 | code: nil, 52 | pc: 0, 53 | result: nil, 54 | Debug: false, 55 | } 56 | } 57 | 58 | func (vm *VM) next() byte { 59 | c := vm.code[vm.pc] 60 | vm.pc++ 61 | return c 62 | } 63 | 64 | func (vm *VM) restart() { 65 | vm.pc = 0 66 | } 67 | 68 | func (vm *VM) reset() { 69 | vm.done = false 70 | } 71 | 72 | func (vm *VM) parse(s string) error { 73 | var bc []byte 74 | 75 | cmdA := "便利" 76 | cmdB := "感極まってきました" 77 | cmdN := "かなり" 78 | 79 | for len(s) > 0 { 80 | switch { 81 | case strings.HasPrefix(s, cmdA): 82 | bc = append(bc, 'A') 83 | s = s[len(cmdA):] 84 | case strings.HasPrefix(s, cmdB): 85 | bc = append(bc, 'B') 86 | s = s[len(cmdB):] 87 | case strings.HasPrefix(s, cmdN): 88 | bc = append(bc, 'N') 89 | s = s[len(cmdN):] 90 | case strings.HasPrefix(s, "\n"): 91 | bc = append(bc, 'C') 92 | s = s[1:] 93 | default: 94 | s = s[1:] 95 | } 96 | } 97 | vm.code = bc 98 | return nil 99 | } 100 | 101 | var bb int 102 | 103 | func (vm *VM) do(s string) bool { 104 | if vm.done { 105 | return false 106 | } 107 | 108 | var isLabel, isNumber bool 109 | 110 | if strings.HasSuffix(s, "l") { 111 | isLabel = true 112 | s = s[:len(s)-1] 113 | } 114 | if strings.HasSuffix(s, "n") { 115 | isNumber = true 116 | s = s[:len(s)-1] 117 | } 118 | 119 | code := string(vm.code[vm.pc : vm.pc+len(s)]) 120 | if code != s { 121 | return false 122 | } 123 | vm.pc += len(s) 124 | 125 | if isNumber { 126 | sign := -1 127 | if vm.next() == 'A' { 128 | sign = 1 129 | } 130 | num := 0 131 | for { 132 | c := vm.next() 133 | if c == 'C' { 134 | break 135 | } 136 | num *= 2 137 | if c == 'B' { 138 | num++ 139 | } 140 | } 141 | vm.result = sign * num 142 | } else if isLabel { 143 | var label []byte 144 | for { 145 | c := vm.next() 146 | if c == 'C' { 147 | break 148 | } 149 | label = append(label, c) 150 | } 151 | vm.result = string(label) 152 | } 153 | vm.done = true 154 | return true 155 | } 156 | 157 | func (vm *VM) Run(s string) error { 158 | var err error 159 | 160 | err = vm.parse(s) 161 | if err != nil { 162 | return err 163 | } 164 | 165 | if vm.Debug { 166 | fmt.Println("command list:", string(vm.code)) 167 | } 168 | 169 | stack := []value{} 170 | pcstack := []int{} 171 | heap := map[int]value{} 172 | last := -1 173 | 174 | cmds := []string{ 175 | "AAn", "ACA", "ACB", "ACC", 176 | "BAAA", "BAAB", "BAAC", "BABA", "BABB", 177 | "BBA", "BBB", 178 | "CAAl", "CABl", "CACl", "CBAl", "CBBl", "CBC", "CCC", 179 | "BCAA", "BCAB", "BCBA", "BCBB", 180 | "N", 181 | } 182 | labels := map[string]int{} 183 | 184 | for vm.pc < len(vm.code) { 185 | if last == vm.pc { 186 | if vm.pc != len(vm.code) - 1 || vm.code[vm.pc] != 'C' { 187 | return errors.New("Seems broken byte codes") 188 | } 189 | return nil 190 | } 191 | last = vm.pc 192 | vm.reset() 193 | for _, cmd := range cmds { 194 | pc := vm.pc 195 | if vm.do(cmd) { 196 | if cmd == "CAAl" { 197 | labels[toString(vm.result)] = vm.pc 198 | } 199 | if vm.Debug { 200 | fmt.Fprintf(os.Stderr, "position: %d command: %s\n", pc, cmd) 201 | } 202 | } 203 | } 204 | } 205 | vm.restart() 206 | 207 | last = -1 208 | for vm.pc < len(vm.code) { 209 | if last == vm.pc { 210 | return errors.New("Seems broken byte codes") 211 | } 212 | last = vm.pc 213 | 214 | if vm.Debug { 215 | fmt.Fprintf(os.Stderr, "position=%d\n", vm.pc) 216 | fmt.Fprintf(os.Stderr, "stack=%s\n", fmt.Sprint(stack)) 217 | } 218 | 219 | vm.reset() 220 | if vm.do("AAn") { 221 | stack = append(stack, vm.result) 222 | } 223 | if vm.do("ACA") { 224 | stack = append(stack, stack[len(stack)-1]) 225 | } 226 | if vm.do("ACB") { 227 | stack[len(stack)-2], stack[len(stack)-1] = stack[len(stack)-1], stack[len(stack)-2] 228 | } 229 | if vm.do("ACC") { 230 | stack = stack[:len(stack)-1] 231 | } 232 | if vm.do("BA") { 233 | left, right := stack[len(stack)-2], stack[len(stack)-1] 234 | stack = stack[:len(stack)-2] 235 | vm.reset() 236 | if vm.do("AA") { 237 | stack = append(stack, toInt(left)+toInt(right)) 238 | } 239 | if vm.do("AB") { 240 | stack = append(stack, toInt(left)-toInt(right)) 241 | } 242 | if vm.do("AC") { 243 | stack = append(stack, toInt(left)*toInt(right)) 244 | } 245 | if vm.do("BA") { 246 | stack = append(stack, toInt(left)/toInt(right)) 247 | } 248 | if vm.do("BB") { 249 | stack = append(stack, toInt(left)%toInt(right)) 250 | } 251 | continue 252 | } 253 | if vm.do("BBA") { 254 | index, value := toInt(stack[len(stack)-2]), stack[len(stack)-1] 255 | stack = stack[:len(stack)-2] 256 | heap[index] = value 257 | } 258 | if vm.do("BBB") { 259 | index := toInt(stack[len(stack)-1]) 260 | stack = stack[:len(stack)-1] 261 | stack = append(stack, heap[index]) 262 | } 263 | vm.do("CAAl") 264 | if vm.do("CABl") { 265 | pcstack = append(pcstack, vm.pc) 266 | vm.pc = labels[toString(vm.result)] 267 | } 268 | if vm.do("CACl") { 269 | vm.pc = labels[toString(vm.result)] 270 | } 271 | if vm.do("CBAl") { 272 | v := toInt(stack[len(stack)-1]) 273 | stack = stack[:len(stack)-1] 274 | if v == 0 { 275 | vm.pc = labels[toString(vm.result)] 276 | } 277 | } 278 | if vm.do("CBBl") { 279 | v := toInt(stack[len(stack)-1]) 280 | stack = stack[:len(stack)-1] 281 | if v < 0 { 282 | vm.pc = labels[toString(vm.result)] 283 | } 284 | } 285 | if vm.do("CBC") { 286 | addr := pcstack[len(pcstack)-1] 287 | pcstack = pcstack[:len(pcstack)-1] 288 | vm.pc = addr 289 | } 290 | if vm.do("CCC") { 291 | return nil 292 | } 293 | if vm.do("BCAA") { 294 | c := toChar(stack[len(stack)-1]) 295 | stack = stack[:len(stack)-1] 296 | fmt.Print(c) 297 | } 298 | if vm.do("BCAB") { 299 | n := stack[len(stack)-1].(int) 300 | stack = stack[:len(stack)-1] 301 | fmt.Print(n) 302 | } 303 | if vm.do("BCBA") { 304 | r, _, err := bufio.NewReader(os.Stdin).ReadRune() 305 | if err != nil { 306 | return err 307 | } 308 | addr := stack[len(stack)-1].(int) 309 | stack = stack[:len(stack)-1] 310 | heap[addr] = string(rune(r)) 311 | } 312 | if vm.do("BCBB") { 313 | var n int 314 | _, err := fmt.Scan(&n) 315 | if err != nil { 316 | return err 317 | } 318 | addr := stack[len(stack)-1].(int) 319 | stack = stack[:len(stack)-1] 320 | heap[addr] = n 321 | } 322 | if vm.do("N") { 323 | fmt.Println("かなり") 324 | } 325 | } 326 | return nil 327 | } 328 | -------------------------------------------------------------------------------- /ujm/ujm.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | 9 | "github.com/mattn/ujihisa" 10 | ) 11 | 12 | var debug = flag.Bool("d", false, "debug") 13 | 14 | func main() { 15 | flag.Parse() 16 | var f *os.File = os.Stdin 17 | var err error 18 | var b []byte 19 | 20 | switch { 21 | case flag.NArg() == 0: 22 | b, err = ioutil.ReadAll(f) 23 | case flag.NArg() == 1: 24 | b, err = ioutil.ReadFile(flag.Arg(0)) 25 | default: 26 | flag.Usage() 27 | os.Exit(1) 28 | } 29 | 30 | if err == nil { 31 | vm := ujihisa.NewVM() 32 | vm.Debug = *debug 33 | err = vm.Run(string(b)) 34 | } 35 | if err != nil { 36 | fmt.Fprintln(os.Stderr, err) 37 | os.Exit(1) 38 | } 39 | } 40 | --------------------------------------------------------------------------------