├── .DS_Store ├── .all-contributorsrc ├── LICENSE ├── README.md ├── examples ├── 99bears.umm ├── addition_calculator.umm ├── evenodd.umm ├── factorial_calculator.umm ├── gugudan.umm ├── helloworld.umm ├── pyramid.umm ├── sqrt.umm ├── string_test.umm └── tree.umm ├── setup.py ├── umjunsik-lang-cc ├── .gitignore ├── Makefile └── src │ ├── file.c │ ├── file.h │ ├── info.h │ ├── main.c │ ├── parse.c │ ├── parse.h │ ├── string.c │ └── string.h ├── umjunsik-lang-csharp ├── .gitignore ├── Program.cs ├── umjunsik-lang-csharp.csproj └── umjunsik-lang-csharp.sln ├── umjunsik-lang-deno ├── index.ts └── readme.md ├── umjunsik-lang-go ├── ast │ └── ast.go ├── eval │ ├── eval.go │ └── util.go ├── go.mod ├── lexer │ └── lexer.go ├── main.go ├── object │ └── object.go ├── parser │ ├── parser.go │ └── util.go └── token │ └── token.go ├── umjunsik-lang-java ├── .DS_Store ├── main.java └── setting │ ├── .DS_Store │ ├── Count.java │ ├── Items.java │ ├── console │ ├── ChangeUni.java │ ├── Print.java │ └── Scan.java │ └── var │ ├── VarGet.java │ └── VarSet.java ├── umjunsik-lang-kotlin ├── build.gradle.kts ├── gradle.properties ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ └── com │ └── alphagot │ └── kumjunsiklang │ ├── Main.kt │ └── ParseUtils.kt ├── umjunsik-lang-node ├── .gitignore ├── package.json ├── src │ └── index.ts ├── tsconfig.json └── yarn.lock ├── umjunsik-lang-python ├── __init__.py ├── __main__.py └── runtime.py ├── umjunsik-lang-rust ├── .gitignore ├── Cargo.toml ├── README.md ├── compiler │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── interpreter │ ├── Cargo.toml │ └── src │ │ └── main.rs └── lib │ ├── Cargo.toml │ └── src │ ├── ast.rs │ ├── lib.rs │ └── parser.rs ├── umjunsik-lang-vba ├── Module1.vb ├── README.md ├── Sheet1.vb ├── ThisWorkbook.vb └── interpreter.xlsm └── umjunsik-lang-web ├── index.html └── src ├── main.css ├── main.js └── vendors └── pico ├── pico.min.css └── pico.min.css.map /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rycont/umjunsik-lang/e973f9d22b9803ee86b53d8e60f1b65ab08c7547/.DS_Store -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "cstria0106", 10 | "name": "goorm", 11 | "avatar_url": "https://avatars1.githubusercontent.com/u/11474150?v=4", 12 | "profile": "https://github.com/cstria0106", 13 | "contributions": [ 14 | "platform" 15 | ] 16 | }, 17 | { 18 | "login": "pl-Steve28-lq", 19 | "name": "Steve28", 20 | "avatar_url": "https://avatars2.githubusercontent.com/u/64412954?v=4", 21 | "profile": "https://github.com/pl-Steve28-lq", 22 | "contributions": [ 23 | "platform" 24 | ] 25 | }, 26 | { 27 | "login": "pmh-only", 28 | "name": "PMH", 29 | "avatar_url": "https://avatars2.githubusercontent.com/u/39158228?v=4", 30 | "profile": "https://trinets.xyz", 31 | "contributions": [ 32 | "platform" 33 | ] 34 | }, 35 | { 36 | "login": "AkiaCode", 37 | "name": "Aki", 38 | "avatar_url": "https://avatars0.githubusercontent.com/u/71239005?v=4", 39 | "profile": "https://github.com/AkiaCode", 40 | "contributions": [ 41 | "code" 42 | ] 43 | }, 44 | { 45 | "login": "Tim232", 46 | "name": "Tim232", 47 | "avatar_url": "https://avatars1.githubusercontent.com/u/64291996?v=4", 48 | "profile": "https://info.tim23.me", 49 | "contributions": [ 50 | "code" 51 | ] 52 | }, 53 | { 54 | "login": "Ign0reLee", 55 | "name": "JeYoung", 56 | "avatar_url": "https://avatars.githubusercontent.com/u/46403849?v=4", 57 | "profile": "https://github.com/Ign0reLee", 58 | "contributions": [ 59 | "code" 60 | ] 61 | }, 62 | { 63 | "login": "Rokr0k", 64 | "name": "Rok", 65 | "avatar_url": "https://avatars.githubusercontent.com/u/35794170?v=4", 66 | "profile": "http://rokr0k.tk", 67 | "contributions": [ 68 | "platform" 69 | ] 70 | }, 71 | { 72 | "login": "adp-study", 73 | "name": "adp-study", 74 | "avatar_url": "https://avatars.githubusercontent.com/u/59760424?v=4", 75 | "profile": "https://github.com/adp-study", 76 | "contributions": [ 77 | "infra", 78 | "bug" 79 | ] 80 | }, 81 | { 82 | "login": "noname0310", 83 | "name": "noname", 84 | "avatar_url": "https://avatars.githubusercontent.com/u/48761044?v=4", 85 | "profile": "https://www.youtube.com/c/noname0310", 86 | "contributions": [ 87 | "code" 88 | ] 89 | }, 90 | { 91 | "login": "TralocDheckoa", 92 | "name": "TralocDheckoa", 93 | "avatar_url": "https://avatars.githubusercontent.com/u/42158095?v=4", 94 | "profile": "https://github.com/TralocDheckoa", 95 | "contributions": [ 96 | "code" 97 | ] 98 | }, 99 | { 100 | "login": "sangchoo1201", 101 | "name": "sangchoo1201", 102 | "avatar_url": "https://avatars.githubusercontent.com/u/75765800?v=4", 103 | "profile": "https://github.com/sangchoo1201", 104 | "contributions": [ 105 | "bug" 106 | ] 107 | }, 108 | { 109 | "login": "shs3182ym", 110 | "name": "Sukuna Shinmyoumaru", 111 | "avatar_url": "https://avatars.githubusercontent.com/u/56759376?v=4", 112 | "profile": "http://warning.or.kr", 113 | "contributions": [ 114 | "platform" 115 | ] 116 | }, 117 | { 118 | "login": "alvin1007", 119 | "name": "Yeong Jae Cho", 120 | "avatar_url": "https://avatars.githubusercontent.com/u/77112874?v=4", 121 | "profile": "https://github.com/alvin1007", 122 | "contributions": [ 123 | "platform" 124 | ] 125 | }, 126 | { 127 | "login": "kiwiyou", 128 | "name": "kiwiyou", 129 | "avatar_url": "https://avatars.githubusercontent.com/u/12986388?v=4", 130 | "profile": "http://kiwiyou.dev", 131 | "contributions": [ 132 | "platform" 133 | ] 134 | }, 135 | { 136 | "login": "kyle-seongwoo-jun", 137 | "name": "Kyle Seongwoo Jun", 138 | "avatar_url": "https://avatars.githubusercontent.com/u/16515307?v=4", 139 | "profile": "https://seongxwoo.notion.site/Kyle-b49a1520f7ea4d5a86acedcf201129f6", 140 | "contributions": [ 141 | "infra" 142 | ] 143 | }, 144 | { 145 | "login": "sean9892", 146 | "name": "Yubin Choi", 147 | "avatar_url": "https://avatars.githubusercontent.com/u/46587635?v=4", 148 | "profile": "https://github.com/sean9892", 149 | "contributions": [ 150 | "example" 151 | ] 152 | }, 153 | { 154 | "login": "Baekjoon", 155 | "name": "Baekjoon Choi", 156 | "avatar_url": "https://avatars.githubusercontent.com/u/706317?v=4", 157 | "profile": "https://www.acmicpc.net", 158 | "contributions": [ 159 | "infra" 160 | ] 161 | }, 162 | { 163 | "login": "EGGnmad", 164 | "name": "ㅇㅂㅎ", 165 | "avatar_url": "https://avatars.githubusercontent.com/u/93484785?v=4", 166 | "profile": "https://eggnmad.com/info/", 167 | "contributions": [ 168 | "example" 169 | ] 170 | }, 171 | { 172 | "login": "pizzaroot", 173 | "name": "pizzaroot", 174 | "avatar_url": "https://avatars.githubusercontent.com/u/17989599?v=4", 175 | "profile": "https://github.com/pizzaroot", 176 | "contributions": [ 177 | "platform" 178 | ] 179 | }, 180 | { 181 | "login": "depth221", 182 | "name": "Dongha Hwang", 183 | "avatar_url": "https://avatars.githubusercontent.com/u/22697167?v=4", 184 | "profile": "https://luxurycoop.tistory.com/", 185 | "contributions": [ 186 | "example", 187 | "bug" 188 | ] 189 | }, 190 | { 191 | "login": "PersesTitan", 192 | "name": "PersesTitan", 193 | "avatar_url": "https://avatars.githubusercontent.com/u/97427878?v=4", 194 | "profile": "https://github.com/PersesTitan", 195 | "contributions": [ 196 | "platform", 197 | "bug" 198 | ] 199 | }, 200 | { 201 | "login": "kongchu2", 202 | "name": "JunHyeok Hong", 203 | "avatar_url": "https://avatars.githubusercontent.com/u/48686444?v=4", 204 | "profile": "http://codeup.kr/userinfo.php?user=qwerty5233", 205 | "contributions": [ 206 | "doc" 207 | ] 208 | }, 209 | { 210 | "login": "happy-spark", 211 | "name": "happy-spark", 212 | "avatar_url": "https://avatars.githubusercontent.com/u/107300540?v=4", 213 | "profile": "https://github.com/happy-spark", 214 | "contributions": [ 215 | "example" 216 | ] 217 | }, 218 | { 219 | "login": "kms0219kms", 220 | "name": "Minsu Kim", 221 | "avatar_url": "https://avatars.githubusercontent.com/u/67222970?v=4", 222 | "profile": "https://sskate.me", 223 | "contributions": [ 224 | "platform", 225 | "design" 226 | ] 227 | }, 228 | { 229 | "login": "jerryjungwh", 230 | "name": "JerryJung", 231 | "avatar_url": "https://avatars.githubusercontent.com/u/16649567?v=4", 232 | "profile": "https://www.youtube.com/@comgongbro", 233 | "contributions": [ 234 | "doc" 235 | ] 236 | }, 237 | { 238 | "login": "Hiyabye", 239 | "name": "Jihoon Lee", 240 | "avatar_url": "https://avatars.githubusercontent.com/u/50550999?v=4", 241 | "profile": "https://github.com/Hiyabye", 242 | "contributions": [ 243 | "doc" 244 | ] 245 | } 246 | ], 247 | "contributorsPerLine": 7, 248 | "projectName": "umjunsik-lang", 249 | "projectOwner": "rycont", 250 | "repoType": "github", 251 | "repoHost": "https://github.com", 252 | "skipCi": true, 253 | "commitConvention": "angular", 254 | "commitType": "docs" 255 | } 256 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 rycont 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 엄랭 2 | 3 | 엄랭은 세계 최초의 인물이름으로 만들어진 난해한 프로그래밍 언어입니다. 엄준식이 어떻게 인물 이름이냐고요? 그러게요ㅋㅋ 어떻게 엄준식이 어떻게 사람 이름이지ㅋㅋ "엄준식 사람이름인데요" 4 | 5 | > 어디선가 유입이 자꾸 들어오고 있는것같은데.. 혹시 시간 되신다면 어디쪽 링크 통해서 들어오셨는지 기재 부탁드리겠습니다. [어떻게 엄랭을 발견하셨나요..!](https://github.com/rycont/umjunsik-lang/issues/1) 6 | 7 | ![](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https://github.com/rycont/umjunsik-lang) 8 | 9 | 10 | ``` 11 | 어떻게 12 | 13 | 엄식? 14 | 어엄식? 15 | 16 | 동탄어?준... .... 17 | 18 | 엄어, 19 | 어엄어어. 20 | 21 | 준.. ... 22 | 식어어! 23 | 24 | 이 사람이름이냐ㅋㅋ 25 | ``` 26 | 27 | [cjaewon/umlang](https://github.com/cjaewon/umlang)에 영감을 받아 제작되었습니다 28 | 29 | **주의: Umlang 표기는 위의 프로젝트와 겹치기 때문에, 꼭 한글로만 표기해주세요.** 30 | 영문표기를 해야할때는 "umjunsik-lang"이라고 표기해주세요. 31 | 32 | ## 엄 on Live! 33 | - 코딩애플: [엄준식 프로그래밍 언어 (어떤 놈이 만들었냐)](https://www.youtube.com/watch?v=G0psQ54f5zE) 34 | - 컴공선배: [엄랭 어떤 놈이 만들었냐? 어떤 놈 만났습니다.](https://youtu.be/NS56sb6EYIw) 35 | - 코딩애플: [chatGPT는 엄준식 프로그래밍 언어도 잘할까?](https://www.youtube.com/watch?v=SdDs0ScOFSU) 36 | 37 | # 구현체 38 | + [류갓 WebIDE에서 엄랭을 실행할 수 있습니다](https://www.ryugod.com/) 39 | 40 | - [디노 (v2)](https://github.com/rycont/umjunsik-lang/tree/master/umjunsik-lang-deno) : 레퍼런스 런타임입니다 41 | - [노드JS (v2)](https://github.com/rycont/umjunsik-lang/tree/master/umjunsik-lang-node) : Deno 구현체의 NodeJS 포트버전입니다. 42 | - [파이썬 (v2)](https://github.com/rycont/umjunsik-lang/tree/master/umjunsik-lang-python) 43 | - pip에서 `umjunsik` 패키지를 설치할 수 있습니다 44 | - `$ pip install umjunsik && umjunsik [filename.umm]` 45 | - [웹-엄 (v2)](https://github.com/rycont/umjunsik-lang/tree/master/umjunsik-lang-web) : [kms0219kms](https://github.com/kms0219kms)님이 [호스팅해주시고 있습니다🎉](https://umjunsik-lang.devayaan.me/) 46 | - [C (v2)](https://github.com/rycont/umjunsik-lang/tree/master/umjunsik-lang-cc) 47 | - [C# (v2)](https://github.com/rycont/umjunsik-lang/tree/master/umjunsik-lang-csharp) 48 | - [코틀린 (v2)](https://github.com/rycont/umjunsik-lang/tree/master/umjunsik-lang-kotlin) 49 | - [Go (v2)](https://github.com/rycont/umjunsik-lang/tree/master/umjunsik-lang-go) : 실제 인터프리터 구조를 차용하여 개발한 고급 런타임입니다 50 | - [러스트 (v2)](https://github.com/rycont/umjunsik-lang/tree/master/umjunsik-lang-rust) 51 | 52 | 53 | # Contributors ✨ 54 | 55 | [![All Contributors](https://img.shields.io/badge/all_contributors-26-orange.svg?style=flat-square)](#contributors-) 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
goorm
goorm

📦
Steve28
Steve28

📦
PMH
PMH

📦
Aki
Aki

💻
Tim232
Tim232

💻
JeYoung
JeYoung

💻
Rok
Rok

📦
adp-study
adp-study

🚇 🐛
noname
noname

💻
TralocDheckoa
TralocDheckoa

💻
sangchoo1201
sangchoo1201

🐛
Sukuna Shinmyoumaru
Sukuna Shinmyoumaru

📦
Yeong Jae Cho
Yeong Jae Cho

📦
kiwiyou
kiwiyou

📦
Kyle Seongwoo Jun
Kyle Seongwoo Jun

🚇
Yubin Choi
Yubin Choi

💡
Baekjoon Choi
Baekjoon Choi

🚇
ㅇㅂㅎ
ㅇㅂㅎ

💡
pizzaroot
pizzaroot

📦
Dongha Hwang
Dongha Hwang

💡 🐛
PersesTitan
PersesTitan

📦 🐛
JunHyeok Hong
JunHyeok Hong

📖
happy-spark
happy-spark

💡
Minsu Kim
Minsu Kim

📦 🎨
JerryJung
JerryJung

📖
Jihoon Lee
Jihoon Lee

📖
99 | 100 | 101 | 102 | 103 | 104 | 105 | # 문법 106 | 107 | 엄랭은 "엄", "준", "식", "동탄" 네개의 키워드와 "!", ".", " ", "~", "ㅋ" 다섯개의 기호로 코드가 이루어집니다. 108 | 모든 프로그램은 "어떻게"로 시작하며, 항상 "이 사람이름이냐ㅋㅋ"로 끝나야 합니다. 109 | 110 | ## 자료형 111 | 112 | 정수: 온점, 반점의 갯수로 나타냅니다. 온점의 갯수만큼 1을 더하며, 반점의 갯수만큼 1을 뺍니다. 113 | 114 | ``` 115 | ... => 3 116 | .. => 2 117 | ,, => -2 118 | ,,, => -3 119 | .,., => 0 120 | ``` 121 | 122 | ## 연산자 123 | 124 | - 1 증가: `.` 125 | - 1 감소: `,` 126 | - 곱하기: " "(공백) 127 | 128 | ``` 129 | .. -> 2 130 | ,, -> -2 131 | ., -> 0 132 | .. .. -> 4 133 | .. ,, -> -4 134 | ... ... ... -> 27 135 | ``` 136 | 137 | ## 변수 138 | 139 | 변수는 인덱싱(정수)을 통해 접근하고 대입할 수 있습니다. 지정하지 않았을경우 모든 변수의 기본값은 0입니다. 140 | 141 | ### 대입(엄) 142 | 143 | 연음의 갯수번째 변수에 뒤에 오는 수를 대입합니다 144 | 145 | ``` 146 | 어어엄 => 3번째 변수에 0 지정 147 | 어엄 => 2번째 변수에 0 지정 148 | 엄.. => 1번째 변수에 2 지정 149 | 어엄. => 2번째 변수에 1 지정 150 | 엄,,, => 1번째 변수에 -3 지정 151 | ``` 152 | 153 | ### 사용(어) 154 | 155 | 연음의 갯수번째 변수를 불러옵니다 156 | 157 | ``` 158 | 어 => 1번째 변수 159 | 어어 => 2번째 변수 160 | 어어어 => 3번째 변수 161 | ``` 162 | 163 | ### 초안/미구현 : N번째 변수에 대입 (엌ㅋ) 164 | 165 | `엌`과 `ㅋ` 사이에 입력된 수 번째의 변수에 뒤에 오는 수를 대입합니다. 시작하는 엌은 `엌ㅋㅋㅋㅋㅋㅋㅋㅋ` 등으로, 끝내는 ㅋ는 `ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ` 등으로 늘려서 적을 수 있으며, 이에 따른 동작의 변화는 없습니다. 166 | 167 | ``` 168 | 엌..ㅋ => 2번째 변수에 0 지정 169 | 엌ㅋㅋㅋㅋㅋ..ㅋㅋㅋㅋㅋ. => 2번째 변수에 1 지정 170 | 엌.ㅋ어 => 1번쨰 변수에 `어`값 지정 171 | 엌어ㅋ어어 => `어`번째 변수에 `어어` 변수의 값 지정 172 | ``` 173 | 174 | ### 초안/미구현 : N번쨰 변수 가져오기 175 | 176 | `어`와 `ㅋ` 사이에 입력된 수 번째의 변수의 값을 가져옵니다. 만약 마지막 문자가 `ㅋ`이 아니라 `엌`이라면 `어ㅋ`으로 분해해서 평가합니다. 끝내는 ㅋ은 `ㅋㅋㅋㅋㅋ`등으로 늘려서 적을 수 있으며, 이에 따른 동작의 변화는 없습니다. 177 | 178 | ``` 179 | 어..ㅋ => 2번째 변수 180 | 어,,,ㅋ => -3번째 변수 181 | 어엌 => 어어ㅋ => `어`번째 변수 182 | 어어어,,ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ => (어어 - 2)번째 변수 183 | ``` 184 | ### 초안/미구현 : 변수연산 185 | 186 | 변수 / 상수 덧셈식 뒤에 변수를 이어적으면 뒤에 따르는 변수를 더할 수 있습니다. 사칙연산의 우선순위가 적용되지 않으며, 무조건 왼쪽에서부터 연산합니다. 187 | 188 | ``` 189 | 어, 어어 => 어 - 1 * 어어 => 어 - 어어 190 | 어.어어 => 어 + 1 + 어어 191 | 어어. 어어 => 어어 + 1 * 어어 => 어어 + 어어 192 | 어어 어어 어어 => 어어 ^ 3 193 | ``` 194 | 195 | ~~정신나갈것같아요~~ 196 | 197 | ## 콘솔 198 | 199 | ### 식? 200 | 201 | 콘솔에서 정수를 입력받습니다. 202 | 203 | ``` 204 | 엄식? => 콘솔을 입력받아서 1번째 변수에 대입한다. 205 | 어엄식? => 콘솔을 입력받아서 2번째 변수에 대입한다. 206 | ``` 207 | 208 | ### 식! 209 | 210 | 콘솔에 정수를 출력합니다. 211 | 212 | ```tsx 213 | 식..! => 콘솔에 2 출력 214 | 식어! => 콘솔에 첫번째 변수 출력 215 | ``` 216 | 217 | ### 식ㅋ 218 | 219 | 콘솔에 문자를 출력합니다. `식`과 `ㅋ`사이에 오는 정수를 유니코드 문자로 변환하여 콘솔에 출력합니다. `식`과 `ㅋ`사이에 정수가 주어지지 않으면 개행합니다(`식ㅋ` => `\n`) 220 | 221 | ```tsx 222 | 식........... ........ㅋ => 콘솔에 X 출력 223 | ``` 224 | 225 | ## 지시문 226 | 227 | ### 동탄? 228 | 229 | `동탄{정수}?{실행할 명령}`으로 작성합니다. 정수가 0이라면 `실행할 명령`이 실행되며, 그렇지 않다면 다음줄로 넘어갑니다. 230 | 231 | ### 준 232 | 233 | `준` 뒤에 오는 정수번째 줄로 이동합니다. `준.. => 2번째 줄(글자)로 이동`. 원라인코드의 경우에는 `~`로 분리된 코드단위로 카운트하여 이동합니다. 234 | 235 | ### 화이팅! 236 | 237 | `화이팅!`뒤에 오는 정수를 반환하며 프로그램을 종료합니다. 238 | 239 | ## 기타 240 | 241 | - 확장자는 `.umm`입니다. 242 | - One-line 작성은 `\n`을 `~`로 치환합니다. (예제: 구구단 참조) 243 | 244 | # 예제 245 | 246 | [위키를 참조해주세요](https://github.com/rycont/umjunsik-lang/wiki) 247 | 248 | # To-Do 249 | - [ ] gnex-umjunsik [What is Gnex?](https://github.com/rycont/Gnex) 250 | - [x] ~~웹-엄~~ 251 | - [x] ~~엄랭파이썬~~ 252 | 253 | # History 254 | 255 | - 20200626 0030 : 엄랭 공개 256 | - 20200626 0855 : 엄랭 문서 완성 257 | - 20200625 1256 : 엄랭 Deno 구현체 배포 258 | - 20200804 : 엄랭v2 259 | 1. 모든 콘솔 출력은 인라인 260 | 1. `화이팅!` 후에 오는 문자열을 반환하며 프로그램이 종료 261 | 1. 새 문법 추가: `식ㅋ` 262 | 1. 새 문법 추가: `동탄?` 263 | 1. `화이팅!`의 명세 변경 264 | - 20200805 : 문서 개정 265 | 1. `동탄?` 설명 추가 266 | 1. `화이팅!` 설명 변경 267 | 1. 지시문들을 별도의 단락으로 분리 268 | - 20200912 : 99병의 맥주 예제 269 | - 20200915 : 엄랭v2-엄랭노드 구현체 배포 270 | - 20201017 : 엄랭v2-파이썬 구현체 배포 by [Steve28](https://github.com/pl-Steve28-lq) 271 | - 20201105 : 웹-엄: 자바스크립트로 된 엄랭 처리기(웹런타임) 배포 by [PMH](https://github.com/pmh-only) 272 | - 20210530 : 엄씨(엄랭-C 컴파일러) 배포 by [Rok](https://github.com/Rokr0k) 273 | - 20210809 : 엄랭 C# 구현체 배포 by [noname0310](https://github.com/noname0310) 274 | - 20220201 : 엄랭 코틀린 구현체 배포 by [shs3182ym](https://github.com/shs3182ym) 275 | - 20220203 : 엄랭 Go 구현체 배포 by [alvin1007](https://github.com/alvin1007) 276 | - 20220203 : 엄랭 러스트 구현체 배포 by [kiwiyou](https://github.com/kiwiyou) 277 | - 20220207 : 엄랭v3 초안 작성중 278 | 1. N번째 변수 접근 / 대입 표현 279 | 1. 변수간 덧셈연산 280 | -------------------------------------------------------------------------------- /examples/addition_calculator.umm: -------------------------------------------------------------------------------- 1 | 어떻게 2 | 3 | 엄식? 4 | 어엄식? 5 | 6 | 동탄어?준... .... 7 | 8 | 엄어, 9 | 어엄어어. 10 | 11 | 준.. ... 12 | 식어어! 13 | 14 | 이 사람이름이냐ㅋㅋ 15 | -------------------------------------------------------------------------------- /examples/evenodd.umm: -------------------------------------------------------------------------------- 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 | 이 사람이름이냐ㅋㅋ -------------------------------------------------------------------------------- /examples/factorial_calculator.umm: -------------------------------------------------------------------------------- 1 | 어떻게 2 | 3 | 엄. 4 | 어엄식? 5 | 6 | 동탄어어?준................. 7 | 8 | 엄어 어어 9 | 어엄어어, 10 | 11 | 동탄어어?준....... .. 12 | 준...... 13 | 14 | 식어! 15 | 준...... ... 16 | 17 | 식.! 18 | 19 | 화이팅.,! 20 | 이 사람이름이냐ㅋㅋ -------------------------------------------------------------------------------- /examples/gugudan.umm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /examples/helloworld.umm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /examples/pyramid.umm: -------------------------------------------------------------------------------- 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 | 61 | 준.. .. .. .. .. 62 | 63 | 화이팅!., 64 | 65 | 이 사람이름이냐ㅋㅋ 66 | -------------------------------------------------------------------------------- /examples/sqrt.umm: -------------------------------------------------------------------------------- 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 | 어엄... ... ........... 61 | 어어어어어어어어어어엄어어어어 62 | 어어엄어어어어 63 | 동탄어어?준.. .. .. ... ... 64 | 동탄어어어?준.. .. ................. 65 | 어어어어어어어어어어엄어어어어어어어어어어어. 66 | 어어엄어어어, 67 | 준.. .. .. .. .. .. 68 | 어엄어어, 69 | 준.. ............................... 70 | 71 | 72 | 어엄., 73 | 어어엄어어어어어어 74 | 어어어엄어어 75 | 동탄어어어어?준.. .. .. .. ..... 76 | 어어엄어어어. 77 | 어어어엄어어어어, 78 | 준... ..... ..... 79 | 80 | 어어어어어어어엄어어어 81 | 어어어어엄어어어 82 | 동탄어어?준.. .. ............................... 83 | 어어어어어어어어엄어어, 84 | 동탄어어어어어어어어어?준.. ............................................... 85 | 동탄어어어어어어어어?준... ... .. ..... 86 | 어어어어어어어엄어어어어어어어어, 87 | 어어어어엄어어어어어. 88 | 준..... ................. 89 | 90 | 어어어어어어어어엄어어어어어어어어어, 91 | 어어어어어어어엄어어어 92 | 준.. .. ... ....... 93 | 94 | 어어어어어어어어어어어엄어어어어어어어어어어어 95 | 동탄어어어어어어어어어어어어?준.. .. ..... ..... 96 | 동탄어어어어어?준.. ... ................... 97 | 어어어어어어어어어어어엄어어어어어어어어어어어어, 98 | 어어어어엄어어어어어, 99 | 준..... ................... 100 | 동탄어어어어어?준... ... ............. 101 | 어엄어어, 102 | 식어어! 103 | 어어어엄어어어어어어어어어어어어어 104 | 어어엄어어어, 105 | 동탄어어?준.. ..... ........... 106 | 어엄어어, 107 | 어어엄어어어. 108 | 준..... ... ....... 109 | 110 | 어어어어어어어어어어어어어엄어어어어어어어어어어어어어어, 111 | 동탄어어어어어어어어어어어어어어?화이팅!., 112 | 어어어어어엄어어어 113 | 준... .. .. .. .. 114 | 115 | 116 | 어어어어어어어어어어어어엄어어어어어어어어어어어어 117 | 어엄어어. 118 | 준......................................................................... 119 | 120 | 식어어! 121 | 화이팅!., 122 | 123 | 124 | 어어어어엄., 125 | 준.. ............................................... 126 | 127 | 128 | 동탄어어어어어?어어어어어엄어어어어어어. 129 | 식어어어어어어! 130 | 화이팅!., 131 | 이 사람이름이냐ㅋㅋ -------------------------------------------------------------------------------- /examples/string_test.umm: -------------------------------------------------------------------------------- 1 | 어떻게 2 | 엄.. 3 | 엄어 .. 4 | 엄어 .. 5 | 엄어 ........... 6 | 식어ㅋ 7 | 이 사람이름이냐ㅋㅋ 8 | -------------------------------------------------------------------------------- /examples/tree.umm: -------------------------------------------------------------------------------- 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 | 식어ㅋ 61 | 62 | 준... ................... 63 | 64 | 식어어어ㅋ 65 | 66 | 식ㅋ 67 | 68 | 어어어어엄어어어어어..... 69 | 동탄어어어어어?준....... ........... 70 | 어어어어엄어어어어어, 71 | 72 | 어어어어어엄어어어어어어. 73 | 74 | 어어어어어어엄어어어어어어어. 75 | 76 | 준... ....................... 77 | 78 | 동탄어어어어어어어?준.. .. ... ....... 79 | 어어어어어어엄어어어어어어어, 80 | 81 | 어어어어엄어어어어어. 82 | 83 | 준.. ... ............. 84 | 어어어어어어엄어어어어어어어. 85 | 86 | 87 | 동탄어어어어어?준.. ............................................................................... 88 | 89 | 동탄어어어어어어?준................................................................................................. 90 | 어어어어어엄어어어어어어, 91 | 92 | 어어어어어어어엄어어어어어어어어. 93 | 94 | 어어어어어어어어엄어어어어어어어어어. 95 | 96 | 준......................................................................................... 97 | 98 | 동탄어어어어어어어어어?준.. .. .. ............. 99 | 어어어어어어어어엄어어어어어어어어어, 100 | 101 | 어어어어어엄어어어어어어. 102 | 103 | 준.. ....... ....... 104 | 105 | 동탄어어어어어어?준... ..................................... 106 | 어어어어어엄어어어어어어, 107 | 108 | 식어ㅋ 109 | 110 | 준... ..... ....... 111 | 112 | 동탄어어어어어어어어?준.. ........................................................... 113 | 어어어어어어어엄어어어어어어어어, 114 | 115 | 어어어어어엄어어어어어어. 116 | 117 | 준.. .. .. .. ....... 118 | 119 | 동탄어어어어어어어?준............................................................................................................................... 120 | 121 | 어어어어어어어엄어어어어어어어어. 122 | 123 | 어어어어어어어어엄어어어어어어어어어. 124 | 125 | 어어어어어어엄어어어어어어어, 126 | 준....... ................. 127 | 128 | 동탄어어어어어어어어어?준.. ................................................................... 129 | 어어어어어어어어엄어어어어어어어어어, 130 | 131 | 어어어어어어엄어어어어어어어. 132 | 133 | 준.. .. .. .. .. .. .. 134 | 135 | 동탄어어어어어어어?준... ............................................... 136 | 어어어어어어엄어어어어어어어, 137 | 138 | 식어어ㅋ 139 | 140 | 준... ... ... ..... 141 | 142 | 동탄어어어어어어어어?준.. .. ..................................... 143 | 어어어어어어어엄어어어어어어어어, 144 | 145 | 어어어어어어엄어어어어어어어. 146 | 147 | 준.. ....................................................................... 148 | 149 | 어어어어어어엄어어어어어어어.. 150 | 151 | 어어어어어엄어어어어어어, 152 | 153 | 어어어어엄어어어어어, 154 | 155 | 식ㅋ 156 | 157 | 준... ............................. 158 | 어어어어엄어어어어어........ 159 | 동탄어어어어어?준... ..... ........... 160 | 어어어어엄어어어어어, 161 | 162 | 어어어어어엄어어어어어어......... 163 | 164 | 준... ..................................................... 165 | 어어어어엄어어어어어... 166 | 167 | 어어어어어엄어어어어어어. 168 | 169 | 동탄어어어어어?준.. .. .. ....................... 170 | 어어어어엄어어어어어, 171 | 172 | 식어ㅋ 173 | 식어ㅋ 174 | 식어ㅋ 175 | 식어ㅋ 176 | 177 | 식어어어어어어ㅋ 178 | 식어어어어어어ㅋ 179 | 식어어어어어어ㅋ 180 | 181 | 식ㅋ 182 | 183 | 준............. ............. 184 | 185 | 화이팅!., 186 | 187 | 이 사람이름이냐ㅋㅋ 188 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name="umjunsik", 5 | version="2.0.2", 6 | packages=find_packages(), 7 | entry_points={ 8 | "console_scripts": [ 9 | "umjunsik=umjunsik-lang-python.__main__:main", 10 | ], 11 | }, 12 | author="rycont", 13 | author_email="rycont@outlook.kr", 14 | description="어떻게 엄준식이 언어이름이냐🤣", 15 | long_description=open("../README.md", "r", encoding="UTF-8").read(), 16 | long_description_content_type="text/markdown", 17 | url="https://github.com/rycont/umjunsik-lang", 18 | classifiers=[ 19 | "Intended Audience :: Developers", 20 | "License :: OSI Approved :: MIT License", 21 | "Programming Language :: Python :: 3", 22 | "Programming Language :: Python :: 3.7", 23 | "Programming Language :: Python :: 3.8", 24 | "Programming Language :: Python :: 3.9", 25 | "Programming Language :: Python :: 3.10", 26 | ], 27 | ) -------------------------------------------------------------------------------- /umjunsik-lang-cc/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.s 3 | *.S 4 | bin/ -------------------------------------------------------------------------------- /umjunsik-lang-cc/Makefile: -------------------------------------------------------------------------------- 1 | C_SOURCES = $(wildcard src/*.c) 2 | HEADERS = $(wildcard src/*.h) 3 | OBJ = $(C_SOURCES:src/%.c=bin/%.o) 4 | 5 | CC = gcc 6 | CFLAGS = -Wall 7 | 8 | TARGET = bin/umcc 9 | 10 | ${TARGET}: ${OBJ} 11 | ${CC} ${CFLAGS} $^ -o $@ 12 | 13 | bin/%.o: src/%.c ${HEADERS} bin 14 | ${CC} ${CFLAGS} -c $< -o $@ 15 | 16 | bin: 17 | mkdir bin 18 | 19 | clean: 20 | rm -rf ${OBJ} ${TARGET} bin -------------------------------------------------------------------------------- /umjunsik-lang-cc/src/file.c: -------------------------------------------------------------------------------- 1 | #include "file.h" 2 | #include 3 | 4 | void moveFile(char *_Old, char *_New) { 5 | FILE *old = fopen(_Old, "r"); 6 | FILE *new = fopen(_New, "w"); 7 | 8 | char c; 9 | while((c = fgetc(old)) != EOF) { 10 | fputc(c, new); 11 | } 12 | 13 | fclose(old); 14 | fclose(new); 15 | 16 | remove(_Old); 17 | } -------------------------------------------------------------------------------- /umjunsik-lang-cc/src/file.h: -------------------------------------------------------------------------------- 1 | #ifndef FILE_H 2 | #define FILE_H 3 | 4 | void moveFile(char *_Old, char *_New); 5 | 6 | #endif -------------------------------------------------------------------------------- /umjunsik-lang-cc/src/info.h: -------------------------------------------------------------------------------- 1 | #ifndef INFO_H 2 | #define INFO_H 3 | 4 | #define HELP_S \ 5 | "Usage: umcc [options] file...\n" \ 6 | "Options:\n" \ 7 | " -h | --help Display this helpful text :)\n" \ 8 | " -v | --version Display compiler information.\n" \ 9 | " -o Place the output into .\n" \ 10 | " -c Compile to C source file.\n" \ 11 | " -s Compile to assembly source file.\n" \ 12 | "\n" \ 13 | "For bug report, please contact\n" \ 14 | ".\n" 15 | #define VERSION_S \ 16 | "umcc 1.1\n" \ 17 | "Copyright (C) 2022 Rok\n" \ 18 | "\n" \ 19 | "umjunsik-lang\n" \ 20 | "Copyright (C) 2022 Rycont\n" 21 | 22 | #define SRC 0x1 23 | #define ASM 0x2 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /umjunsik-lang-cc/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #ifdef __unix__ 5 | #include 6 | #endif 7 | #include "info.h" 8 | #include "parse.h" 9 | #include "string.h" 10 | #include "file.h" 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | FILE *input = NULL; 15 | FILE *output = NULL; 16 | int mode = 0; 17 | char input_path[4096] = {0}; 18 | char output_path[4096] = {0}; 19 | char command[8500] = {0}; 20 | int i; 21 | for (i = 1; i < argc; i++) 22 | { 23 | if (argv[i][0] == '-') 24 | { 25 | if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) 26 | { 27 | fprintf(stdout, HELP_S); 28 | exit(0); 29 | } 30 | else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) 31 | { 32 | fprintf(stdout, VERSION_S); 33 | exit(0); 34 | } 35 | else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) 36 | { 37 | strcpy(output_path, argv[++i]); 38 | } 39 | else if (strcmp(argv[i], "-c") == 0) 40 | { 41 | mode = SRC; 42 | } 43 | else if (strcmp(argv[i], "-s") == 0) 44 | { 45 | mode = ASM; 46 | } 47 | else 48 | { 49 | fprintf(stderr, "어떻게 이게 옵션이냐ㅋㅋ\n"); 50 | exit(1); 51 | } 52 | } 53 | else 54 | { 55 | strcpy(input_path, argv[i]); 56 | } 57 | } 58 | if (input_path[0] == 0) 59 | { 60 | fprintf(stderr, "어떻게 파일 이름이 없냐ㅋㅋ\n"); 61 | exit(1); 62 | } 63 | if (strcmp(strrchr(input_path, '.'), ".umm")) 64 | { 65 | fprintf(stderr, "어떻게 %s가 umm파일이냐ㅋㅋ\n", strrchr(input_path, '.')); 66 | exit(1); 67 | } 68 | input = fopen(input_path, "r"); 69 | if (input == NULL) 70 | { 71 | fprintf(stderr, "어떻게 %s가 파일 이름이냐ㅋㅋ\n", input_path); 72 | exit(1); 73 | } 74 | #ifdef __unix__ 75 | fseek(input, 0L, SEEK_END); 76 | long l = ftell(input); 77 | rewind(input); 78 | char *text = malloc(sizeof(char) * l + 1); 79 | memset(text, 0, sizeof(char) * l + 1); 80 | fread(text, sizeof(char), l, input); 81 | fclose(input); 82 | int ispipe = 1; 83 | 84 | switch (mode) 85 | { 86 | case SRC: 87 | if (output_path[0] == 0) 88 | { 89 | strcpy(output_path, strrchr(input_path, '/') + 1); 90 | strcpy(strrchr(output_path, '.'), ".c"); 91 | } 92 | output = fopen(output_path, "w"); 93 | ispipe = 0; 94 | break; 95 | case ASM: 96 | if (output_path[0] == 0) 97 | { 98 | strcpy(output_path, strrchr(input_path, '/') + 1); 99 | strcpy(strrchr(output_path, '.'), ".s"); 100 | } 101 | sprintf(command, "gcc -S -x c - -o \"%s\"", output_path); 102 | output = popen(command, "w"); 103 | break; 104 | default: 105 | if (output_path[0] == 0) 106 | { 107 | strcpy(output_path, "a.out"); 108 | } 109 | sprintf(command, "gcc -x c - -o \"%s\"", output_path); 110 | output = popen(command, "w"); 111 | break; 112 | } 113 | if (parse(text, output)) 114 | { 115 | fprintf(stderr, "어떻게 이 코드가 엄랭이냐ㅋㅋ\n"); 116 | free(text); 117 | ispipe ? pclose(output) : fclose(output); 118 | remove(output_path); 119 | exit(1); 120 | } 121 | free(text); 122 | ispipe ? pclose(output) : fclose(output); 123 | #else 124 | char temp_path[4096] = {0}; 125 | strcpy(temp_path, strrchr(input_path, '/') + 1); 126 | strcpy(strrchr(temp_path, '.'), ".c"); 127 | fseek(input, 0L, SEEK_END); 128 | long l = ftell(input); 129 | rewind(input); 130 | char *text = malloc(sizeof(char) * l + 1); 131 | memset(text, 0, sizeof(char) * l + 1); 132 | fread(text, sizeof(char), l, input); 133 | fclose(input); 134 | output = fopen(temp_path, "w"); 135 | if (parse(text, output)) 136 | { 137 | fprintf(stderr, "어떻게 이 코드가 엄랭이냐ㅋㅋ\n"); 138 | free(text); 139 | fclose(output); 140 | remove(temp_path); 141 | exit(1); 142 | } 143 | free(text); 144 | fclose(output); 145 | switch (mode) 146 | { 147 | case SRC: 148 | if (output_path[0]) 149 | { 150 | moveFile(temp_path, output_path); 151 | remove(temp_path); 152 | } 153 | break; 154 | case ASM: 155 | if (output_path[0] == 0) 156 | { 157 | strcpy(output_path, strrchr(input_path, '/') + 1); 158 | strcpy(strrchr(output_path, '.'), ".s"); 159 | } 160 | sprintf(command, "gcc -S \"%s\" -o \"%s\"", temp_path, output_path); 161 | system(command); 162 | remove(temp_path); 163 | break; 164 | default: 165 | if (output_path[0] == 0) 166 | { 167 | sprintf(command, "gcc \"%s\"", temp_path); 168 | } 169 | else 170 | { 171 | sprintf(command, "gcc \"%s\" -o \"%s\"", temp_path, output_path); 172 | } 173 | system(command); 174 | remove(temp_path); 175 | break; 176 | } 177 | #endif 178 | return 0; 179 | } -------------------------------------------------------------------------------- /umjunsik-lang-cc/src/parse.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include 3 | #include 4 | #include "string.h" 5 | 6 | char **splitLines(char *text) { 7 | size_t nc=1, i, j, k; 8 | for(i=0; text[i]; i++) { 9 | if(text[i] == '\n' || text[i] == '~') { 10 | nc++; 11 | } 12 | } 13 | char **lines = malloc(sizeof(char *)*(nc+1)); 14 | for(i=0, j=0; i\n" 129 | "#include\n" 130 | "#define JUN(n) switch(n){"); 131 | for(i=1; i 5 | 6 | int parse(char *text, FILE *output); 7 | 8 | #endif -------------------------------------------------------------------------------- /umjunsik-lang-cc/src/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | size_t stridx(const char *_Str, const char *_Target) { 4 | size_t l = strlen(_Target); 5 | size_t i, j; 6 | int flag; 7 | for(i=0; _Str[i]; i++) { 8 | flag = 1; 9 | for(j=0; j 5 | 6 | size_t stridx(const char *_Str1, const char *_Str2); 7 | int strstt(const char *_Str1, const char *_Str2); 8 | void strsub(char *_Des, const char *_Str, size_t _Idx, size_t _Len); 9 | 10 | #endif -------------------------------------------------------------------------------- /umjunsik-lang-csharp/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/csharp 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=csharp 4 | 5 | ### Csharp ### 6 | ## Ignore Visual Studio temporary files, build results, and 7 | ## files generated by popular Visual Studio add-ons. 8 | ## 9 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 10 | 11 | # User-specific files 12 | *.rsuser 13 | *.suo 14 | *.user 15 | *.userosscache 16 | *.sln.docstates 17 | 18 | # User-specific files (MonoDevelop/Xamarin Studio) 19 | *.userprefs 20 | 21 | # Mono auto generated files 22 | mono_crash.* 23 | 24 | # Build results 25 | [Dd]ebug/ 26 | [Dd]ebugPublic/ 27 | [Rr]elease/ 28 | [Rr]eleases/ 29 | x64/ 30 | x86/ 31 | [Ww][Ii][Nn]32/ 32 | [Aa][Rr][Mm]/ 33 | [Aa][Rr][Mm]64/ 34 | bld/ 35 | [Bb]in/ 36 | [Oo]bj/ 37 | [Ll]og/ 38 | [Ll]ogs/ 39 | 40 | # Visual Studio 2015/2017 cache/options directory 41 | .vs/ 42 | # Uncomment if you have tasks that create the project's static files in wwwroot 43 | #wwwroot/ 44 | 45 | # Visual Studio 2017 auto generated files 46 | Generated\ Files/ 47 | 48 | # MSTest test Results 49 | [Tt]est[Rr]esult*/ 50 | [Bb]uild[Ll]og.* 51 | 52 | # NUnit 53 | *.VisualState.xml 54 | TestResult.xml 55 | nunit-*.xml 56 | 57 | # Build Results of an ATL Project 58 | [Dd]ebugPS/ 59 | [Rr]eleasePS/ 60 | dlldata.c 61 | 62 | # Benchmark Results 63 | BenchmarkDotNet.Artifacts/ 64 | 65 | # .NET Core 66 | project.lock.json 67 | project.fragment.lock.json 68 | artifacts/ 69 | 70 | # ASP.NET Scaffolding 71 | ScaffoldingReadMe.txt 72 | 73 | # StyleCop 74 | StyleCopReport.xml 75 | 76 | # Files built by Visual Studio 77 | *_i.c 78 | *_p.c 79 | *_h.h 80 | *.ilk 81 | *.meta 82 | *.obj 83 | *.iobj 84 | *.pch 85 | *.pdb 86 | *.ipdb 87 | *.pgc 88 | *.pgd 89 | *.rsp 90 | *.sbr 91 | *.tlb 92 | *.tli 93 | *.tlh 94 | *.tmp 95 | *.tmp_proj 96 | *_wpftmp.csproj 97 | *.log 98 | *.tlog 99 | *.vspscc 100 | *.vssscc 101 | .builds 102 | *.pidb 103 | *.svclog 104 | *.scc 105 | 106 | # Chutzpah Test files 107 | _Chutzpah* 108 | 109 | # Visual C++ cache files 110 | ipch/ 111 | *.aps 112 | *.ncb 113 | *.opendb 114 | *.opensdf 115 | *.sdf 116 | *.cachefile 117 | *.VC.db 118 | *.VC.VC.opendb 119 | 120 | # Visual Studio profiler 121 | *.psess 122 | *.vsp 123 | *.vspx 124 | *.sap 125 | 126 | # Visual Studio Trace Files 127 | *.e2e 128 | 129 | # TFS 2012 Local Workspace 130 | $tf/ 131 | 132 | # Guidance Automation Toolkit 133 | *.gpState 134 | 135 | # ReSharper is a .NET coding add-in 136 | _ReSharper*/ 137 | *.[Rr]e[Ss]harper 138 | *.DotSettings.user 139 | 140 | # TeamCity is a build add-in 141 | _TeamCity* 142 | 143 | # DotCover is a Code Coverage Tool 144 | *.dotCover 145 | 146 | # AxoCover is a Code Coverage Tool 147 | .axoCover/* 148 | !.axoCover/settings.json 149 | 150 | # Coverlet is a free, cross platform Code Coverage Tool 151 | coverage*.json 152 | coverage*.xml 153 | coverage*.info 154 | 155 | # Visual Studio code coverage results 156 | *.coverage 157 | *.coveragexml 158 | 159 | # NCrunch 160 | _NCrunch_* 161 | .*crunch*.local.xml 162 | nCrunchTemp_* 163 | 164 | # MightyMoose 165 | *.mm.* 166 | AutoTest.Net/ 167 | 168 | # Web workbench (sass) 169 | .sass-cache/ 170 | 171 | # Installshield output folder 172 | [Ee]xpress/ 173 | 174 | # DocProject is a documentation generator add-in 175 | DocProject/buildhelp/ 176 | DocProject/Help/*.HxT 177 | DocProject/Help/*.HxC 178 | DocProject/Help/*.hhc 179 | DocProject/Help/*.hhk 180 | DocProject/Help/*.hhp 181 | DocProject/Help/Html2 182 | DocProject/Help/html 183 | 184 | # Click-Once directory 185 | publish/ 186 | 187 | # Publish Web Output 188 | *.[Pp]ublish.xml 189 | *.azurePubxml 190 | # Note: Comment the next line if you want to checkin your web deploy settings, 191 | # but database connection strings (with potential passwords) will be unencrypted 192 | *.pubxml 193 | *.publishproj 194 | 195 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 196 | # checkin your Azure Web App publish settings, but sensitive information contained 197 | # in these scripts will be unencrypted 198 | PublishScripts/ 199 | 200 | # NuGet Packages 201 | *.nupkg 202 | # NuGet Symbol Packages 203 | *.snupkg 204 | # The packages folder can be ignored because of Package Restore 205 | **/[Pp]ackages/* 206 | # except build/, which is used as an MSBuild target. 207 | !**/[Pp]ackages/build/ 208 | # Uncomment if necessary however generally it will be regenerated when needed 209 | #!**/[Pp]ackages/repositories.config 210 | # NuGet v3's project.json files produces more ignorable files 211 | *.nuget.props 212 | *.nuget.targets 213 | 214 | # Microsoft Azure Build Output 215 | csx/ 216 | *.build.csdef 217 | 218 | # Microsoft Azure Emulator 219 | ecf/ 220 | rcf/ 221 | 222 | # Windows Store app package directories and files 223 | AppPackages/ 224 | BundleArtifacts/ 225 | Package.StoreAssociation.xml 226 | _pkginfo.txt 227 | *.appx 228 | *.appxbundle 229 | *.appxupload 230 | 231 | # Visual Studio cache files 232 | # files ending in .cache can be ignored 233 | *.[Cc]ache 234 | # but keep track of directories ending in .cache 235 | !?*.[Cc]ache/ 236 | 237 | # Others 238 | ClientBin/ 239 | ~$* 240 | *~ 241 | *.dbmdl 242 | *.dbproj.schemaview 243 | *.jfm 244 | *.pfx 245 | *.publishsettings 246 | orleans.codegen.cs 247 | 248 | # Including strong name files can present a security risk 249 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 250 | #*.snk 251 | 252 | # Since there are multiple workflows, uncomment next line to ignore bower_components 253 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 254 | #bower_components/ 255 | 256 | # RIA/Silverlight projects 257 | Generated_Code/ 258 | 259 | # Backup & report files from converting an old project file 260 | # to a newer Visual Studio version. Backup files are not needed, 261 | # because we have git ;-) 262 | _UpgradeReport_Files/ 263 | Backup*/ 264 | UpgradeLog*.XML 265 | UpgradeLog*.htm 266 | ServiceFabricBackup/ 267 | *.rptproj.bak 268 | 269 | # SQL Server files 270 | *.mdf 271 | *.ldf 272 | *.ndf 273 | 274 | # Business Intelligence projects 275 | *.rdl.data 276 | *.bim.layout 277 | *.bim_*.settings 278 | *.rptproj.rsuser 279 | *- [Bb]ackup.rdl 280 | *- [Bb]ackup ([0-9]).rdl 281 | *- [Bb]ackup ([0-9][0-9]).rdl 282 | 283 | # Microsoft Fakes 284 | FakesAssemblies/ 285 | 286 | # GhostDoc plugin setting file 287 | *.GhostDoc.xml 288 | 289 | # Node.js Tools for Visual Studio 290 | .ntvs_analysis.dat 291 | node_modules/ 292 | 293 | # Visual Studio 6 build log 294 | *.plg 295 | 296 | # Visual Studio 6 workspace options file 297 | *.opt 298 | 299 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 300 | *.vbw 301 | 302 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 303 | *.vbp 304 | 305 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 306 | *.dsw 307 | *.dsp 308 | 309 | # Visual Studio 6 technical files 310 | 311 | # Visual Studio LightSwitch build output 312 | **/*.HTMLClient/GeneratedArtifacts 313 | **/*.DesktopClient/GeneratedArtifacts 314 | **/*.DesktopClient/ModelManifest.xml 315 | **/*.Server/GeneratedArtifacts 316 | **/*.Server/ModelManifest.xml 317 | _Pvt_Extensions 318 | 319 | # Paket dependency manager 320 | .paket/paket.exe 321 | paket-files/ 322 | 323 | # FAKE - F# Make 324 | .fake/ 325 | 326 | # CodeRush personal settings 327 | .cr/personal 328 | 329 | # Python Tools for Visual Studio (PTVS) 330 | __pycache__/ 331 | *.pyc 332 | 333 | # Cake - Uncomment if you are using it 334 | # tools/** 335 | # !tools/packages.config 336 | 337 | # Tabs Studio 338 | *.tss 339 | 340 | # Telerik's JustMock configuration file 341 | *.jmconfig 342 | 343 | # BizTalk build output 344 | *.btp.cs 345 | *.btm.cs 346 | *.odx.cs 347 | *.xsd.cs 348 | 349 | # OpenCover UI analysis results 350 | OpenCover/ 351 | 352 | # Azure Stream Analytics local run output 353 | ASALocalRun/ 354 | 355 | # MSBuild Binary and Structured Log 356 | *.binlog 357 | 358 | # NVidia Nsight GPU debugger configuration file 359 | *.nvuser 360 | 361 | # MFractors (Xamarin productivity tool) working folder 362 | .mfractor/ 363 | 364 | # Local History for Visual Studio 365 | .localhistory/ 366 | 367 | # Visual Studio History (VSHistory) files 368 | .vshistory/ 369 | 370 | # BeatPulse healthcheck temp database 371 | healthchecksdb 372 | 373 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 374 | MigrationBackup/ 375 | 376 | # Ionide (cross platform F# VS Code tools) working folder 377 | .ionide/ 378 | 379 | # Fody - auto-generated XML schema 380 | FodyWeavers.xsd 381 | 382 | # VS Code files for those working on multiple tools 383 | .vscode/* 384 | !.vscode/settings.json 385 | !.vscode/tasks.json 386 | !.vscode/launch.json 387 | !.vscode/extensions.json 388 | *.code-workspace 389 | 390 | # Local History for Visual Studio Code 391 | .history/ 392 | 393 | # Windows Installer files from build outputs 394 | *.cab 395 | *.msi 396 | *.msix 397 | *.msm 398 | *.msp 399 | 400 | # JetBrains Rider 401 | *.sln.iml 402 | 403 | # End of https://www.toptal.com/developers/gitignore/api/csharp -------------------------------------------------------------------------------- /umjunsik-lang-csharp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Collections.Generic; 5 | 6 | Bootstrap(/*"../../../../examples/pyramid.umm");//*/args[0]); 7 | 8 | void Bootstrap(string filePath) 9 | { 10 | try 11 | { 12 | if (File.Exists(filePath)) 13 | Run(File.ReadAllText(filePath)); 14 | } 15 | catch (IOException) 16 | { 17 | throw new Exception($"{filePath}가 어떻게 파일이름이냐ㅋㅋ"); 18 | } 19 | }; 20 | 21 | void Run (string content) { 22 | var proceed = content.TrimEnd().Split("\n").Select(x => x.Trim()).ToArray(); 23 | if (!(proceed[0] == "어떻게" && proceed[^1] == "이 사람이름이냐ㅋㅋ")) 24 | throw new Exception("어떻게 이 코드가 엄랭이냐ㅋㅋ"); 25 | var variables = new Dictionary(); 26 | if (content.Contains("~")) proceed = content.Split("~"); 27 | var pointer = 1; 28 | 29 | while (proceed[pointer] != "이 사람이름이냐ㅋㅋ") 30 | { 31 | var operation = proceed[pointer++]; 32 | var evaludated = ParseOperation(operation); 33 | if (evaludated != null) 34 | Environment.Exit(evaludated.Value); 35 | } 36 | 37 | int? ParseOperation(string operation) 38 | { 39 | if (operation.Contains("동탄") && operation.Contains("?")) 40 | { 41 | var condition = Numberify( 42 | SubStringJs(operation, 2, operation.LastIndexOf("?") + 1) 43 | ); 44 | if (condition == 0) 45 | return ParseOperation(operation.Substring(operation.LastIndexOf("?") + 1)); 46 | return null; 47 | } 48 | if (operation.Contains('엄')) 49 | { 50 | var a = operation.Split('엄'); 51 | var variablePointer = operation.Split('엄')[0].Count(x => x == '어'); 52 | var setteeValue = Numberify(operation.Split('엄')[1]); 53 | if (variables.ContainsKey(variablePointer)) 54 | variables[variablePointer] = setteeValue; 55 | else 56 | variables.Add(variablePointer, setteeValue); 57 | } 58 | if (operation.Contains('식') && operation[^1] == '!') 59 | Console.Write(Numberify(operation[1..^1])); 60 | if (operation.Contains('식') && operation[^1] == 'ㅋ') 61 | { 62 | if (operation == "식ㅋ") Console.WriteLine(); 63 | Console.Write((char)Numberify(operation[1..^1])); 64 | } 65 | if (operation.Contains('준')) 66 | { 67 | pointer = Numberify(operation.Split('준')[1]) - 1; 68 | } 69 | if (operation.IndexOf("화이팅!") == 0) 70 | return Numberify(operation.Split("화이팅!")[1]); 71 | return null; 72 | 73 | int Numberify(string a) 74 | { 75 | var numbered = 0; 76 | if (a.Contains(" ")) 77 | return a.Split(" ").Select(x => Numberify(x)).Aggregate((a, b) => a * b); 78 | if (a.Contains("식?")) 79 | a = a.Replace("식?", string.Concat(Enumerable.Repeat(".", int.Parse(Console.ReadLine())))); 80 | 81 | var index = a.Count(x => x == '어') - 1; 82 | if (variables.ContainsKey(index)) 83 | if (a.Contains('어')) numbered += variables[index]; 84 | if (a.Contains('.')) numbered += a.Count(x => x == '.'); 85 | if (a.Contains(',')) numbered -= a.Count(x => x == ','); 86 | return numbered; 87 | } 88 | 89 | string SubStringJs(string str, int from, int to) 90 | { 91 | if (from == to) return string.Empty; 92 | if (to < from) 93 | { 94 | var t = from; 95 | from = to; 96 | to = t; 97 | } 98 | return str.Substring(from, to - from); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /umjunsik-lang-csharp/umjunsik-lang-csharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | umjunsik_lang_csharp 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /umjunsik-lang-csharp/umjunsik-lang-csharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31507.150 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "umjunsik-lang-csharp", "umjunsik-lang-csharp.csproj", "{53CAE929-82BE-4F94-8A57-9F8CCF2C375A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {53CAE929-82BE-4F94-8A57-9F8CCF2C375A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {53CAE929-82BE-4F94-8A57-9F8CCF2C375A}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {53CAE929-82BE-4F94-8A57-9F8CCF2C375A}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {53CAE929-82BE-4F94-8A57-9F8CCF2C375A}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {4801A51B-6747-4D82-A84A-2074C45AB231} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /umjunsik-lang-deno/index.ts: -------------------------------------------------------------------------------- 1 | import { readLines } from "https://deno.land/std@v0.68.0/io/bufio.ts"; 2 | 3 | export const run = async (content: string) => { 4 | let proceed = content.split("\n"); 5 | const encoder = new TextEncoder(); 6 | if ( 7 | !(proceed[0] === "어떻게" && proceed.slice(-1)[0] === "이 사람이름이냐!") 8 | ) { 9 | new Error("어떻게 이 코드가 엄랭이냐ㅋㅋ"); 10 | } 11 | const variables: number[] = []; 12 | if (content.includes("~")) proceed = content.split("~"); 13 | let pointer = 0; 14 | const numberify = async (a: string): Promise => { 15 | let numbered = 0; 16 | if (a.includes(" ")) 17 | return (await Promise.all(a.split(" ").map(numberify))).reduce( 18 | (a, b) => a * b 19 | ); 20 | if (a.includes("식?")) { 21 | for await (const line of readLines(Deno.stdin)) { 22 | a = a.replace("식?", ".".repeat(Number(line))); 23 | break; 24 | } 25 | } 26 | if (a.includes("어")) numbered += variables[a.split("어").length - 1]; 27 | if (a.includes(".")) numbered += a.split(".").length - 1; 28 | if (a.includes(",")) numbered -= a.split(",").length - 1; 29 | return numbered; 30 | }; 31 | const stringify = (unicode: number) => { 32 | return String.fromCharCode(unicode); 33 | }; 34 | 35 | const parseOperation = async ( 36 | operation: string 37 | ): Promise => { 38 | if (operation.includes("동탄") && operation.includes("?")) { 39 | //IFGOTO 40 | const condition = await numberify( 41 | operation.substring(2, operation.lastIndexOf("?") + 1) 42 | ); 43 | if (condition === 0) { 44 | return parseOperation(operation.substr(operation.lastIndexOf("?") + 1)); 45 | } 46 | return; 47 | } 48 | if (operation.includes("엄")) { 49 | const variablePointer = operation.split("엄")[0].split("어").length; 50 | const setteeValue = await numberify(operation.split("엄")[1]); 51 | variables[variablePointer] = setteeValue; 52 | } 53 | if (operation.includes("식") && operation[operation.length - 1] === "!") { 54 | await Deno.stdout.write( 55 | encoder.encode(String(await numberify(operation.slice(1, -1)))) 56 | ); 57 | } 58 | if (operation.includes("식") && operation[operation.length - 1] === "ㅋ") { 59 | if (operation === "식ㅋ") console.log(); 60 | await Deno.stdout.write( 61 | encoder.encode(stringify(await numberify(operation.slice(1, -1)))) 62 | ); 63 | } 64 | if (operation.includes("준")) { 65 | pointer = (await numberify(operation.split("준")[1])) - 1; 66 | } 67 | if (operation.indexOf("화이팅!") === 0) { 68 | return numberify(operation.split("화이팅!")[1]); 69 | } 70 | }; 71 | 72 | while (proceed[pointer] !== "이 사람이름이냐!") { 73 | const operation = proceed[pointer++]; 74 | const evaludated = await parseOperation(operation); 75 | if (evaludated) return evaludated; 76 | } 77 | }; 78 | 79 | const bootstrap = async (filepath: string) => { 80 | try { 81 | if (await Deno.stat(filepath)) run(await Deno.readTextFile(filepath)); 82 | } catch (e) { 83 | new Error(`${filepath}가 어떻게 파일이름이냐ㅋㅋ`); 84 | } 85 | }; 86 | 87 | if (Deno.args[0]) bootstrap(Deno.args[0]); 88 | -------------------------------------------------------------------------------- /umjunsik-lang-deno/readme.md: -------------------------------------------------------------------------------- 1 | # 엄랭 Deno 구현체 2 | 3 | ## How to run? 4 | 5 | `deno run --allow-read --unstable .\index.ts filename` 6 | 7 | ## 업데이트 로그 8 | 9 | - 20200625 : 엄랭v1-엄랭디노v2 10 | - 엄랭디노의 첫 버전입니다 11 | - 20200804 : 엄랭v2-엄랭디노v2 12 | - **엄랭v2 변경점 반영** 13 | - `,` 키워드가 정상적으로 작동하지 않는 이슈 해결 14 | - `while` 안에 인라인으로 작성되었던 코드분석 코드를 `parseOperation`함수로 분리 15 | - `어떻게`로 시작하고 `이 사람이름이냐!`로 끝나야만 실행되어야했지만, 그 반대여서 어떤 프로그램도 실행하지 못했던 오류 수정 16 | - 20200805 : 엄랭v2-엄랭디노v2.1 17 | - 전까지는 두 수의 곱셈만 가능했지만, 이제는 공백으로 연결된 수많은 수를 곱할 수 있습니다 18 | - 20200912 : 엄랭v2-엄랭디노v2.1.1 19 | - 여러 디노 버전에 대응하기 위해 std/fs 의존성 제거 20 | - 이하 변경사항은 code styling 21 | -------------------------------------------------------------------------------- /umjunsik-lang-go/ast/ast.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "bytes" 5 | "strconv" 6 | "umjunsik-lang/umjunsik-lang-go/token" 7 | ) 8 | 9 | type Node interface { 10 | TokenLiteral() string 11 | String() string 12 | } 13 | 14 | type Line interface { 15 | Node 16 | lineNode() 17 | } 18 | 19 | type Expression interface { 20 | Node 21 | expressionNode() 22 | } 23 | 24 | type Program struct { 25 | Lines []Line 26 | } 27 | 28 | func (p *Program) TokenLiteral() string { 29 | if len(p.Lines) > 0 { 30 | return p.Lines[0].TokenLiteral() 31 | } else { 32 | return "" 33 | } 34 | } 35 | 36 | func (p *Program) String() string { 37 | var out bytes.Buffer 38 | 39 | for i, s := range p.Lines { 40 | out.WriteString(strconv.Itoa(i) + ". ") 41 | out.WriteString(s.String()) 42 | out.WriteString("\n") 43 | } 44 | 45 | return out.String() 46 | } 47 | 48 | type ExpressionLine struct { 49 | Token token.Token 50 | Expression Expression 51 | } 52 | 53 | func (el *ExpressionLine) lineNode() {} 54 | func (el *ExpressionLine) TokenLiteral() string { return el.Token.Literal } 55 | func (el *ExpressionLine) String() string { 56 | if el.Expression != nil { 57 | return el.Expression.String() 58 | } 59 | return "" 60 | } 61 | 62 | type InfixIntegerExpression struct { 63 | Token token.Token 64 | Left Expression 65 | Right int64 66 | } 67 | 68 | func (ie *InfixIntegerExpression) expressionNode() {} 69 | func (ie *InfixIntegerExpression) TokenLiteral() string { return ie.Token.Literal } 70 | func (ie *InfixIntegerExpression) String() string { 71 | var out bytes.Buffer 72 | 73 | out.WriteString("(") 74 | out.WriteString(ie.Left.String()) 75 | out.WriteString(" + " + strconv.Itoa(int(ie.Right))) 76 | out.WriteString(")") 77 | 78 | return out.String() 79 | } 80 | 81 | type SPACEExpression struct { 82 | Token token.Token 83 | Left Expression 84 | Right Expression 85 | } 86 | 87 | func (se *SPACEExpression) expressionNode() {} 88 | func (se *SPACEExpression) TokenLiteral() string { return se.Token.Literal } 89 | func (se *SPACEExpression) String() string { 90 | var out bytes.Buffer 91 | 92 | out.WriteString("(") 93 | out.WriteString(se.Left.String()) 94 | out.WriteString(" * " + se.Right.String()) 95 | out.WriteString(")") 96 | 97 | return out.String() 98 | } 99 | 100 | type IntegerLiteral struct { 101 | Token token.Token 102 | Value int64 103 | } 104 | 105 | func (il *IntegerLiteral) expressionNode() {} 106 | func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal } 107 | func (il *IntegerLiteral) String() string { 108 | var out bytes.Buffer 109 | 110 | for i := 0; i < int(il.Value); i++ { 111 | out.WriteString(".") 112 | } 113 | 114 | for i := 0; i > int(il.Value); i-- { 115 | out.WriteString(",") 116 | } 117 | 118 | return out.String() 119 | } 120 | 121 | type UEpxression struct { 122 | Token token.Token 123 | Index int64 124 | } 125 | 126 | func (ue *UEpxression) expressionNode() {} 127 | func (ue *UEpxression) TokenLiteral() string { return ue.Token.Literal } 128 | func (ue *UEpxression) String() string { 129 | var out bytes.Buffer 130 | 131 | for i := 0; i < int(ue.Index+1); i++ { 132 | out.WriteString("어") 133 | } 134 | 135 | return out.String() 136 | } 137 | 138 | type UMExpression struct { 139 | Token token.Token 140 | Index int64 141 | Value Expression 142 | } 143 | 144 | func (ume *UMExpression) expressionNode() {} 145 | func (ume *UMExpression) TokenLiteral() string { return ume.Token.Literal } 146 | func (ume *UMExpression) String() string { 147 | var out bytes.Buffer 148 | 149 | for i := 0; i < int(ume.Index); i++ { 150 | out.WriteString("어") 151 | } 152 | 153 | out.WriteString("엄") 154 | out.WriteString(ume.Value.String()) 155 | 156 | return out.String() 157 | } 158 | 159 | type JUNEExpression struct { 160 | Token token.Token 161 | Index Expression 162 | } 163 | 164 | func (je *JUNEExpression) expressionNode() {} 165 | func (je *JUNEExpression) TokenLiteral() string { return je.Token.Literal } 166 | func (je *JUNEExpression) String() string { 167 | var out bytes.Buffer 168 | 169 | out.WriteString("준") 170 | 171 | out.WriteString(je.Index.String()) 172 | 173 | return out.String() 174 | } 175 | 176 | type SIKQExpression struct { 177 | Token token.Token 178 | } 179 | 180 | func (sqe *SIKQExpression) expressionNode() {} 181 | func (sqe *SIKQExpression) TokenLiteral() string { return sqe.Token.Literal } 182 | func (sqe *SIKQExpression) String() string { 183 | return "식?" 184 | } 185 | 186 | type SIKKIExpression struct { 187 | Token token.Token 188 | Value Expression 189 | } 190 | 191 | func (ske *SIKKIExpression) expressionNode() {} 192 | func (ske *SIKKIExpression) TokenLiteral() string { return ske.Token.Literal } 193 | func (ske *SIKKIExpression) String() string { 194 | var out bytes.Buffer 195 | 196 | out.WriteString("식") 197 | out.WriteString(ske.Value.String()) 198 | out.WriteString("ㅋ") 199 | 200 | return out.String() 201 | } 202 | 203 | type SIKBExpression struct { 204 | Token token.Token 205 | Value Expression 206 | } 207 | 208 | func (sbe *SIKBExpression) expressionNode() {} 209 | func (sbe *SIKBExpression) TokenLiteral() string { return sbe.Token.Literal } 210 | func (sbe *SIKBExpression) String() string { 211 | var out bytes.Buffer 212 | 213 | out.WriteString("식") 214 | out.WriteString(sbe.Value.String()) 215 | out.WriteString("!") 216 | 217 | return out.String() 218 | } 219 | 220 | type DONGTANExpression struct { 221 | Token token.Token 222 | Condition Expression 223 | Statement Expression 224 | } 225 | 226 | func (de *DONGTANExpression) expressionNode() {} 227 | func (de *DONGTANExpression) TokenLiteral() string { return de.Token.Literal } 228 | func (de *DONGTANExpression) String() string { 229 | var out bytes.Buffer 230 | 231 | out.WriteString("동탄") 232 | out.WriteString(de.Condition.String()) 233 | out.WriteString("?") 234 | out.WriteString(de.Statement.String()) 235 | 236 | return out.String() 237 | } 238 | 239 | type FIGHTINGExpression struct { 240 | Token token.Token 241 | Value Expression 242 | } 243 | 244 | func (fe *FIGHTINGExpression) expressionNode() {} 245 | func (fe *FIGHTINGExpression) TokenLiteral() string { return fe.Token.Literal } 246 | func (fe *FIGHTINGExpression) String() string { 247 | var out bytes.Buffer 248 | 249 | out.WriteString("화이팅!") 250 | out.WriteString(fe.Value.String()) 251 | 252 | return out.String() 253 | } 254 | -------------------------------------------------------------------------------- /umjunsik-lang-go/eval/eval.go: -------------------------------------------------------------------------------- 1 | package eval 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "umjunsik-lang/umjunsik-lang-go/ast" 7 | "umjunsik-lang/umjunsik-lang-go/object" 8 | ) 9 | 10 | func Eval(node ast.Node, env *object.Environment) object.Object { 11 | switch node := node.(type) { 12 | case *ast.Program: 13 | return evalProgram(node, env) 14 | case *ast.ExpressionLine: 15 | return Eval(node.Expression, env) 16 | case *ast.InfixIntegerExpression: 17 | leftObj := Eval(node.Left, env) 18 | return &object.Integer{Value: leftObj.(*object.Integer).Value + node.Right} 19 | case *ast.SPACEExpression: 20 | leftObj := Eval(node.Left, env) 21 | rightObj := Eval(node.Right, env) 22 | return &object.Integer{Value: leftObj.(*object.Integer).Value * rightObj.(*object.Integer).Value} 23 | case *ast.IntegerLiteral: 24 | return &object.Integer{Value: node.Value} 25 | case *ast.UEpxression: 26 | obj, ok := env.Get(int(node.Index)) 27 | if !ok { 28 | return newError("ObjectFindError") 29 | } 30 | 31 | return obj 32 | case *ast.UMExpression: 33 | obj := Eval(node.Value, env) 34 | env.Set(int(node.Index), obj) 35 | case *ast.JUNEExpression: 36 | obj := Eval(node.Index, env) 37 | return &object.JUN{Index: obj.(*object.Integer).Value} 38 | case *ast.SIKQExpression: 39 | var integer int 40 | fmt.Scanln(&integer) 41 | return &object.Integer{Value: int64(integer)} 42 | case *ast.SIKKIExpression: 43 | obj := Eval(node.Value, env) 44 | fmt.Printf("%c", obj.(*object.Integer).Value) 45 | case *ast.SIKBExpression: 46 | obj := Eval(node.Value, env) 47 | fmt.Printf("%d", obj.(*object.Integer).Value) 48 | case *ast.DONGTANExpression: 49 | conditionObj := Eval(node.Condition, env) 50 | if conditionObj.(*object.Integer).Value == 0 { 51 | return Eval(node.Statement, env) 52 | } 53 | case *ast.FIGHTINGExpression: 54 | obj := Eval(node.Value, env) 55 | os.Exit(int(obj.(*object.Integer).Value)) 56 | } 57 | 58 | return nil 59 | } 60 | 61 | func evalProgram(program *ast.Program, env *object.Environment) object.Object { 62 | var result object.Object 63 | 64 | for i := 0; i < len(program.Lines); i++ { 65 | line := program.Lines[i] 66 | 67 | result = Eval(line, env) 68 | 69 | switch result := result.(type) { 70 | case *object.JUN: 71 | i = int(result.Index - 3) 72 | case *object.Error: 73 | return result 74 | } 75 | } 76 | 77 | return result 78 | } 79 | -------------------------------------------------------------------------------- /umjunsik-lang-go/eval/util.go: -------------------------------------------------------------------------------- 1 | package eval 2 | 3 | import ( 4 | "fmt" 5 | "umjunsik-lang/umjunsik-lang-go/object" 6 | ) 7 | 8 | func isError(obj object.Object) bool { 9 | if obj != nil { 10 | return obj.Type() == object.ERROR_OBJ 11 | } 12 | return false 13 | } 14 | 15 | func newError(format string, a ...interface{}) *object.Error { 16 | return &object.Error{Message: fmt.Sprintf(format, a...)} 17 | } 18 | -------------------------------------------------------------------------------- /umjunsik-lang-go/go.mod: -------------------------------------------------------------------------------- 1 | module umjunsik-lang/umjunsik-lang-go 2 | 3 | go 1.17 4 | -------------------------------------------------------------------------------- /umjunsik-lang-go/lexer/lexer.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import ( 4 | "umjunsik-lang/umjunsik-lang-go/token" 5 | ) 6 | 7 | type Lexer struct { 8 | input string 9 | position int 10 | readPosition int 11 | ch string 12 | } 13 | 14 | func New(input string) *Lexer { 15 | l := &Lexer{input: input} 16 | l.readChar() 17 | if l.ch == "어" { 18 | l.readChar() 19 | if l.ch == "떻" { 20 | l.readChar() 21 | if l.ch == "게" { 22 | l.readChar() 23 | } else { 24 | return nil 25 | } 26 | } else { 27 | return nil 28 | } 29 | } else { 30 | return nil 31 | } 32 | return l 33 | } 34 | 35 | func (l *Lexer) NextToken() token.Token { 36 | var tok token.Token 37 | 38 | l.skipWhiteSpace() 39 | 40 | switch l.ch { 41 | case "어": 42 | tok = newToken(token.U, "어") 43 | case "엄": 44 | tok = newToken(token.UM, "엄") 45 | case "준": 46 | tok = newToken(token.JUN, "준") 47 | case "식": 48 | tok = newToken(token.SIK, "식") 49 | case "동": 50 | if l.peekchar() == "탄" { 51 | tok = newToken(token.DONGTAN, "동탄") 52 | l.readChar() 53 | } 54 | case "ㅋ": 55 | tok = newToken(token.KI, "ㅋ") 56 | case "화": 57 | if l.peekchar() == "이" { 58 | l.readChar() 59 | if l.peekchar() == "팅" { 60 | l.readChar() 61 | tok = newToken(token.FIGHTING, "화이팅") 62 | } 63 | } 64 | case ".": 65 | tok = newToken(token.PERIOD, ".") 66 | case ",": 67 | tok = newToken(token.COMMA, ",") 68 | case "?": 69 | tok = newToken(token.QUESTION, "?") 70 | case "!": 71 | tok = newToken(token.BANG, "!") 72 | case "~": 73 | tok = newToken(token.NEWLINE, "~") 74 | case "\n": 75 | tok = newToken(token.NEWLINE, "\n") 76 | case " ": 77 | tok = newToken(token.SPACE, " ") 78 | case "이": 79 | if l.IsLast() { 80 | tok = newToken(token.EOF, "") 81 | return tok 82 | } 83 | } 84 | 85 | l.readChar() 86 | return tok 87 | } 88 | 89 | func newToken(tokenType token.TokenType, ch string) token.Token { 90 | return token.Token{Type: tokenType, Literal: ch} 91 | } 92 | 93 | // UTF-8 인코딩에 따라 문자를 읽습니다. 94 | func (l *Lexer) readChar() { 95 | Byte1 := l.input[l.readPosition] 96 | 97 | if Byte1 >= 128 { 98 | l.ch = string([]byte{Byte1, l.input[l.readPosition+1], l.input[l.readPosition+2]}) 99 | 100 | l.position = l.readPosition 101 | l.readPosition += 3 102 | } else { 103 | l.ch = string(Byte1) 104 | l.position = l.readPosition 105 | l.readPosition += 1 106 | } 107 | } 108 | 109 | func (l *Lexer) peekchar() string { 110 | if l.input[l.readPosition] >= 128 { 111 | return string([]byte{l.input[l.readPosition], l.input[l.readPosition+1], l.input[l.readPosition+2]}) 112 | } else { 113 | return string(l.input[l.readPosition]) 114 | } 115 | } 116 | 117 | func (l *Lexer) skipWhiteSpace() { 118 | if l.ch == "\r" || l.ch == "\t" || l.ch == "\v" || l.ch == "\f" { 119 | l.readChar() 120 | } 121 | } 122 | 123 | func (l *Lexer) IsLast() bool { 124 | return l.input[l.position:l.position+28] == "이 사람이름이냐ㅋㅋ" 125 | } 126 | -------------------------------------------------------------------------------- /umjunsik-lang-go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "io/ioutil" 6 | "umjunsik-lang/umjunsik-lang-go/eval" 7 | "umjunsik-lang/umjunsik-lang-go/lexer" 8 | "umjunsik-lang/umjunsik-lang-go/object" 9 | "umjunsik-lang/umjunsik-lang-go/parser" 10 | ) 11 | 12 | var ( 13 | FilePath string 14 | ) 15 | 16 | func init() { 17 | flag.Parse() 18 | FilePath = flag.Args()[0] 19 | } 20 | 21 | func main() { 22 | Code, err := ioutil.ReadFile(FilePath) 23 | if err != nil { 24 | panic(err) 25 | } 26 | Interpret(Code) 27 | } 28 | 29 | func Interpret(Code []byte) { 30 | l := lexer.New(string(Code)) 31 | p := parser.New(l) 32 | program := p.ParseProgram() 33 | env := object.NewEnvironment() 34 | eval.Eval(program, env) 35 | 36 | // for tok := l.NextToken(); tok.Type != token.EOF; tok = l.NextToken() { 37 | // fmt.Println("{" + " Type : " + string(tok.Type) + ", Literal : " + tok.Literal + " }") 38 | //} 39 | } 40 | -------------------------------------------------------------------------------- /umjunsik-lang-go/object/object.go: -------------------------------------------------------------------------------- 1 | package object 2 | 3 | import "strconv" 4 | 5 | type Environment struct { 6 | store map[int]Object 7 | } 8 | 9 | func NewEnvironment() *Environment { 10 | s := make(map[int]Object) 11 | return &Environment{store: s} 12 | } 13 | 14 | func (env *Environment) Get(index int) (Object, bool) { 15 | obj, ok := env.store[index] 16 | if !ok { 17 | obj = &Integer{Value: 0} 18 | } 19 | return obj, true 20 | } 21 | 22 | func (env *Environment) Set(index int, obj Object) { 23 | env.store[index] = obj 24 | } 25 | 26 | const ( 27 | JUN_OBJ = "JUN_OBJ" 28 | INTEGER_OBJ = "INTEGER_OBJ" 29 | ERROR_OBJ = "ERROR_OBJ" 30 | ) 31 | 32 | type ObjectType string 33 | 34 | type Object interface { 35 | Type() ObjectType 36 | Inspect() string 37 | } 38 | 39 | type JUN struct { 40 | Index int64 41 | } 42 | 43 | func (j *JUN) Type() ObjectType { return JUN_OBJ } 44 | func (j *JUN) Inspect() string { return strconv.Itoa(int(j.Index)) } 45 | 46 | type Integer struct { 47 | Value int64 48 | } 49 | 50 | func (i *Integer) Type() ObjectType { return INTEGER_OBJ } 51 | func (i *Integer) Inspect() string { return strconv.Itoa(int(i.Value)) } 52 | 53 | type Error struct { 54 | Message string 55 | } 56 | 57 | func (e *Error) Type() ObjectType { return ERROR_OBJ } 58 | func (e *Error) Inspect() string { return "ERROR: " + e.Message } 59 | -------------------------------------------------------------------------------- /umjunsik-lang-go/parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "umjunsik-lang/umjunsik-lang-go/ast" 5 | "umjunsik-lang/umjunsik-lang-go/lexer" 6 | "umjunsik-lang/umjunsik-lang-go/token" 7 | ) 8 | 9 | type Parser struct { 10 | l *lexer.Lexer 11 | errors []string 12 | 13 | curToken token.Token 14 | peekToken token.Token 15 | 16 | prefixParseFns map[token.TokenType]prefixParseFn 17 | infixParseFns map[token.TokenType]infixParseFn 18 | } 19 | 20 | type ( 21 | prefixParseFn func() ast.Expression 22 | infixParseFn func(ast.Expression) ast.Expression 23 | ) 24 | 25 | func (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixParseFn) { 26 | p.prefixParseFns[tokenType] = fn 27 | } 28 | 29 | func (p *Parser) registerInfix(tokenType token.TokenType, fn infixParseFn) { 30 | p.infixParseFns[tokenType] = fn 31 | } 32 | 33 | func New(l *lexer.Lexer) *Parser { 34 | p := &Parser{ 35 | l: l, 36 | errors: []string{}, 37 | } 38 | p.nextToken() 39 | p.nextToken() 40 | 41 | p.prefixParseFns = make(map[token.TokenType]prefixParseFn) 42 | p.registerPrefix(token.U, p.parseUExpression) 43 | p.registerPrefix(token.PERIOD, p.parsePrefixIntegerExpression) 44 | p.registerPrefix(token.COMMA, p.parsePrefixIntegerExpression) 45 | p.registerPrefix(token.UM, p.parseUMExpression) 46 | p.registerPrefix(token.JUN, p.parseJUNExpression) 47 | p.registerPrefix(token.SIK, p.parseSIKExpression) 48 | p.registerPrefix(token.DONGTAN, p.parseDONGTANExpression) 49 | p.registerPrefix(token.FIGHTING, p.parseFIGHTINGExpression) 50 | 51 | p.infixParseFns = make(map[token.TokenType]infixParseFn) 52 | p.registerInfix(token.PERIOD, p.parseInfixIntegerExpression) 53 | p.registerInfix(token.COMMA, p.parseInfixIntegerExpression) 54 | p.registerInfix(token.SPACE, p.parseSPACEExpression) 55 | 56 | return p 57 | } 58 | 59 | func (p *Parser) ParseProgram() *ast.Program { 60 | program := &ast.Program{} 61 | program.Lines = []ast.Line{} 62 | 63 | for p.curToken.Type != token.EOF { 64 | line := p.parseLine() 65 | program.Lines = append(program.Lines, line) 66 | 67 | p.nextToken() 68 | } 69 | 70 | return program 71 | } 72 | 73 | func (p *Parser) parseLine() ast.Line { 74 | return p.parseExpressionStatement() 75 | } 76 | 77 | func (p *Parser) parseExpressionStatement() *ast.ExpressionLine { 78 | line := &ast.ExpressionLine{Token: p.curToken} 79 | line.Expression = p.parseExpression() 80 | 81 | if p.peekTokenIs(token.NEWLINE) { 82 | p.nextToken() 83 | } 84 | 85 | return line 86 | } 87 | 88 | func (p *Parser) parseExpression() ast.Expression { 89 | prefix := p.prefixParseFns[p.curToken.Type] 90 | if prefix == nil { 91 | p.noPrefixParseFnError(p.curToken.Type) 92 | return nil 93 | } 94 | leftExp := prefix() 95 | 96 | for !(p.peekTokenIs(token.NEWLINE) || p.peekTokenIs(token.KI) || p.peekTokenIs(token.QUESTION) || p.peekTokenIs(token.BANG)) { 97 | infix := p.infixParseFns[p.peekToken.Type] 98 | if infix == nil { 99 | return leftExp 100 | } 101 | 102 | p.nextToken() 103 | 104 | leftExp = infix(leftExp) 105 | } 106 | 107 | return leftExp 108 | } 109 | 110 | func (p *Parser) parseUExpression() ast.Expression { 111 | exp := &ast.UEpxression{Token: p.curToken} 112 | 113 | var index int64 = 0 114 | 115 | for p.peekTokenIs(token.U) { 116 | index++ 117 | p.nextToken() 118 | } 119 | 120 | if p.peekTokenIs(token.UM) { 121 | p.nextToken() 122 | exp := &ast.UMExpression{Token: p.curToken} 123 | exp.Index = index + 1 124 | 125 | if p.peekTokenIs(token.NEWLINE) { 126 | if exp.Value == nil { 127 | exp.Value = &ast.IntegerLiteral{ 128 | Token: token.Token{ 129 | Type: token.PERIOD, 130 | Literal: ".", 131 | }, 132 | Value: 0, 133 | } 134 | } 135 | } else { 136 | p.nextToken() 137 | exp.Value = p.parseExpression() 138 | } 139 | 140 | return exp 141 | } 142 | 143 | exp.Index = index 144 | 145 | return exp 146 | } 147 | 148 | func (p *Parser) parseUMExpression() ast.Expression { 149 | if p.curTokenIs(token.UM) { 150 | p.nextToken() 151 | } 152 | 153 | tmp := p.parseExpression() 154 | tok := p.curToken 155 | 156 | if tmp != nil { 157 | return &ast.UMExpression{Token: tok, Index: 0, Value: tmp} 158 | } else { 159 | return &ast.UMExpression{Token: tok, Index: 0, Value: &ast.IntegerLiteral{ 160 | Token: token.Token{ 161 | Type: token.PERIOD, 162 | Literal: ".", 163 | }, 164 | Value: 0, 165 | }, 166 | } 167 | } 168 | } 169 | 170 | func (p *Parser) parsePrefixIntegerExpression() ast.Expression { 171 | lit := &ast.IntegerLiteral{Token: p.curToken} 172 | 173 | var result int64 = 0 174 | 175 | if p.curTokenIs(token.PERIOD) { 176 | result++ 177 | } else if p.curTokenIs(token.COMMA) { 178 | result-- 179 | } 180 | 181 | for p.peekTokenIs(token.PERIOD) || p.peekTokenIs(token.COMMA) { 182 | switch p.peekToken.Type { 183 | case token.PERIOD: 184 | result++ 185 | case token.COMMA: 186 | result-- 187 | } 188 | p.nextToken() 189 | } 190 | 191 | lit.Value = result 192 | 193 | return lit 194 | } 195 | 196 | func (p *Parser) parseJUNExpression() ast.Expression { 197 | exp := &ast.JUNEExpression{Token: p.curToken} 198 | 199 | if p.peekTokenIs(token.NEWLINE) { 200 | return nil 201 | } 202 | 203 | p.nextToken() 204 | 205 | exp.Index = p.parseExpression() 206 | 207 | return exp 208 | } 209 | 210 | func (p *Parser) parseSIKExpression() ast.Expression { 211 | if p.peekTokenIs(token.QUESTION) { 212 | p.nextToken() 213 | return &ast.SIKQExpression{Token: p.curToken} 214 | } 215 | 216 | p.nextToken() 217 | 218 | // if p.peekTokenIs(token.BANG) { 219 | // p.nextToken() 220 | //} 221 | if p.curTokenIs(token.KI) { 222 | exp := &ast.SIKKIExpression{Token: p.curToken} 223 | exp.Value = &ast.IntegerLiteral{ 224 | Token: token.Token{ 225 | Type: token.PERIOD, 226 | Literal: ".", 227 | }, 228 | Value: 10, 229 | } 230 | 231 | return exp 232 | } 233 | 234 | tem := p.parseExpression() 235 | 236 | switch p.peekToken.Type { 237 | case token.BANG: 238 | p.nextToken() 239 | exp := &ast.SIKBExpression{Token: p.curToken} 240 | 241 | exp.Value = tem 242 | return exp 243 | case token.KI: 244 | p.nextToken() 245 | exp := &ast.SIKKIExpression{Token: p.curToken} 246 | if tem != nil { 247 | exp.Value = tem 248 | } 249 | return exp 250 | } 251 | 252 | return nil 253 | } 254 | 255 | func (p *Parser) parseDONGTANExpression() ast.Expression { 256 | exp := &ast.DONGTANExpression{Token: p.curToken} 257 | 258 | if p.peekTokenIs(token.NEWLINE) { 259 | return nil 260 | } 261 | 262 | p.nextToken() 263 | 264 | exp.Condition = p.parseExpression() 265 | 266 | if !p.expectPeek(token.QUESTION) { 267 | return nil 268 | } 269 | 270 | p.nextToken() 271 | 272 | exp.Statement = p.parseExpression() 273 | 274 | return exp 275 | } 276 | 277 | func (p *Parser) parseFIGHTINGExpression() ast.Expression { 278 | exp := &ast.FIGHTINGExpression{Token: p.curToken} 279 | 280 | if !p.expectPeek(token.BANG) { 281 | return nil 282 | } 283 | 284 | p.nextToken() 285 | 286 | exp.Value = p.parseExpression() 287 | 288 | return exp 289 | } 290 | 291 | func (p *Parser) parseInfixIntegerExpression(left ast.Expression) ast.Expression { 292 | exp := &ast.InfixIntegerExpression{Token: p.curToken, Left: left} 293 | 294 | var result int64 = 0 295 | 296 | if p.curTokenIs(token.PERIOD) { 297 | result++ 298 | } else if p.curTokenIs(token.COMMA) { 299 | result-- 300 | } 301 | 302 | for p.peekTokenIs(token.PERIOD) || p.peekTokenIs(token.COMMA) { 303 | switch p.curToken.Type { 304 | case token.PERIOD: 305 | result++ 306 | case token.COMMA: 307 | result-- 308 | } 309 | p.nextToken() 310 | } 311 | 312 | exp.Right = result 313 | 314 | return exp 315 | } 316 | 317 | func (p *Parser) parseSPACEExpression(left ast.Expression) ast.Expression { 318 | exp := &ast.SPACEExpression{Token: p.curToken, Left: left} 319 | 320 | p.nextToken() 321 | exp.Right = p.parseExpression() 322 | 323 | return exp 324 | } 325 | -------------------------------------------------------------------------------- /umjunsik-lang-go/parser/util.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "umjunsik-lang/umjunsik-lang-go/token" 6 | ) 7 | 8 | func (p *Parser) Errors() []string { 9 | return p.errors 10 | } 11 | 12 | func (p *Parser) noPrefixParseFnError(t token.TokenType) { 13 | msg := fmt.Sprintf("no prefix parse function for %s found", t) 14 | p.errors = append(p.errors, msg) 15 | } 16 | 17 | func (p *Parser) peekError(t token.TokenType) { 18 | msg := fmt.Sprintf("expected next token to be %s, got %s instend", t, p.peekToken.Type) 19 | p.errors = append(p.errors, msg) 20 | } 21 | 22 | func (p *Parser) nextToken() { 23 | p.curToken = p.peekToken 24 | p.peekToken = p.l.NextToken() 25 | } 26 | 27 | // 다음 토큰을 검사하고 이동하므로 안전한 토큰 이동입니다. 28 | func (p *Parser) expectPeek(t token.TokenType) bool { 29 | if p.peekTokenIs(t) { 30 | p.nextToken() 31 | return true 32 | } else { 33 | p.peekError(t) 34 | return false 35 | } 36 | } 37 | 38 | func (p *Parser) curTokenIs(t token.TokenType) bool { 39 | return p.curToken.Type == t 40 | } 41 | 42 | func (p *Parser) peekTokenIs(t token.TokenType) bool { 43 | return p.peekToken.Type == t 44 | } 45 | -------------------------------------------------------------------------------- /umjunsik-lang-go/token/token.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | type TokenType string 4 | 5 | type Token struct { 6 | Type TokenType 7 | Literal string 8 | } 9 | 10 | const ( 11 | ILLEGAL = "ILLEGAL" 12 | EOF = "EOF" 13 | 14 | U = "U" 15 | UM = "UM" 16 | JUN = "JUN" 17 | SIK = "SIK" 18 | DONGTAN = "DONGTAN" 19 | KI = "KI" 20 | NEWLINE = "NEWLINE" 21 | FIGHTING = "FIGHTING" 22 | PERIOD = "." 23 | COMMA = "," 24 | BANG = "!" 25 | QUESTION = "?" 26 | SPACE = " " 27 | ) 28 | -------------------------------------------------------------------------------- /umjunsik-lang-java/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rycont/umjunsik-lang/e973f9d22b9803ee86b53d8e60f1b65ab08c7547/umjunsik-lang-java/.DS_Store -------------------------------------------------------------------------------- /umjunsik-lang-java/main.java: -------------------------------------------------------------------------------- 1 | import setting.Items; 2 | import setting.console.ChangeUni; 3 | import setting.console.Print; 4 | import setting.console.Scan; 5 | import setting.var.VarGet; 6 | import setting.var.VarSet; 7 | 8 | import java.io.BufferedReader; 9 | import java.io.FileReader; 10 | import java.io.IOException; 11 | import java.nio.charset.Charset; 12 | import java.nio.charset.StandardCharsets; 13 | import java.nio.file.Files; 14 | import java.nio.file.Path; 15 | import java.nio.file.Paths; 16 | import java.util.List; 17 | import java.util.Locale; 18 | 19 | public class main extends Items { 20 | 21 | public static void main(String[] args) throws IOException { 22 | TotalText = ""; 23 | 24 | // Path path = Paths.get("./" + "test.umm"); 25 | // Charset cs = StandardCharsets.UTF_8; 26 | // List list = Files.readAllLines(path, cs); 27 | // list.forEach(main::first); 28 | 29 | String fileName = args[0]; 30 | if (fileName.toLowerCase(Locale.ROOT).endsWith(".umm")) throw new IOException("확장자가 일치하지 않습니다."); 31 | BufferedReader reader = new BufferedReader(new FileReader(fileName, StandardCharsets.UTF_8)); 32 | String readerString; 33 | while ((readerString = reader.readLine()) != null) first(readerString); 34 | reader.close(); 35 | 36 | int startPos = TotalText.indexOf("어떻게") + 3; 37 | int endPos = TotalText.lastIndexOf("이 사람이름이냐ㅋㅋ"); 38 | TotalText = TotalText.substring(startPos, endPos); 39 | 40 | ChangeUni changeUni = new ChangeUni(); 41 | Print print = new Print(); 42 | Scan scan = new Scan(); 43 | VarGet varGet = new VarGet(); 44 | VarSet varSet = new VarSet(); 45 | 46 | String[] lines = TotalText.split("\\n"); 47 | for (String line : lines) { 48 | // System.out.println(line); 49 | if (changeUni.check(line)) changeUni.change(line); 50 | else if (print.check(line)) print.print(line); 51 | else if (scan.check(line)) scan.scanner(line); 52 | else if (varGet.check(line)) varGet.get(line); 53 | else if (varSet.check(line)) varSet.set(line); 54 | } 55 | } 56 | 57 | private static void first(String line) { 58 | TotalText += (line + "\n"); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /umjunsik-lang-java/setting/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rycont/umjunsik-lang/e973f9d22b9803ee86b53d8e60f1b65ab08c7547/umjunsik-lang-java/setting/.DS_Store -------------------------------------------------------------------------------- /umjunsik-lang-java/setting/Count.java: -------------------------------------------------------------------------------- 1 | package setting; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Count { 7 | int totalNumber = 0; 8 | 9 | //계산 후 반환 10 | public int count(String line) { 11 | totalNumber = 0; 12 | String[] texts = line.split(" "); 13 | List list = new ArrayList<>(); 14 | 15 | for (String text : texts) { 16 | int count = 0; 17 | for (int i = 0; i totalNumber *= number); 28 | return totalNumber; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /umjunsik-lang-java/setting/Items.java: -------------------------------------------------------------------------------- 1 | package setting; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class Items { 7 | public static String TotalText; 8 | public static Map map = new HashMap<>(); 9 | } -------------------------------------------------------------------------------- /umjunsik-lang-java/setting/console/ChangeUni.java: -------------------------------------------------------------------------------- 1 | package setting.console; 2 | 3 | import setting.var.VarGet; 4 | 5 | public class ChangeUni { 6 | 7 | public void change(String line) { 8 | int start = line.indexOf("식") + 1; 9 | int end = line.lastIndexOf("ㅋ"); 10 | line = line.substring(start, end); 11 | 12 | VarGet varGet = new VarGet(); 13 | if (line.isBlank()) System.out.println(); 14 | else { 15 | int i = varGet.get(line); 16 | System.out.print((char) i); 17 | } 18 | } 19 | 20 | public boolean check(String line) { 21 | if (line.isBlank()) return false; 22 | return line.trim().startsWith("식") && line.endsWith("ㅋ"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /umjunsik-lang-java/setting/console/Print.java: -------------------------------------------------------------------------------- 1 | package setting.console; 2 | 3 | import setting.var.VarGet; 4 | 5 | public class Print { 6 | 7 | public void print(String line) { 8 | 9 | int start = line.indexOf("식") + 1; 10 | int end = line.lastIndexOf("!"); 11 | 12 | line = line.substring(start, end); 13 | VarGet varGet = new VarGet(); 14 | System.out.print(varGet.get(line)); 15 | } 16 | 17 | public boolean check(String line) { 18 | return line.trim().startsWith("식") && line.endsWith("!"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /umjunsik-lang-java/setting/console/Scan.java: -------------------------------------------------------------------------------- 1 | package setting.console; 2 | 3 | import setting.var.VarSet; 4 | 5 | import java.util.Scanner; 6 | 7 | public class Scan { 8 | public void scanner(String line) { 9 | Scanner sc = new Scanner(System.in); 10 | int getInt = sc.nextInt(); 11 | VarSet varSet = new VarSet(); 12 | varSet.set(line, getInt); 13 | } 14 | 15 | public boolean check(String line) { 16 | return line.trim().endsWith("식?"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /umjunsik-lang-java/setting/var/VarGet.java: -------------------------------------------------------------------------------- 1 | package setting.var; 2 | 3 | import setting.Count; 4 | import setting.Items; 5 | 6 | public class VarGet { 7 | //어.. 8 | public int get(String line) { 9 | Count count = new Count(); 10 | return count.count(changeVar(line.trim())); 11 | } 12 | 13 | public boolean check(String text) { 14 | return text.contains("어"); 15 | } 16 | 17 | //변수 -> 값 18 | private String changeVar(String line) { 19 | int len = line.trim().replaceAll("[.|,]", "").length(); 20 | for (int i = len; i>0; i--) { 21 | String key = getKey(i); 22 | if (line.contains(key)) line = line.replace(key, Items.map.get(i)); 23 | } return line; 24 | } 25 | 26 | private String getKey(int len) { 27 | String total = ""; 28 | for (int i = 0; i = mutableListOf() 10 | 11 | var pc: Int = 0 12 | 13 | fun MutableList.getSafe(index: Int): Int { 14 | return if(index > this.lastIndex) 0 else this[index] 15 | } 16 | 17 | fun MutableList.setSafe(index: Int, value: Int) { 18 | if(index > this.lastIndex){ 19 | for(i in 0 until index - this.lastIndex){ 20 | this.add(0) 21 | } 22 | } 23 | this[index] = value 24 | } 25 | 26 | fun parseLine(code: String){ 27 | if(code.startsWith("화이팅!")){ 28 | exitProcess(memory.getSafe(code.replace("화이팅!", "").toUmmInt())) 29 | } 30 | else if(code.endsWith("식?")){ 31 | if(code.replace("식?", "") == ""){ 32 | throw java.lang.RuntimeException("문법 오류: 대입할 변수 미지정 (${pc + 1}번 줄)") 33 | } 34 | else { 35 | val sc = Scanner(System.`in`) 36 | memory.setSafe(code.replace("식?", "").toUmmInt(), sc.nextInt()) 37 | } 38 | } 39 | else if(code.startsWith("식")){ 40 | if(code.endsWith("!")){ 41 | val q = code.replace("식", "").replace("!", "") 42 | print("${q.toUmmInt()}") 43 | } 44 | else if(code.endsWith("ㅋ")){ 45 | val q = code.replace("식", "").replace("ㅋ", "") 46 | if(q == ""){ 47 | println() 48 | } 49 | else { 50 | val b = q.toUmmInt() 51 | 52 | print(convertUnicodeToString("\\u${b.toString(16).padStart(4 - b.toString(16).length, '0')}")) 53 | } 54 | } 55 | } 56 | else if(code.startsWith("동탄")){ 57 | if(code.contains("?")){ 58 | val cc = code.replace("동탄", "").split("?") 59 | 60 | val r = cc[0].toUmmInt() 61 | 62 | if(r == 0){ 63 | parseLine(cc[1]) 64 | } 65 | } 66 | } 67 | else if(code.startsWith("준")){ 68 | if(code.replace("준", "") == ""){ 69 | throw java.lang.RuntimeException("문법 오류: 점프할 줄 번호 미지정 (${pc + 2}번 줄)") 70 | } 71 | else { 72 | val lPC = code.replace("준", "") 73 | 74 | pc = lPC.toUmmInt() - 3 75 | } 76 | } 77 | else if(code.contains("엄")){ 78 | val c = code.split("엄") 79 | 80 | memory.setSafe(c[0].countChar("어"), c[1].toUmmInt()) 81 | } 82 | else { 83 | return 84 | } 85 | return 86 | } 87 | 88 | fun main(args: Array) { 89 | if(args.isEmpty()){ 90 | throw IOException("어떻게 파일 이름이 없냐ㅋㅋ") 91 | } 92 | else if(!args[0].endsWith(".umm")){ 93 | throw IOException("어떻게 ${args[0]}이 파일이름이냐ㅋㅋ") 94 | } 95 | 96 | val f = File(args[0]) 97 | if(!f.canRead()) { 98 | throw IOException("파일을 읽을 수 없음") 99 | } 100 | else { 101 | var codes = f.readText().trim().replace("~", "\n").split("\n") 102 | 103 | if(codes[0] != "어떻게" && codes.last() != "이 사람이름이냐ㅋㅋ"){ 104 | throw Exception("어떻게 이게 엄랭이냐ㅋㅋ") 105 | } 106 | 107 | codes = codes.subList(1, codes.size) 108 | 109 | while(true){ 110 | if(codes[pc] != "이 사람이름이냐ㅋㅋ"){ 111 | parseLine(codes[pc].trim()) 112 | pc++ 113 | } 114 | else break 115 | } 116 | } 117 | 118 | exitProcess(0) 119 | } -------------------------------------------------------------------------------- /umjunsik-lang-kotlin/src/main/kotlin/com/alphagot/kumjunsiklang/ParseUtils.kt: -------------------------------------------------------------------------------- 1 | package com.alphagot.kumjunsiklang 2 | 3 | import java.util.* 4 | 5 | fun String.countChar(c: String): Int { 6 | var ret = 0 7 | this.toCharArray().forEach { 8 | if(it.toString() == c){ 9 | ret++ 10 | } 11 | } 12 | return ret 13 | } 14 | 15 | fun String.toUmmInt(): Int { 16 | return toUmmmInt(this) 17 | } 18 | 19 | fun toUmmmInt(a: String): Int { 20 | var n = 0 21 | if (a.contains(" ")) { 22 | val b = a.split(" ").map { 23 | toUmmmIntInternal(it) 24 | } 25 | n = b[0] 26 | b.subList(1, b.size).forEach { 27 | n *= it 28 | } 29 | } 30 | else { 31 | n = toUmmmIntInternal(a) 32 | } 33 | return n 34 | } 35 | 36 | fun toUmmmIntInternal(a: String): Int { 37 | var s = a 38 | var n = 0 39 | 40 | if(s.contains("식?")) { 41 | val answer = Scanner(System.`in`).nextInt() 42 | s = s.replace("식?", ".".repeat(answer)) 43 | } 44 | if(s.contains("어")) n += memory.getSafe(s.countChar("어") - 1) 45 | if(s.contains(".")) n += s.countChar(".") 46 | if(s.contains(",")) n -= s.countChar(",") 47 | return n 48 | } 49 | 50 | fun String.toVarIndex(isLoad: Boolean = true): Int { 51 | if(this.split(" ").size > 1){ 52 | val s = this.split(" ") 53 | 54 | val b = mutableListOf() 55 | s.forEach { b.add(it.countChar("어") - 1) } 56 | 57 | var r = 1 58 | 59 | b.forEach { 60 | r *= it 61 | } 62 | 63 | return r + if(isLoad) -1 else 0 64 | } 65 | else { 66 | return this.countChar("어") + if(isLoad) -1 else 0 67 | } 68 | } 69 | 70 | fun String.isVariable(): Boolean = this.startsWith("어") || this.endsWith("엄") 71 | 72 | fun convertUnicodeToString(unicodeString: String): String { 73 | var str: String = unicodeString.split(" ")[0] 74 | str = str.replace("\\", "") 75 | val arr = str.split("u").toTypedArray() 76 | var text = "" 77 | for (i in 1 until arr.size) { 78 | val hexVal = arr[i].toInt(16) 79 | text += hexVal.toChar() 80 | } 81 | 82 | return text 83 | } 84 | -------------------------------------------------------------------------------- /umjunsik-lang-node/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules -------------------------------------------------------------------------------- /umjunsik-lang-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "umjunsik-lang-node", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "UNLICENSED", 6 | "scripts": { 7 | "build": "tsc" 8 | }, 9 | "devDependencies": { 10 | "@types/node": "^14.6.4", 11 | "@types/readline-sync": "^1.4.3" 12 | }, 13 | "dependencies": { 14 | "readline-sync": "^1.4.10", 15 | "typescript": "^4.0.2" 16 | } 17 | } -------------------------------------------------------------------------------- /umjunsik-lang-node/src/index.ts: -------------------------------------------------------------------------------- 1 | import {promises as fs} from 'fs' 2 | import readline from 'readline-sync' 3 | 4 | function stringify(unicode: number) { 5 | return String.fromCharCode(unicode) 6 | } 7 | 8 | async function run(code: string) { 9 | const statements = code.trim().split(code.includes('~') ? '~' : '\n').map(line => line.trim()) 10 | 11 | if(statements[0] !== '어떻게' || !statements.slice(-1)[0].startsWith('이 사람이름이냐')) { 12 | throw new Error('Error: 어떻게 이 코드가 엄랭이냐ㅋㅋ') 13 | } 14 | 15 | const variables: number[] = [] 16 | let pointer = 0 17 | 18 | const evaluate = async (x: string): Promise => { 19 | let n = 0 20 | if(x.includes(' ')) return (await Promise.all(x.split(' ').map(evaluate))).reduce((a, b) => a * b) 21 | if(x.includes('식?')) { 22 | const answer= readline.question(); 23 | x = x.replace('식?', '.'.repeat(Number(answer))) 24 | } 25 | if(x.includes('어')) n += variables[x.split('어').length - 1] 26 | if(x.includes('.')) n += x.split('.').length - 1 27 | if(x.includes(',')) n -= x.split(',').length - 1 28 | return n 29 | } 30 | 31 | const execute = async (statement: string): Promise => { 32 | if (statement.includes('동탄') && statement.includes('?')) { // IF GOTO 33 | const condition = await evaluate(statement.substring(2, statement.lastIndexOf('?') + 1)) 34 | if (condition === 0) { 35 | return execute(statement.substr(statement.lastIndexOf('?') + 1)) 36 | } 37 | return 38 | } 39 | 40 | if(statement.includes('엄')) { 41 | const variablePointer = statement.split('엄')[0].split('어').length 42 | const setteeValue = await evaluate(statement.split('엄')[1]) 43 | variables[variablePointer] = setteeValue 44 | } 45 | 46 | if (statement.includes('식') && statement[statement.length - 1] === '!') { 47 | process.stdout.write(String(await evaluate(statement.slice(1, -1)))) 48 | } 49 | 50 | if (statement.includes('식') && statement[statement.length - 1] === 'ㅋ') { 51 | if (statement === '식ㅋ') process.stdout.write('\n') 52 | process.stdout.write(stringify(await evaluate(statement.slice(1, -1)))) 53 | } 54 | 55 | if(statement.includes('준')) { 56 | pointer = await evaluate(statement.split('준')[1]) - 1 57 | } 58 | 59 | if (statement.indexOf('화이팅!') === 0) { 60 | return evaluate(statement.split('화이팅!')[1]) 61 | } 62 | } 63 | 64 | while(!statements[pointer].startsWith('이 사람이름이냐')) { 65 | const statement = statements[pointer++] 66 | const evaluated = await execute(statement) 67 | if(evaluated) return evaluated 68 | } 69 | } 70 | 71 | async function bootstrap(path: string) { 72 | try { 73 | try { 74 | await fs.access(path) 75 | } catch(e) { 76 | throw new Error(`Error: ${path}가 어떻게 파일이름이냐ㅋㅋ`) 77 | } 78 | 79 | await run((await fs.readFile(path, 'utf-8'))) 80 | } catch(e) { 81 | process.stderr.write(`${e.message}\n`) 82 | } 83 | } 84 | 85 | if(process.argv[2]) bootstrap(process.argv[2]) -------------------------------------------------------------------------------- /umjunsik-lang-node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "outDir": "dist", 6 | "esModuleInterop": true 7 | }, 8 | "include": [ 9 | "src" 10 | ] 11 | } -------------------------------------------------------------------------------- /umjunsik-lang-node/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/node@^14.6.4": 6 | version "14.10.1" 7 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.10.1.tgz#cc323bad8e8a533d4822f45ce4e5326f36e42177" 8 | integrity sha512-aYNbO+FZ/3KGeQCEkNhHFRIzBOUgc7QvcVNKXbfnhDkSfwUv91JsQQa10rDgKSTSLkXZ1UIyPe4FJJNVgw1xWQ== 9 | 10 | "@types/readline-sync@^1.4.3": 11 | version "1.4.3" 12 | resolved "https://registry.yarnpkg.com/@types/readline-sync/-/readline-sync-1.4.3.tgz#eac55a39d5a349912062c9e5216cd550c07fd9c8" 13 | integrity sha512-YP9NVli96E+qQLAF2db+VjnAUEeZcFVg4YnMgr8kpDUFwQBnj31rPLOVHmazbKQhaIkJ9cMHsZhpKdzUeL0KTg== 14 | 15 | readline-sync@^1.4.10: 16 | version "1.4.10" 17 | resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" 18 | integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== 19 | 20 | typescript@^4.0.2: 21 | version "4.0.2" 22 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2" 23 | integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ== 24 | -------------------------------------------------------------------------------- /umjunsik-lang-python/__init__.py: -------------------------------------------------------------------------------- 1 | from .runtime import Umjunsik -------------------------------------------------------------------------------- /umjunsik-lang-python/__main__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from .runtime import Umjunsik 3 | 4 | def main(): 5 | if len(sys.argv) != 2: 6 | print("Usage: umjunsik ") 7 | sys.exit(1) 8 | 9 | filename = sys.argv[1] 10 | with open(filename, "r", encoding="UTF-8") as file: 11 | code = file.read() 12 | 13 | interpreter = Umjunsik() 14 | interpreter.compile(code) 15 | 16 | if __name__ == "__main__": 17 | main() -------------------------------------------------------------------------------- /umjunsik-lang-python/runtime.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | class Umjunsik: 5 | def __init__(self): 6 | self.data = [0]*256 7 | 8 | def toNumber(self, code): 9 | tokens = code.split(' ') 10 | result = 1 11 | for token in tokens: 12 | num = (self.data[token.count('어') - 1] if token.count('어') else 0) + token.count('.') - token.count(',') 13 | result *= num 14 | return result 15 | 16 | @staticmethod 17 | def type(code): 18 | if '동탄' in code: 19 | return 'IF' 20 | if '준' in code: 21 | return 'MOVE' 22 | if '화이팅!' in code: 23 | return 'END' 24 | if '식' in code and '?' in code: 25 | return 'INPUT' 26 | if '식' in code and '!' in code: 27 | return 'PRINT' 28 | if '식' in code and 'ㅋ' in code: 29 | return 'PRINTASCII' 30 | if '엄' in code: 31 | return 'DEF' 32 | 33 | def compileLine(self, code): 34 | if code == '': 35 | return None 36 | TYPE = self.type(code) 37 | 38 | if TYPE == 'DEF': 39 | var, cmd = code.split('엄') 40 | self.data[var.count('어')] = self.toNumber(cmd) 41 | elif TYPE == 'END': 42 | print(self.toNumber(code.split('화이팅!')[1]), end='') 43 | sys.exit() 44 | elif TYPE == 'INPUT': 45 | self.data[code.replace('식?', '').count('어')] = int(input()) 46 | elif TYPE == 'PRINT': 47 | print(self.toNumber(code[1:-1]), end='') 48 | elif TYPE == 'PRINTASCII': 49 | value = self.toNumber(code[1:-1]) 50 | print(chr(value) if value else '\n', end='') 51 | elif TYPE == 'IF': 52 | cond, cmd = code.replace('동탄', '').split('?') 53 | if self.toNumber(cond) == 0: 54 | return cmd 55 | elif TYPE == 'MOVE': 56 | return self.toNumber(code.replace('준', '')) 57 | 58 | def compile(self, code, check=True, errors=100000): 59 | jun = False 60 | recode = '' 61 | spliter = '\n' if '\n' in code else '~' 62 | code = code.rstrip().split(spliter) 63 | if check and (code[0].replace(" ","") != '어떻게' or code[-1] != '이 사람이름이냐ㅋㅋ' or not code[0].startswith('어떻게')): 64 | raise SyntaxError('어떻게 이게 엄랭이냐!') 65 | index = 0 66 | error = 0 67 | while index < len(code): 68 | errorline = index 69 | c = code[index].strip() 70 | res = self.compileLine(c) 71 | if jun: 72 | jun = False 73 | code[index] = recode 74 | if isinstance(res, int): 75 | index = res-2 76 | if isinstance(res, str): 77 | recode = code[index] 78 | code[index] = res 79 | index -= 1 80 | jun = True 81 | 82 | index += 1 83 | error += 1 84 | if error == errors: 85 | raise RecursionError(str(errorline+1) + '번째 줄에서 무한 루프가 감지되었습니다.') 86 | 87 | def compilePath(self, path): 88 | with open(path) as file: 89 | code = ''.join(file.readlines()) 90 | self.compile(code) -------------------------------------------------------------------------------- /umjunsik-lang-rust/.gitignore: -------------------------------------------------------------------------------- 1 | /Cargo.lock 2 | /target 3 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["lib", "interpreter", "compiler"] 3 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/README.md: -------------------------------------------------------------------------------- 1 | # umjunsik-lang-rust 2 | 3 | 엄랭의 Rust 구현체입니다. 현재 파서(umjunsik, `/lib`)와 인터프리터(rummi, `/interpreter`), 4 | 컴파일러(rummc, `/compiler`)가 개발되어 있습니다. 5 | 6 | ## 인터프리터 7 | 8 | `cargo run -p rummi`로 REPL을, `cargo run -p rummi -- <파일명>`으로 코드 파일을 실행할 수 있습니다. 9 | 10 | ## 컴파일러 11 | 12 | `cargo run -p rummc -- <파일명> -o <출력 파일명>`로 object 파일을 생성할 수 있습니다. 13 | 14 | 이후 `gcc -o <실행 파일명> `이나 15 | `clang -o <실행 파일명> `으로 실행 파일을 생성할 수 있습니다. 16 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/compiler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rummc" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = { version = "3.0.14", features = ["derive"] } 10 | guess_host_triple = "0.1.3" 11 | inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = [ 12 | "llvm10-0", 13 | ] } 14 | umjunsik = { version = "0.1.0", path = "../lib" } 15 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/compiler/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::RefCell, collections::HashMap, path::Path}; 2 | 3 | use clap::Parser; 4 | use guess_host_triple::guess_host_triple; 5 | use inkwell::{ 6 | basic_block::BasicBlock, 7 | builder::Builder, 8 | context::Context, 9 | module::{Linkage, Module}, 10 | targets::{CodeModel, FileType, RelocMode, Target, TargetTriple}, 11 | values::{FunctionValue, IntValue, PointerValue}, 12 | AddressSpace, IntPredicate, OptimizationLevel, 13 | }; 14 | use umjunsik::ast::{Load, Multiply, Program, Statement, Term}; 15 | 16 | /// Umjunsik-lang LLVM Compiler 17 | #[derive(Parser, Debug)] 18 | #[clap(author, version, about)] 19 | struct Args { 20 | /// Name of source file 21 | input: String, 22 | /// Output file name 23 | #[clap(long, short)] 24 | output: String, 25 | #[clap(long, short)] 26 | /// Compile target triple 27 | target: Option, 28 | /// Target features 29 | #[clap(long, short, default_value = "")] 30 | features: String, 31 | /// Optimize aggressively if set 32 | #[clap(long, short = 'O')] 33 | optimize: bool, 34 | } 35 | 36 | fn main() { 37 | let args = Args::parse(); 38 | let path = Path::new(&args.input); 39 | 40 | let code = std::fs::read_to_string(&args.input).expect("파일을 읽는 도중 오류가 발생했습니다."); 41 | 42 | let (_, program) = 43 | umjunsik::parser::parse_program(code.trim()).expect("코드의 문법이 맞지 않습니다."); 44 | 45 | let context = Context::create(); 46 | let module = context.create_module(path.file_name().unwrap().to_str().unwrap()); 47 | Target::initialize_all(&Default::default()); 48 | let host_triple = args 49 | .target 50 | .as_deref() 51 | .or_else(|| guess_host_triple()) 52 | .expect("빌드 타겟을 직접 지정해주세요."); 53 | let triple = TargetTriple::create(&host_triple); 54 | let target = Target::from_triple(&triple).expect("지원하지 않는 타겟입니다."); 55 | let level = if args.optimize { 56 | OptimizationLevel::Aggressive 57 | } else { 58 | OptimizationLevel::None 59 | }; 60 | let machine = target 61 | .create_target_machine( 62 | &triple, 63 | "", 64 | &args.features, 65 | level, 66 | RelocMode::Default, 67 | CodeModel::Default, 68 | ) 69 | .expect("지원하지 않는 타겟입니다."); 70 | let builder = context.create_builder(); 71 | let main_func = module.add_function( 72 | "main", 73 | context.i32_type().fn_type(&[], false), 74 | Some(Linkage::External), 75 | ); 76 | let entry = context.append_basic_block(main_func, "entry"); 77 | let compiler = Compiler { 78 | context: &context, 79 | builder: &builder, 80 | module: &module, 81 | main_func, 82 | main_block: entry, 83 | vars: HashMap::new().into(), 84 | }; 85 | compiler.compile_program(&program); 86 | 87 | compiler 88 | .module 89 | .verify() 90 | .expect("컴파일 오류가 발생했습니다."); 91 | 92 | machine 93 | .write_to_file(&module, FileType::Object, args.output.as_ref()) 94 | .expect("출력 중 오류가 발생했습니다."); 95 | } 96 | 97 | struct Compiler<'ctx, 'a> { 98 | context: &'ctx Context, 99 | builder: &'a Builder<'ctx>, 100 | module: &'a Module<'ctx>, 101 | main_func: FunctionValue<'ctx>, 102 | main_block: BasicBlock<'ctx>, 103 | vars: RefCell>>, 104 | } 105 | 106 | impl Compiler<'_, '_> { 107 | fn compile_print_int(&self) { 108 | let i32_type = self.context.i32_type(); 109 | let printf_type = i32_type.fn_type( 110 | &[self 111 | .context 112 | .i8_type() 113 | .ptr_type(AddressSpace::Generic) 114 | .into()], 115 | true, 116 | ); 117 | let printf = self 118 | .module 119 | .add_function("printf", printf_type, Some(Linkage::External)); 120 | 121 | let func_type = self.context.void_type().fn_type(&[i32_type.into()], false); 122 | let func = self.module.add_function("print_int", func_type, None); 123 | let entry = self.context.append_basic_block(func, "entry"); 124 | 125 | self.builder.position_at_end(entry); 126 | let format_str = self 127 | .builder 128 | .build_global_string_ptr("%d", "format") 129 | .as_pointer_value(); 130 | self.builder.build_call( 131 | printf, 132 | &[format_str.into(), func.get_first_param().unwrap().into()], 133 | "call_printf", 134 | ); 135 | self.builder.build_return(None); 136 | } 137 | 138 | fn compile_print_char(&self) { 139 | let i32_type = self.context.i32_type(); 140 | let putchar_type = i32_type.fn_type(&[i32_type.into()], false); 141 | let putchar = self 142 | .module 143 | .add_function("putchar", putchar_type, Some(Linkage::External)); 144 | 145 | let func_type = self.context.void_type().fn_type(&[i32_type.into()], false); 146 | let func = self.module.add_function("print_char", func_type, None); 147 | let entry = self.context.append_basic_block(func, "entry"); 148 | 149 | self.builder.position_at_end(entry); 150 | self.builder.build_call( 151 | putchar, 152 | &[func.get_first_param().unwrap().into()], 153 | "call_putchar", 154 | ); 155 | self.builder.build_return(None); 156 | } 157 | 158 | fn compile_read_int(&self) { 159 | let i32_type = self.context.i32_type(); 160 | let scanf_type = i32_type.fn_type( 161 | &[self 162 | .context 163 | .i8_type() 164 | .ptr_type(AddressSpace::Generic) 165 | .into()], 166 | true, 167 | ); 168 | let scanf = self 169 | .module 170 | .add_function("scanf", scanf_type, Some(Linkage::External)); 171 | 172 | let func_type = i32_type.fn_type(&[], false); 173 | let func = self.module.add_function("read_int", func_type, None); 174 | let basic_block = self.context.append_basic_block(func, "entry"); 175 | 176 | self.builder.position_at_end(basic_block); 177 | 178 | let format = self 179 | .builder 180 | .build_global_string_ptr("%d", "format") 181 | .as_pointer_value(); 182 | let temp = self.builder.build_alloca(i32_type, "temp"); 183 | self.builder 184 | .build_call(scanf, &[format.into(), temp.into()], "call_scanf"); 185 | let ret = self.builder.build_load(temp, "load_temp").into_int_value(); 186 | self.builder.build_return(Some(&ret)); 187 | } 188 | 189 | fn get_ptr(&self, index: usize) -> PointerValue { 190 | let current = self.builder.get_insert_block().unwrap(); 191 | self.builder.position_at_end(self.main_block); 192 | let mut vars = self.vars.borrow_mut(); 193 | let ptr = vars.entry(index).or_insert_with(|| { 194 | self.builder 195 | .build_alloca(self.context.i32_type(), &format!("var_{}", index)) 196 | }); 197 | self.builder.position_at_end(current); 198 | *ptr 199 | } 200 | 201 | fn compile_load(&self, int: &Load) -> IntValue { 202 | self.builder 203 | .build_load(self.get_ptr(int.index), &format!("load_{}", int.index)) 204 | .into_int_value() 205 | } 206 | 207 | fn compile_term(&self, term: &Term) -> IntValue { 208 | let i32_type = self.context.i32_type(); 209 | let base = term 210 | .load 211 | .as_ref() 212 | .map(|load| self.compile_load(load)) 213 | .unwrap_or_else(|| i32_type.const_zero()); 214 | let added = 215 | self.builder 216 | .build_int_add(base, i32_type.const_int(term.add as u64, true), "add"); 217 | let mut inputs = added; 218 | let read_int = self.module.get_function("read_int").unwrap(); 219 | for _ in 0..term.input { 220 | let call = self 221 | .builder 222 | .build_call(read_int, &[], "read_int") 223 | .try_as_basic_value() 224 | .left() 225 | .unwrap() 226 | .into_int_value(); 227 | inputs = self.builder.build_int_add(inputs, call, "add_input"); 228 | } 229 | inputs 230 | } 231 | 232 | fn compile_multiply(&self, multiply: &Multiply) -> IntValue { 233 | let mut prod = self.compile_term(&multiply.terms[0]); 234 | for term in &multiply.terms[1..] { 235 | prod = self 236 | .builder 237 | .build_int_mul(prod, self.compile_term(term), "mul"); 238 | } 239 | prod 240 | } 241 | 242 | fn compile_statement( 243 | &self, 244 | next: BasicBlock, 245 | statement: &Statement, 246 | blocks: &[BasicBlock], 247 | addrs: PointerValue, 248 | ) { 249 | match statement { 250 | Statement::Assign { index, value } => { 251 | let value = value 252 | .as_ref() 253 | .map(|multiply| self.compile_multiply(multiply)) 254 | .unwrap_or_else(|| self.context.i32_type().const_zero()); 255 | self.builder.build_store(self.get_ptr(*index), value); 256 | self.builder.build_unconditional_branch(next); 257 | } 258 | Statement::PrintInt { value } => { 259 | let value = value 260 | .as_ref() 261 | .map(|multiply| self.compile_multiply(multiply)) 262 | .unwrap_or_else(|| self.context.i32_type().const_zero()); 263 | let print_int = self.module.get_function("print_int").unwrap(); 264 | self.builder 265 | .build_call(print_int, &[value.into()], "call_print_int"); 266 | self.builder.build_unconditional_branch(next); 267 | } 268 | Statement::PrintChar { codepoint } => { 269 | let codepoint = codepoint 270 | .as_ref() 271 | .map(|multiply| self.compile_multiply(multiply)) 272 | .unwrap_or_else(|| self.context.i32_type().const_int(10, false)); 273 | let print_char = self.module.get_function("print_char").unwrap(); 274 | self.builder 275 | .build_call(print_char, &[codepoint.into()], "call_print_char"); 276 | self.builder.build_unconditional_branch(next); 277 | } 278 | Statement::If { 279 | condition, 280 | statement, 281 | } => { 282 | let condition = condition 283 | .as_ref() 284 | .map(|multiply| self.compile_multiply(multiply)) 285 | .unwrap_or_else(|| self.context.i32_type().const_zero()); 286 | let condition = self.builder.build_int_compare( 287 | IntPredicate::EQ, 288 | condition, 289 | self.context.i32_type().const_zero(), 290 | "if_condition", 291 | ); 292 | let then_block = self.context.append_basic_block(self.main_func, "then"); 293 | self.builder 294 | .build_conditional_branch(condition, then_block, next); 295 | self.builder.position_at_end(then_block); 296 | self.compile_statement(next, statement, blocks, addrs); 297 | } 298 | Statement::Goto { line } => { 299 | let line = self.compile_multiply(line); 300 | let minus_one = self.context.i32_type().const_int(1, false); 301 | let line_minus_one = self 302 | .builder 303 | .build_int_sub(line, minus_one, "goto_minus_one"); 304 | let zero = self.context.i32_type().const_zero(); 305 | let address_ptr = unsafe { 306 | self.builder.build_in_bounds_gep( 307 | addrs, 308 | &[zero, line_minus_one], 309 | "index_jump_addr", 310 | ) 311 | }; 312 | let address = self.builder.build_load(address_ptr, "fetch_jump_addr"); 313 | self.builder.build_indirect_branch(address, blocks); 314 | } 315 | Statement::Exit { code } => { 316 | let code = code 317 | .as_ref() 318 | .map(|multiply| self.compile_multiply(multiply)) 319 | .unwrap_or_else(|| self.context.i32_type().const_zero()); 320 | self.builder.build_return(Some(&code)); 321 | } 322 | } 323 | } 324 | 325 | fn compile_program(&self, program: &Program) { 326 | self.compile_read_int(); 327 | self.compile_print_int(); 328 | self.compile_print_char(); 329 | 330 | let mut blocks = vec![]; 331 | let mut addrs = vec![]; 332 | // https://llvm.org/docs/LangRef.html 333 | // blockaddress always has i8 addrspace(P)* type 334 | let addr_type = self.context.i8_type().ptr_type(AddressSpace::Generic); 335 | // safety: addrs must be used only in build_indirect_branch 336 | for _ in 0..program.statements.len() { 337 | let block = self.context.append_basic_block(self.main_func, "statement"); 338 | blocks.push(block); 339 | // panic safety: entry block is self.context.main_block 340 | addrs.push(unsafe { block.get_address() }.unwrap()); 341 | } 342 | let addr_array = addr_type.const_array(&addrs); 343 | let addrs = self.module.add_global( 344 | addr_type.array_type(addrs.len() as u32), 345 | None, 346 | "block_addrs", 347 | ); 348 | addrs.set_initializer(&addr_array); 349 | 350 | let end = self.context.append_basic_block(self.main_func, "end"); 351 | self.builder.position_at_end(end); 352 | self.builder 353 | .build_return(Some(&self.context.i32_type().const_zero())); 354 | blocks.push(end); 355 | 356 | for (i, (&block, statement)) in blocks.iter().zip(&program.statements).enumerate() { 357 | self.builder.position_at_end(block); 358 | if let Some(statement) = statement { 359 | self.compile_statement(blocks[i + 1], statement, &blocks, addrs.as_pointer_value()); 360 | } else { 361 | self.builder.build_unconditional_branch(blocks[i + 1]); 362 | } 363 | } 364 | 365 | self.builder.position_at_end(self.main_block); 366 | self.builder.build_unconditional_branch(blocks[0]); 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/interpreter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rummi" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["kiwiyou "] 6 | 7 | [dependencies] 8 | clap = { version = "3.0.13", features = ["derive"] } 9 | umjunsik = { version = "0.1.0", path = "../lib" } 10 | whiteread = "0.5.0" 11 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/interpreter/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, fmt::Display, io::Write}; 2 | 3 | use clap::Parser; 4 | use umjunsik::{ 5 | ast::{Load, Multiply, Statement}, 6 | parser::parse_statement, 7 | }; 8 | use whiteread::Reader; 9 | 10 | /// Umjunsik-lang REPL / Interpreter 11 | #[derive(Parser, Debug)] 12 | #[clap(author, version, about)] 13 | struct Args { 14 | /// Name of source file 15 | input: Option, 16 | } 17 | 18 | fn main() { 19 | let args = Args::parse(); 20 | 21 | let exit_code = if let Some(input) = args.input { 22 | let code = std::fs::read_to_string(&input).expect("파일을 읽는 도중 오류가 발생했습니다."); 23 | interpret(code.trim()) 24 | } else { 25 | repl().expect("REPL 실행 중 오류가 발생했습니다.") 26 | }; 27 | std::process::exit(exit_code); 28 | } 29 | 30 | fn repl() -> std::io::Result { 31 | let stdin = std::io::stdin(); 32 | let mut ctx = Context { 33 | len: 0, 34 | pc: 0, 35 | vars: HashMap::new(), 36 | exit: None, 37 | reader: Reader::new(stdin.lock()), 38 | }; 39 | let mut input = String::new(); 40 | while ctx.exit.is_none() { 41 | print!("> "); 42 | std::io::stdout().flush()?; 43 | input.clear(); 44 | let read = std::io::stdin().read_line(&mut input)?; 45 | if read == 0 { 46 | break; 47 | } 48 | if let Ok((_, statement)) = parse_statement(&input) { 49 | if let Err(e) = run_statement(&mut ctx, &statement) { 50 | eprintln!("{}", e); 51 | } 52 | println!(); 53 | } else { 54 | eprintln!("코드의 문법이 맞지 않습니다."); 55 | } 56 | } 57 | Ok(ctx.exit.unwrap_or(0)) 58 | } 59 | 60 | fn interpret(code: &str) -> i32 { 61 | let (_, program) = umjunsik::parser::parse_program(code).expect("코드의 문법이 맞지 않습니다."); 62 | 63 | let stdin = std::io::stdin(); 64 | let mut ctx = Context { 65 | len: program.statements.len(), 66 | pc: 0, 67 | vars: HashMap::new(), 68 | exit: None, 69 | reader: Reader::new(stdin.lock()), 70 | }; 71 | while ctx.pc < ctx.len { 72 | if let Some(statement) = &program.statements[ctx.pc] { 73 | ctx.pc += 1; 74 | let pc = ctx.pc; 75 | if let Err(e) = run_statement(&mut ctx, statement) { 76 | eprintln!("{}번째 줄: {}", pc, e); 77 | ctx.exit = Some(-1); 78 | } 79 | } else { 80 | ctx.pc += 1; 81 | } 82 | if ctx.exit.is_some() { 83 | break; 84 | } 85 | } 86 | ctx.exit.unwrap_or(0) 87 | } 88 | 89 | struct Context<'a> { 90 | len: usize, 91 | pc: usize, 92 | vars: HashMap, 93 | exit: Option, 94 | reader: whiteread::Reader>, 95 | } 96 | 97 | enum Error { 98 | GotoOutOfRange, 99 | UnicodeOutOfRange, 100 | InputNotNumber, 101 | } 102 | 103 | impl Display for Error { 104 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 105 | match self { 106 | Self::GotoOutOfRange => write!(f, "\"준\" 명령에 주어진 줄 수가 범위를 벗어났습니다."), 107 | Self::UnicodeOutOfRange => { 108 | write!(f, "\"식ㅋ\" 명령에 주어진 유니코드가 범위를 벗어났습니다.") 109 | } 110 | Self::InputNotNumber => write!(f, "입력이 수가 아닙니다."), 111 | } 112 | } 113 | } 114 | 115 | fn run_statement(ctx: &mut Context, statement: &Statement) -> Result<(), Error> { 116 | match statement { 117 | Statement::Assign { index, value } => { 118 | let value = match value { 119 | Some(multiply) => get_multiply(ctx, multiply)?, 120 | None => 0, 121 | }; 122 | ctx.vars 123 | .entry(*index) 124 | .and_modify(|v| *v = value) 125 | .or_insert(value); 126 | } 127 | Statement::PrintInt { value } => { 128 | let value = match value { 129 | Some(multiply) => get_multiply(ctx, multiply)?, 130 | None => 0, 131 | }; 132 | print!("{}", value); 133 | } 134 | Statement::PrintChar { codepoint } => { 135 | let char = match codepoint { 136 | Some(multiply) => { 137 | let code: u32 = get_multiply(ctx, multiply)? 138 | .try_into() 139 | .map_err(|_| Error::UnicodeOutOfRange)?; 140 | char::from_u32(code).ok_or(Error::UnicodeOutOfRange)? 141 | } 142 | None => '\n', 143 | }; 144 | print!("{}", char); 145 | } 146 | Statement::If { 147 | condition, 148 | statement, 149 | } => { 150 | let condition = match condition { 151 | Some(multiply) => get_multiply(ctx, multiply)?, 152 | None => 0, 153 | }; 154 | if condition == 0 { 155 | return run_statement(ctx, statement.as_ref()); 156 | } 157 | } 158 | Statement::Goto { line } => { 159 | let line = get_multiply(ctx, line)?; 160 | if 1 <= line && (line as usize) <= ctx.len { 161 | ctx.pc = line as usize - 1; 162 | } else { 163 | return Err(Error::GotoOutOfRange); 164 | } 165 | } 166 | Statement::Exit { code } => { 167 | let code = match code { 168 | Some(multiply) => get_multiply(ctx, multiply)?, 169 | None => 0, 170 | }; 171 | ctx.exit = Some(code); 172 | } 173 | } 174 | Ok(()) 175 | } 176 | 177 | fn get_multiply(ctx: &mut Context, multiply: &Multiply) -> Result { 178 | let mut result = 1i32; 179 | for term in &multiply.terms { 180 | let load = term 181 | .load 182 | .as_ref() 183 | .map(|&Load { index }| *ctx.vars.entry(index).or_insert(0)) 184 | .unwrap_or(0); 185 | let mut term_value = load.wrapping_add(term.add); 186 | for _ in 0..term.input { 187 | let add = ctx.reader.parse().map_err(|_| Error::InputNotNumber)?; 188 | term_value = term_value.wrapping_add(add); 189 | } 190 | let new_result = result.wrapping_mul(term_value); 191 | result = new_result; 192 | } 193 | Ok(result) 194 | } 195 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "umjunsik" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["kiwiyou "] 6 | 7 | [features] 8 | 9 | [dependencies] 10 | nom = "7.1.0" 11 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/lib/src/ast.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq)] 2 | pub struct Load { 3 | pub index: usize, 4 | } 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub struct Term { 8 | pub load: Option, 9 | pub add: i32, 10 | pub input: usize, 11 | } 12 | 13 | #[derive(Debug, PartialEq)] 14 | pub struct Multiply { 15 | pub terms: Vec, 16 | } 17 | 18 | #[derive(Debug, PartialEq)] 19 | pub enum Statement { 20 | Assign { 21 | index: usize, 22 | value: Option, 23 | }, 24 | PrintInt { 25 | value: Option, 26 | }, 27 | PrintChar { 28 | codepoint: Option, 29 | }, 30 | If { 31 | condition: Option, 32 | statement: Box, 33 | }, 34 | Goto { 35 | line: Multiply, 36 | }, 37 | Exit { 38 | code: Option, 39 | }, 40 | } 41 | 42 | #[derive(Debug, PartialEq)] 43 | pub struct Program { 44 | pub statements: Vec>, 45 | } 46 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod ast; 2 | pub mod parser; 3 | -------------------------------------------------------------------------------- /umjunsik-lang-rust/lib/src/parser.rs: -------------------------------------------------------------------------------- 1 | use nom::{ 2 | branch::alt, 3 | bytes::complete::tag, 4 | combinator::{all_consuming, map, opt}, 5 | multi::{fold_many0, fold_many1, many0_count, many1_count, separated_list1}, 6 | sequence::{delimited, pair, preceded, terminated, tuple}, 7 | IResult, 8 | }; 9 | 10 | use super::ast::*; 11 | 12 | pub type ParseResult<'a, T> = IResult<&'a str, T>; 13 | 14 | pub fn parse_load(s: &str) -> ParseResult { 15 | map(many1_count(tag("어")), |count| Load { index: count })(s) 16 | } 17 | 18 | fn parse_add_fragment(s: &str) -> ParseResult { 19 | map(many1_count(tag(".")), |count| count as i32)(s) 20 | } 21 | 22 | fn parse_sub_fragment(s: &str) -> ParseResult { 23 | map(many1_count(tag(",")), |count| -(count as i32))(s) 24 | } 25 | 26 | fn parse_input_fragment(s: &str) -> ParseResult { 27 | many1_count(tag("식?"))(s) 28 | } 29 | 30 | enum AddSubOrInput { 31 | AddSub(i32), 32 | Input(usize), 33 | } 34 | 35 | fn parse_input_or_add_sub(s: &str) -> ParseResult { 36 | alt(( 37 | map(parse_add_fragment, AddSubOrInput::AddSub), 38 | map(parse_sub_fragment, AddSubOrInput::AddSub), 39 | map(parse_input_fragment, AddSubOrInput::Input), 40 | ))(s) 41 | } 42 | 43 | fn parse_add(s: &str) -> ParseResult<(i32, usize)> { 44 | fold_many1( 45 | parse_input_or_add_sub, 46 | || (0, 0), 47 | |(add_sub, input), bit| match bit { 48 | AddSubOrInput::AddSub(a) => (add_sub + a, input), 49 | AddSubOrInput::Input(i) => (add_sub, input + i), 50 | }, 51 | )(s) 52 | } 53 | 54 | pub fn parse_term(s: &str) -> ParseResult { 55 | alt(( 56 | map(pair(opt(parse_load), parse_add), |(load, (add, input))| { 57 | Term { load, add, input } 58 | }), 59 | map(parse_load, |load| Term { 60 | load: Some(load), 61 | add: 0, 62 | input: 0, 63 | }), 64 | ))(s) 65 | } 66 | 67 | pub fn parse_multiply(s: &str) -> ParseResult { 68 | map(separated_list1(tag(" "), parse_term), |terms| Multiply { 69 | terms, 70 | })(s) 71 | } 72 | 73 | pub fn parse_statement(s: &str) -> ParseResult { 74 | alt(( 75 | map( 76 | tuple((many0_count(tag("어")), tag("엄"), opt(parse_multiply))), 77 | |(len, _, a)| Statement::Assign { 78 | index: len + 1, 79 | value: a, 80 | }, 81 | ), 82 | map(delimited(tag("식"), opt(parse_multiply), tag("!")), |int| { 83 | Statement::PrintInt { value: int } 84 | }), 85 | map( 86 | delimited(tag("식"), opt(parse_multiply), tag("ㅋ")), 87 | |int| Statement::PrintChar { codepoint: int }, 88 | ), 89 | map( 90 | tuple((tag("동탄"), opt(parse_multiply), tag("?"), parse_statement)), 91 | |(_, int, _, statement)| Statement::If { 92 | condition: int, 93 | statement: Box::new(statement), 94 | }, 95 | ), 96 | map(preceded(tag("준"), parse_multiply), |int| { 97 | Statement::Goto { line: int } 98 | }), 99 | map(preceded(tag("화이팅!"), opt(parse_multiply)), |int| { 100 | Statement::Exit { code: int } 101 | }), 102 | ))(s) 103 | } 104 | 105 | fn parse_newline(s: &str) -> ParseResult<()> { 106 | map(alt((tag("\n"), tag("\r"), tag("~"))), |_| ())(s) 107 | } 108 | 109 | pub fn parse_program(s: &str) -> ParseResult { 110 | let (s, _) = terminated(tag("어떻게"), parse_newline)(s)?; 111 | let (s, mut statements) = fold_many0( 112 | terminated(opt(parse_statement), parse_newline), 113 | || vec![None], 114 | |mut acc, stmt| { 115 | acc.push(stmt); 116 | acc 117 | }, 118 | )(s)?; 119 | let (s, _) = all_consuming(tag("이 사람이름이냐ㅋㅋ"))(s)?; 120 | statements.push(None); 121 | Ok((s, Program { statements })) 122 | } 123 | 124 | #[cfg(test)] 125 | mod test { 126 | use super::*; 127 | 128 | #[test] 129 | fn load_one() { 130 | assert_eq!(parse_load("어..").unwrap(), ("..", Load { index: 1 })); 131 | } 132 | 133 | #[test] 134 | fn load_many() { 135 | assert_eq!(parse_load("어어,").unwrap(), (",", Load { index: 2 })); 136 | } 137 | 138 | #[test] 139 | fn add_fragment() { 140 | assert_eq!(parse_add_fragment("......,,.").unwrap(), (",,.", 6)); 141 | } 142 | 143 | #[test] 144 | fn sub_fragment() { 145 | assert_eq!(parse_sub_fragment(",,.").unwrap(), (".", -2)); 146 | } 147 | 148 | #[test] 149 | fn input_fragment() { 150 | assert_eq!(parse_input_fragment("식?식?").unwrap(), ("", 2)); 151 | } 152 | 153 | #[test] 154 | fn add() { 155 | assert_eq!(parse_add("..,.식?,.,,식?,.").unwrap(), ("", (0, 2))); 156 | } 157 | 158 | #[test] 159 | fn term_composite() { 160 | assert_eq!( 161 | parse_term("어어..,").unwrap(), 162 | ( 163 | "", 164 | Term { 165 | load: Some(Load { index: 2 }), 166 | add: 1, 167 | input: 0 168 | } 169 | ) 170 | ); 171 | } 172 | 173 | #[test] 174 | fn term_only_load() { 175 | assert_eq!( 176 | parse_term("어어어").unwrap(), 177 | ( 178 | "", 179 | Term { 180 | load: Some(Load { index: 3 }), 181 | add: 0, 182 | input: 0 183 | } 184 | ) 185 | ); 186 | } 187 | 188 | #[test] 189 | fn term_only_add() { 190 | assert_eq!( 191 | parse_term("..,,,,.").unwrap(), 192 | ( 193 | "", 194 | Term { 195 | load: None, 196 | add: -1, 197 | input: 0 198 | } 199 | ) 200 | ); 201 | } 202 | 203 | #[test] 204 | fn multiply_one() { 205 | assert_eq!( 206 | parse_multiply("어..식?..").unwrap(), 207 | ( 208 | "", 209 | Multiply { 210 | terms: vec![Term { 211 | load: Some(Load { index: 1 }), 212 | add: 4, 213 | input: 1 214 | }] 215 | } 216 | ) 217 | ); 218 | } 219 | 220 | #[test] 221 | fn multiply_many() { 222 | assert_eq!( 223 | parse_multiply(".. , 어어.").unwrap(), 224 | ( 225 | "", 226 | Multiply { 227 | terms: vec![ 228 | Term { 229 | load: None, 230 | add: 2, 231 | input: 0 232 | }, 233 | Term { 234 | load: None, 235 | add: -1, 236 | input: 0 237 | }, 238 | Term { 239 | load: Some(Load { index: 2 }), 240 | add: 1, 241 | input: 0 242 | }, 243 | ] 244 | } 245 | ) 246 | ); 247 | } 248 | 249 | #[test] 250 | fn statement_assign() { 251 | assert_eq!( 252 | parse_statement("어엄식?").unwrap(), 253 | ( 254 | "", 255 | Statement::Assign { 256 | index: 2, 257 | value: Some(Multiply { 258 | terms: vec![Term { 259 | load: None, 260 | add: 0, 261 | input: 1, 262 | },], 263 | }), 264 | } 265 | ) 266 | ); 267 | } 268 | 269 | #[test] 270 | fn statement_print_int() { 271 | assert_eq!( 272 | parse_statement("식어어.. ..!").unwrap(), 273 | ( 274 | "", 275 | Statement::PrintInt { 276 | value: Some(Multiply { 277 | terms: vec![ 278 | Term { 279 | load: Some(Load { index: 2 }), 280 | add: 2, 281 | input: 0 282 | }, 283 | Term { 284 | load: None, 285 | add: 2, 286 | input: 0 287 | }, 288 | ] 289 | }) 290 | } 291 | ) 292 | ); 293 | } 294 | 295 | #[test] 296 | fn statement_print_char() { 297 | assert_eq!( 298 | parse_statement("식ㅋ").unwrap(), 299 | ("", Statement::PrintChar { codepoint: None }) 300 | ) 301 | } 302 | 303 | #[test] 304 | fn statement_if() { 305 | assert_eq!( 306 | parse_statement("동탄?동탄.?엄").unwrap(), 307 | ( 308 | "", 309 | Statement::If { 310 | condition: None, 311 | statement: Box::new(Statement::If { 312 | condition: Some(Multiply { 313 | terms: vec![Term { 314 | load: None, 315 | add: 1, 316 | input: 0 317 | }] 318 | }), 319 | statement: Box::new(Statement::Assign { 320 | index: 1, 321 | value: None 322 | }) 323 | }) 324 | } 325 | ) 326 | ); 327 | } 328 | 329 | #[test] 330 | fn program() { 331 | let program = "어떻게 332 | 333 | 엄식? 334 | 어엄식? 335 | 336 | 동탄어?준... .... 337 | 338 | 엄어, 339 | 어엄어어. 340 | 341 | 준.. ... 342 | 식어어! 343 | 344 | 이 사람이름이냐ㅋㅋ"; 345 | assert_eq!( 346 | parse_program(program).unwrap(), 347 | ( 348 | "", 349 | Program { 350 | statements: vec![ 351 | None, 352 | None, 353 | Some(Statement::Assign { 354 | index: 1, 355 | value: Some(Multiply { 356 | terms: vec![Term { 357 | load: None, 358 | add: 0, 359 | input: 1 360 | }] 361 | }) 362 | }), 363 | Some(Statement::Assign { 364 | index: 2, 365 | value: Some(Multiply { 366 | terms: vec![Term { 367 | load: None, 368 | add: 0, 369 | input: 1 370 | }] 371 | }) 372 | }), 373 | None, 374 | Some(Statement::If { 375 | condition: Some(Multiply { 376 | terms: vec![Term { 377 | load: Some(Load { index: 1 }), 378 | add: 0, 379 | input: 0 380 | }] 381 | }), 382 | statement: Box::new(Statement::Goto { 383 | line: Multiply { 384 | terms: vec![ 385 | Term { 386 | load: None, 387 | add: 3, 388 | input: 0 389 | }, 390 | Term { 391 | load: None, 392 | add: 4, 393 | input: 0 394 | } 395 | ] 396 | } 397 | }) 398 | }), 399 | None, 400 | Some(Statement::Assign { 401 | index: 1, 402 | value: Some(Multiply { 403 | terms: vec![Term { 404 | load: Some(Load { index: 1 }), 405 | add: -1, 406 | input: 0 407 | }] 408 | }) 409 | }), 410 | Some(Statement::Assign { 411 | index: 2, 412 | value: Some(Multiply { 413 | terms: vec![Term { 414 | load: Some(Load { index: 2 }), 415 | add: 1, 416 | input: 0 417 | }] 418 | }) 419 | }), 420 | None, 421 | Some(Statement::Goto { 422 | line: Multiply { 423 | terms: vec![ 424 | Term { 425 | load: None, 426 | add: 2, 427 | input: 0 428 | }, 429 | Term { 430 | load: None, 431 | add: 3, 432 | input: 0 433 | }, 434 | ] 435 | } 436 | }), 437 | Some(Statement::PrintInt { 438 | value: Some(Multiply { 439 | terms: vec![Term { 440 | load: Some(Load { index: 2 }), 441 | add: 0, 442 | input: 0, 443 | }] 444 | }) 445 | }), 446 | None, 447 | None, 448 | ] 449 | } 450 | ) 451 | ); 452 | } 453 | } 454 | -------------------------------------------------------------------------------- /umjunsik-lang-vba/Module1.vb: -------------------------------------------------------------------------------- 1 | Public initial_sound_is_allowed As Boolean, is_running As Boolean, is_debugging As Boolean, is_on_console As Boolean, blocking As Boolean, visual As Boolean 2 | Public current_command_row As Long, current_console_row As Long, last_command_row As Long 3 | Public prev_cell_row As Long, prev_cell_col As Long 4 | Public updated_max_var As Long, updated_min_var As Long, return_num As Long 5 | '사전에 입력한 입력값에서 아직 사용하지 않은 입력값의 위치 6 | Public has_input_list As Boolean 7 | Public input_to_use As Long 8 | 9 | Sub ClearAll() 10 | Worksheets("실행기").Range("E105:K1048576").ClearContents 11 | Worksheets("변수").Range("C5:C1048576").ClearContents 12 | Worksheets("변수").Range("G5:G1048576").ClearContents 13 | 14 | Worksheets("변수").Range("J5:J1048576").ClearContents 15 | 16 | With Range("K5:K1048576") '변수(양수) 17 | .Value = 0: .Font.ColorIndex = 1 18 | End With 19 | With Range("H16:H1048576") '변수(음수) 20 | .Value = 0: .Font.ColorIndex = 1 21 | End With 22 | Worksheets("변수").Range("C5:C1048576").Value = 0 '변경한 변수(양수) 23 | Worksheets("변수").Range("G5:G1048576").Value = 0 '변경한 변수(음수) 24 | End Sub 25 | 26 | Sub Clear() 27 | Worksheets("실행기").Range("E105:K1000").ClearContents 28 | Worksheets("실행기").Range("E5:F105").ClearContents 29 | Worksheets("변수").Range("C5:C1000").ClearContents 30 | Worksheets("변수").Range("G5:G1000").ClearContents 31 | End Sub 32 | 33 | Sub TransformInputs(ByRef error_code As Integer) 34 | Worksheets("변수").Range("J5:J1000").ClearContents 35 | 36 | Dim Str As String 37 | Dim prev_pos As Long, line As Long 38 | Str = vbNullString 39 | prev_pos = 1 40 | line = 1 41 | 42 | For i = 0 To 9 43 | current_command_row = i + 1 44 | Str = Cells(i + 5, 8).Value 45 | 46 | If (IsEmpty(Replace(Cells(i + 5, 8), " ", ""))) Then 47 | GoTo Trans_Continue1 48 | End If 49 | 50 | For j = 1 To Len(Str) 51 | Worksheets("변수").Cells(3, 10).Value = Mid(Str, j, 1) 52 | If (WorksheetFunction.IsNumber(Worksheets("변수").Cells(3, 10))) Then '0~9의 숫자 53 | If (Int(Mid(Str, j, 1)) - Mid(Str, j, 1) = 0) Then 54 | Worksheets("변수").Cells(line + 4, 10).Value = Worksheets("변수").Cells(line + 4, 10).Value & Mid(Str, j, 1) 55 | End If 56 | ElseIf (Mid(Str, j, 1) = "-") Then '-부호 57 | Worksheets("변수").Cells(line + 4, 10).Value = Worksheets("변수").Cells(line + 4, 10).Value & Mid(Str, j, 1) 58 | ElseIf (Mid(Str, j, 1) = " ") Then '공백 처리 59 | If (Not IsEmpty(Worksheets("변수").Cells(line + 4, 10))) Then '다음 저장 공간으로 이동 60 | line = line + 1 61 | Else '무시 62 | End If 63 | Else 64 | Call ErrorCode(-108) 65 | error_code = -108 66 | Exit Sub 67 | End If 68 | 69 | Worksheets("변수").Cells(3, 10).ClearContents 70 | Next 71 | 72 | If (Not IsEmpty(Worksheets("변수").Cells(line + 4, 10))) Then '다음 저장 공간으로 이동 73 | line = line + 1 74 | Else '무시 75 | End If 76 | 77 | Trans_Continue1: 78 | Next 79 | 80 | input_to_use = 1 81 | If (IsEmpty(Worksheets("변수").Cells(5, 10))) Then 82 | has_input_list = False 83 | Else 84 | has_input_list = True 85 | End If 86 | End Sub 87 | 88 | Sub OneLineToSeveralLine() 89 | Dim code, current_line 90 | code = Cells(1 + 4, 4).Value 91 | Cells(1 + 4, 4).ClearContents 92 | current_line = 1 93 | 94 | For i = 1 To Len(code) 95 | character = Mid(code, i, 1) 96 | If (character = "~") Then '줄바꿈 97 | current_line = current_line + 1 98 | Else 99 | Cells(current_line + 4, 4).Value = Cells(current_line + 4, 4).Value & character 100 | End If 101 | Next 102 | End Sub 103 | 104 | Sub Debug_code() 105 | If Not (is_running) Then '실행 중이 아니면 프로그램 실행 106 | is_debugging = True 107 | visual = False 108 | is_running = True 109 | is_on_console = False 110 | blocking = True 111 | has_input_list = False 112 | input_to_use = 0 113 | 114 | Call Clear 115 | 116 | Dim error_c As Integer 117 | error_c = 0 118 | 119 | Call TransformInputs(error_c) 120 | If (error_c <> 0) Then 121 | Call Stop_code 122 | Exit Sub 123 | Else 124 | Call start 125 | End If 126 | 127 | If (is_running) Then 128 | Call Stop_code 129 | Else '도중 종료가 일어났을 때 130 | If (return_num = 0) Then 131 | return_num = -1 '일반적인 오류 시 반환값 132 | End If 133 | End If 134 | 135 | Cells(current_console_row + 1 + 4, 6).Value = "Exited with code " & return_num 136 | 137 | ElseIf (is_debugging) Then '실행 중이면 중단된 프로그램을 계속 실행 138 | blocking = False 139 | End If 140 | End Sub 141 | 142 | Sub Init() 143 | If Not (is_running) Then '실행 중이 아니면 프로그램 실행 144 | is_debugging = False 145 | is_running = True 146 | is_on_console = False 147 | blocking = False 148 | has_input_list = False 149 | input_to_use = 0 150 | 151 | Call Clear 152 | 153 | Dim error_c As Integer 154 | error_c = 0 155 | 156 | Call TransformInputs(error_c) 157 | If (error_c <> 0) Then 158 | Call Stop_code 159 | Exit Sub 160 | Else 161 | Call start 162 | End If 163 | 164 | If (is_running) Then 165 | Call Stop_code 166 | Else '도중 종료가 일어났을 때 167 | If (return_num = 0) Then 168 | return_num = -1 '일반적인 오류 시 반환값 169 | End If 170 | End If 171 | 172 | Cells(current_console_row + 1 + 4, 6).Value = "Exited with code " & return_num 173 | ElseIf (blocking = True) Then '실행 중이면 중단된 프로그램을 계속 실행 174 | blocking = False 175 | End If 176 | End Sub 177 | 178 | Sub Stop_code() 179 | If Not (is_running) Then '이미 종료되었을 때 180 | Exit Sub 181 | End If 182 | 183 | is_running = False 184 | is_debugging = False 185 | blocking = False 186 | 187 | If (is_on_console) Then 188 | is_on_console = False 189 | End If 190 | 191 | Cells(current_console_row + 2 + 4, 5).Value = "$" 192 | Application.ScreenUpdating = True 193 | If (visual) Then 194 | Cells(current_console_row + 2 + 4, 6).Select 195 | End If 196 | End Sub 197 | 198 | Sub start() 199 | '변수 초기화 200 | With Range("K5:K1000") '변수(양수) 201 | .Value = 0: .Font.ColorIndex = 1 202 | End With 203 | With Range("H16:H1000") '변수(음수) 204 | .Value = 0: .Font.ColorIndex = 1 205 | End With 206 | Worksheets("변수").Range("C5:C1000").Value = 0 '변경한 변수(양수) 207 | Worksheets("변수").Range("G5:G1000").Value = 0 '변경한 변수(음수) 208 | Worksheets("실행기").Range("E5:F105").ClearContents 209 | Cells(5, 5).Value = "$" 210 | Cells(5, 6).Value = "umjunsik main.umm" 211 | 212 | current_command_row = 1 213 | current_console_row = 2 214 | 215 | prev_cell_row = current_command_row + 4 216 | prev_cell_col = 4 217 | 218 | Cells(current_command_row + 4, 4).Select 219 | '콘솔 입력 부분을 제외한 나머지 명령 처리는 Selection 대신 command 사용 220 | Dim command As Variant 221 | command = Selection.Value 222 | 223 | Dim error_code As Integer 224 | error_code = 0 225 | 226 | Dim count_for_visual As Integer 227 | count_for_visual = 0 228 | 229 | '반환값 230 | return_num = 0 231 | 232 | '초기화 완료된 화면을 업데이트 후 시각 효과 생략 233 | If Not (is_debugging) Then 234 | Application.Calculation = CalculationManual 235 | If (visual) Then 236 | Application.ScreenUpdating = False 237 | Application.EnableEvents = False 238 | End If 239 | End If 240 | 241 | '코드 첫 부분이 "어떻게"로 시작되는지 확인 242 | If Not (Cells(current_command_row + 4, 4).Value = "어떻게") Then 243 | ErrorCode (-101) 'Error 101 244 | Cells(current_command_row + 4, 4).Select 245 | return_num = -1 246 | Exit Sub 247 | End If 248 | 249 | 250 | '코드 마지막 부분에 "이 사람이름이냐ㅋㅋ"가 있는지 확인 251 | last_command_row = FindEndPoint 252 | If (last_command_row = -1) Then 253 | ErrorCode (-102) 'Error 102 254 | return_num = -1 255 | Exit Sub 256 | End If 257 | For Each cell1 In Range("B5:B1000") '중단점 외 모든 정보 삭제 258 | If (Not IsEmpty(cell1) And cell1.Value <> "?") Then 259 | cell1.ClearContents 260 | End If 261 | Next 262 | Cells(last_command_row + 4, 2).Value = "▲" 263 | 264 | 265 | '코드 실행 266 | Do 267 | current_command_row = current_command_row + 1 268 | 269 | Continue2: 270 | prev_cell_row = current_command_row + 4 271 | prev_cell_col = 4 '콘솔 입력 외의 상황 272 | 273 | If Not (visual) Then 274 | Cells(current_command_row + 4, 4).Select 275 | End If 276 | command = Cells(current_command_row + 4, 4).Value 277 | 278 | error_code = 0 279 | count_for_visual = count_for_visual + 1 280 | 281 | '마지막 부분에 도달하면 코드 종료 282 | If (Cells(current_command_row + 4, 2).Value = "▲") Then 283 | Exit Do 284 | End If 285 | 286 | If (Cells(current_command_row + 4, 2).Value = "?" Or Cells(current_command_row + 4, 2).Value = "¶") Then 287 | Cells(current_command_row + 4, 2).Value = "¶" 288 | blocking = True 289 | Else 290 | If (Cells(current_command_row + 4, 2).Value <> "▲") Then 291 | Cells(current_command_row + 4, 2).Value = "→" 292 | End If 293 | End If 294 | 295 | '조건문 속 명령은 여기서부터 실행 296 | IfCommand: 297 | 298 | '마지막 부분에 도달하면 코드 종료(조건문으로 도달 시) 299 | If (Cells(current_command_row + 4, 2).Value = "▲") Then 300 | Exit Do 301 | End If 302 | 303 | '앞뒤 공백 자르기 304 | command = Trim(command) 305 | 306 | '빈 줄은 무시 307 | If (Len(command) = 0) Then 308 | GoTo Continue1 309 | End If 310 | 311 | '변수 계산 312 | Dim variable_count As Long, number As Long, updated_var_row As Long, var_end_point As Long 313 | Dim is_called As Boolean 314 | is_called = False 315 | var_end_point = 1 316 | variable_count = 1 317 | number = 0 318 | updated_var_row = 0 319 | 320 | '콘솔 출력 321 | Dim output_char 322 | Dim is_numeral As Boolean 323 | 324 | Dim dongtan_end_point As Long 325 | dongtan_end_point = 0 326 | 327 | If (Cells(current_command_row + 4, 4).Value = "어떻게") Then '첫 번째 줄 328 | GoTo Continue1 329 | End If 330 | 331 | Select Case Mid(command, 1, 1) 332 | Case "엄", "어", "엌" '변수 대입 혹은 호출(출력) 333 | If (current_command_row = 1) Then '"어떻게" 334 | GoTo Continue1 335 | End If 336 | 337 | '대입할 변수 탐색 338 | variable_count = ParseVariable(command, 1, Len(command), var_end_point, is_called, error_code) 339 | If (error_code <> 0) Then 340 | Call ErrorCode(error_code) 341 | If (error_code < 0) Then 342 | return_num = -1 343 | Exit Sub 344 | End If 345 | ElseIf (is_called) Then 346 | Call ErrorCode(251) 'Warn 251 347 | End If 348 | 349 | error_code = 0 350 | 351 | '(뒤쪽에 수식이 있다면) 변수에 대입할 숫자 계산 352 | number = CalculateNumber(command, var_end_point + 1, Len(command), error_code) 353 | 354 | If (error_code <> 0) Then 355 | Call ErrorCode(error_code) 356 | If (error_code < 0) Then 357 | return_num = -1 358 | Exit Sub 359 | End If 360 | 361 | error_code = 0 362 | End If 363 | 364 | '변수에 값 대입 365 | Call MapVar(variable_count, number, error_code) 366 | 367 | If (error_code <> 0) Then 368 | Call ErrorCode(error_code) 369 | If (error_code < 0) Then 370 | return_num = -1 371 | Exit Sub 372 | End If 373 | 374 | error_code = 0 375 | End If 376 | 377 | '변경된 변수 표시 378 | If Not (visual) Then 379 | If (variable_count > 0) Then 380 | Cells(4 + variable_count, 11).Font.ColorIndex = 3 381 | Worksheets("변수").Cells(4 + variable_count, 3).Value = 1 382 | If (updated_max_var < variable_count) Then '최대 변수 383 | updated_max_var = variable_count 384 | End If 385 | ElseIf (variable_count <= 0) Then 386 | Cells(16 - variable_count, 8).Font.ColorIndex = 3 387 | Worksheets("변수").Cells(5 - variable_count, 7).Value = 1 388 | If (updated_min_var > variable_count) Then '최소 변수 389 | updated_min_var = variable_count 390 | End If 391 | End If 392 | End If 393 | 394 | Case "식" '값 출력 395 | If (Mid(command, 2, 1) = "?") Then '대입 없이 입력만 받을 경우(출력과는 관계 X) 396 | '숫자 계산 397 | Call ErrorCode(252) 398 | number = CalculateNumber(command, 1, Len(command), error_code) 399 | 400 | If (error_code <> 0) Then 401 | Call ErrorCode(error_code) 402 | If (error_code < 0) Then 403 | return_num = -1 404 | Exit Sub 405 | End If 406 | 407 | error_code = 0 408 | End If 409 | 410 | GoTo Continue1 411 | End If 412 | 413 | 414 | Call PrintToConsole(command, error_code) 415 | 416 | If (error_code <> 0) Then 417 | Call ErrorCode(error_code) 418 | If (error_code < 0) Then 419 | return_num = -1 420 | Exit Sub 421 | End If 422 | 423 | error_code = 0 424 | End If 425 | 426 | Case "동" '조건문 427 | If Not (Mid(command, 2, 1) = "탄") Then '"동탄"의 현태가 아님 428 | Call ErrorCode(-106) 'Error 106 429 | return_num = -1 430 | Exit Sub 431 | End If 432 | 433 | For j = 3 To Len(command) 434 | If (Mid(command, j, 1) = "?") Then '"?"를 찾음 435 | dongtan_end_point = j 436 | Exit For 437 | ElseIf (j = Len(command)) Then '"?"를 찾지 못함 438 | Call ErrorCode(-106) 'Error 106 439 | return_num = -1 440 | Exit Sub 441 | End If 442 | Next 443 | 444 | number = CalculateNumber(command, 3, dongtan_end_point - 1, error_code) 445 | If (error_code <> 0) Then 446 | Call ErrorCode(error_code) 447 | If (error_code < 0) Then 448 | return_num = -1 449 | Exit Sub 450 | End If 451 | 452 | error_code = 0 453 | End If 454 | 455 | If (number = 0) Then '조건문이 참이면 456 | command = Mid(command, dongtan_end_point + 1) 457 | GoTo IfCommand 458 | Else '조건문이 거짓이면 459 | GoTo Continue1 460 | End If 461 | 462 | Case "준" 'Goto문 463 | number = CalculateNumber(command, 2, Len(command), error_code) 464 | 465 | If (error_code <> 0) Then 466 | Call ErrorCode(error_code) 467 | If (error_code < 0) Then 468 | return_num = -1 469 | Exit Sub 470 | End If 471 | 472 | error_code = 0 473 | End If 474 | 475 | If (number <= 0) Then '0, 음수번째 줄 476 | Call ErrorCode(-401) 477 | return_num = -1 478 | Exit Sub 479 | ElseIf (number > last_command_row) Then '종료 지점 이후로 이동 불가 480 | Call ErrorCode(-402) 481 | return_num = -1 482 | Exit Sub 483 | ElseIf (number = current_command_row) Then '자기 자신으로 이동 불가 484 | Call ErrorCode(-404) 485 | return_num = -1 486 | Exit Sub 487 | Else 488 | '현재 실행 중인 줄에서 화살표 지우기 489 | If (Cells(current_command_row + 4, 2).Value = "¶" Or Cells(current_command_row + 4, 2).Value = "?") Then 490 | Cells(current_command_row + 4, 2).Value = "?" 491 | Else 492 | Cells(current_command_row + 4, 2).ClearContents 493 | End If 494 | 495 | '이동하는 줄에 중단점이 있을 경우 496 | If (Cells(number + 4, 2).Value = "?" Or Cells(number + 4, 2).Value = "¶") Then 497 | Cells(number + 4, 2).Value = "¶" 498 | blocking = True 499 | End If 500 | 501 | If Not (visual) Then 502 | Cells(number + 4, 4).Select 503 | End If 504 | current_command_row = number 505 | GoTo Continue2 506 | End If 507 | 508 | Case "화" 'return문 509 | If Not (Mid(command, 2, 3) = "이팅!") Then '"화이팅!"의 형태가 아님 510 | Call ErrorCode(-107) 'Error 107 511 | return_num = -1 512 | Exit Sub 513 | End If 514 | 515 | number = CalculateNumber(command, 5, Len(command), error_code) 516 | If (error_code <> 0) Then 517 | Call ErrorCode(error_code) 518 | If (error_code < 0) Then 519 | return_num = -1 520 | Exit Sub 521 | End If 522 | 523 | error_code = 0 524 | End If 525 | 526 | '반환 후 프로그램 종료 527 | If Not (visual) Then 528 | For j = 1 To updated_max_var '양수 변수 지우기 529 | If (Worksheets("변수").Cells(4 + j, 3).Value <> 0) Then 530 | Cells(4 + j, 11).Font.ColorIndex = 1 531 | Worksheets("변수").Cells(4 + j, 3).Value = 0 532 | End If 533 | Next 534 | 535 | For j = 0 To updated_min_var Step -1 '음수 변수 지우기 536 | If (Worksheets("변수").Cells(5 - j, 7).Value <> 0) Then 537 | Cells(16 - j, 8).Font.ColorIndex = 1 538 | Worksheets("변수").Cells(5 - j, 7).Value = 0 539 | End If 540 | Next 541 | End If 542 | 543 | If (Cells(current_command_row + 4, 2).Value = "¶" Or Cells(current_command_row + 4, 2).Value = "?") Then 544 | Cells(current_command_row + 4, 2).Value = "?" 545 | Else 546 | Cells(current_command_row + 4, 2).Value = vbNullString 547 | End If 548 | 549 | return_num = number 550 | Exit Sub 551 | 552 | Case ".", "," '맨 앞에 바로 수식이 나오는 경우 553 | '숫자 계산 554 | Call ErrorCode(252) 555 | number = CalculateNumber(command, 1, Len(command), error_code) 556 | 557 | If (error_code <> 0) Then 558 | Call ErrorCode(error_code) 559 | If (error_code < 0) Then 560 | return_num = -1 561 | Exit Sub 562 | End If 563 | 564 | error_code = 0 565 | End If 566 | 567 | GoTo Continue1 568 | Case "이" '이 사람이름이냐ㅋㅋ 569 | If (Cells(current_command_row + 4, 2).Value = "▲") Then '코드의 끝 부분 570 | return_num = 0 571 | Exit Sub 572 | Else 573 | Call ErrorCode(-103) '잘못된 문자로 시작 574 | return_num = -1 575 | Exit Sub 576 | End If 577 | 578 | Case Else 579 | Call ErrorCode(-103) '잘못된 문자로 시작 580 | return_num = -1 581 | Exit Sub 582 | End Select 583 | 584 | Continue1: 585 | 586 | If (visual And count_for_visual >= 100) Then '시각 모드 해제 시 100회마다 1번씩 화면 업데이트 587 | Application.ScreenUpdating = True 588 | Cells(current_console_row + 4, 6).Select 589 | Application.ScreenUpdating = False 590 | count_for_visual = 0 591 | End If 592 | 593 | If (blocking) Then '비주얼 생략 모드에서 중단점 적용 시 화면 업데이트 594 | Application.ScreenUpdating = True 595 | Cells(current_command_row + 4, 4).Select 596 | End If 597 | Do 598 | 599 | If Not (blocking) Then 600 | If (is_debugging) Then '디버깅 중일 때만 다음 코드 실행 후 중단 적용 601 | blocking = True 602 | End If 603 | 604 | If (Cells(current_command_row + 4, 2).Value = "¶" Or Cells(current_command_row + 4, 2).Value = "?") Then 605 | Cells(current_command_row + 4, 2).Value = "?" 606 | Else 607 | Cells(current_command_row + 4, 2).Value = vbNullString 608 | End If 609 | 610 | Exit Do 611 | End If 612 | 613 | Delay (0.1) 614 | Loop 615 | 616 | If (visual) Then 617 | Application.ScreenUpdating = False 618 | End If 619 | 620 | If Not (visual) Then 621 | For j = 1 To updated_max_var '양수 변수 지우기 622 | If (Worksheets("변수").Cells(4 + j, 3).Value <> 0) Then 623 | Cells(4 + j, 11).Font.ColorIndex = 1 624 | Worksheets("변수").Cells(4 + j, 3).Value = 0 625 | End If 626 | Next 627 | 628 | For j = 0 To updated_min_var Step -1 '음수 변수 지우기 629 | If (Worksheets("변수").Cells(5 - j, 7).Value <> 0) Then 630 | Cells(16 - j, 8).Font.ColorIndex = 1 631 | Worksheets("변수").Cells(5 - j, 7).Value = 0 632 | End If 633 | Next 634 | End If 635 | 636 | 637 | If (Cells(current_command_row + 4, 2).Value = "¶" Or Cells(current_command_row + 4, 2).Value = "?") Then 638 | Cells(current_command_row + 4, 2).Value = "?" 639 | Else 640 | Cells(current_command_row + 4, 2).Value = vbNullString 641 | End If 642 | 643 | If Not (is_running) Then '처리 도중 종료 명령이 들어왔을 때 644 | return_num = -1 645 | Exit Sub 646 | End If 647 | 648 | Loop 649 | End Sub 650 | 651 | Sub Delay(ByVal a As Double) 652 | Dim start 653 | start = Timer 654 | 655 | Do While Timer < start + a 656 | DoEvents 657 | Loop 658 | End Sub 659 | 660 | Sub ErrorCode(ByVal error_code As Integer) 661 | Dim contents 662 | contents = vbNullString 663 | 664 | If (error_code < 0) Then '오류 665 | contents = Application.VLookup(-error_code, Worksheets("오류 코드").Range("C2:D42"), 2, False) 666 | MsgBox current_command_row & "번째 줄에서 오류 발생(" & -error_code & "): " & contents, vbCritical, "오류" 667 | ElseIf (error_code > 0) Then '경고 668 | contents = Application.VLookup(error_code, Worksheets("오류 코드").Range("G2:H42"), 2, False) 669 | MsgBox current_command_row & "번째 줄에서 경고 발생(" & error_code & "): " & contents, vbExclamation, "경고" 670 | Else 671 | MsgBox "프로그래밍 오류(오류 코드 0)" 672 | End If 673 | 674 | Cells(current_command_row + 4, 4).Select 675 | End Sub 676 | 677 | Private Function FindEndPoint() As Long 678 | FindEndPoint = 1 679 | 680 | For i = 0 To 10000 681 | If (Cells(FindEndPoint + 4, 4).Value = "이 사람이름이냐ㅋㅋ" Or Cells(FindEndPoint + 4, 4).Value = "이 사람이름이냐크크") Then 682 | Exit Function 683 | ElseIf (Cells(FindEndPoint + 4, 4).Value = "이 사람이름이냐크ㅋ" Or Cells(FindEndPoint + 4, 4).Value = "이 사람이름이냐ㅋ크") Then 684 | Exit Function 685 | End If 686 | 687 | FindEndPoint = FindEndPoint + 1 688 | Next 689 | 690 | FindEndPoint = -1 691 | End Function 692 | 693 | Function ParseVariable(ByVal Target As Variant, ByVal start_point As Long, ByVal restriction_end_point As Long, ByRef end_point As Long, ByRef is_called As Boolean, ByRef error_code As Integer) As Long 694 | 'MsgBox "target:" & target & "start_point: " & start_point & "restriction_end_point: " & restriction_end_point 695 | Dim n_start_point As Long, tmp_end_point As Long, tmp_number As Long, orig_len_of_target As Long 696 | Dim target_is_modified As Boolean, is_called_for_v3 As Boolean 697 | Dim is_called_for_v3_last_k As Long '"어" 변수 호출 또는 "어...ㅋ"의 변수 호출인지 확인 698 | n_start_point = start_point 699 | tmp_end_point = start_point 700 | tmp_number = 0 701 | target_is_modified = False 702 | orig_len_of_target = restriction_end_point 703 | ParseVariable = 1 704 | is_called = True 705 | 706 | is_called_for_v3 = False 707 | is_called_for_v3_last_k = restriction_end_point 708 | 709 | If (Mid(Target, start_point, 1) = "어") Then '"어" 변수 호출 또는 "어...ㅋ"의 변수 호출인지 확인 710 | For i = restriction_end_point To start_point Step -1 711 | If (Mid(Target, i, 1) = "ㅋ" Or Mid(Target, i, 1) = "크") Then 712 | is_called_for_v3 = True 713 | is_called_for_v3_last_k = i 714 | Exit For 715 | End If 716 | Next 717 | End If 718 | 719 | If (start_point = 1) Then 'ㅋ가 들어 있지만 맨 처음 L-Value 부분인 경우 720 | is_called_for_v3 = False 721 | is_called_for_v3_last_k = restriction_end_point 722 | End If 723 | 724 | If (Not is_called_for_v3 And (Mid(Target, start_point, 1) = "엄" Or Mid(Target, start_point, 2) = "어어" Or Mid(Target, start_point, 2) = "어엄" Or Mid(Target, start_point, 1) = "어")) Then '연음으로 변수 탐색 725 | For i = start_point To restriction_end_point 726 | If (Mid(Target, i, 1) = "엄") Then 727 | is_called = False 728 | ParseVariable = i - start_point + 1 729 | end_point = start_point + ParseVariable - 1 730 | Exit Function 731 | ElseIf (Mid(Target, i, 1) = "어") Then 732 | If (i <> restriction_end_point) And (Mid(Target, i + 1, 1) = "어" Or Mid(Target, i + 1, 1) = "엄") Then '변수 표현이 끝나지 않음 733 | ParseVariable = i - start_point + 1 734 | Else '어 뒤로 변수와 관련 없는 문자가 옴, 또는 탐색 범위가 끝남(=변수 끝 또는 오류) 735 | ParseVariable = i - start_point + 1 736 | end_point = start_point + ParseVariable - 1 737 | Exit Function 738 | End If 739 | Else 740 | Exit For 741 | End If 742 | Next 743 | ElseIf (Mid(Target, start_point, 1) = "엌") Then '값으로 변수 탐색 744 | For i = start_point + 1 To restriction_end_point 'N 값의 시작 부분 직전 찾기 745 | If Not (Mid(Target, i, 1) = "ㅋ" Or Mid(Target, i, 1) = "크") Then 746 | n_start_point = i - 1 747 | Exit For 748 | End If 749 | Next 750 | 751 | For i = n_start_point + 1 To restriction_end_point 'N 값의 끝 부분 찾기 752 | If (Mid(Target, i, 1) = "ㅋ" Or Mid(Target, i, 1) = "크") Then 753 | tmp_end_point = i - 1 754 | Exit For 755 | End If 756 | Next 757 | 758 | 'N 값 계산 759 | tmp_number = CalculateNumber(Target, n_start_point + 1, tmp_end_point, error_code) 760 | If (error_code < 0) Then 761 | ParseVariable = -1 762 | Exit Function 763 | End If 764 | 765 | ParseVariable = tmp_number 766 | is_called = False 767 | 768 | For i = tmp_end_point + 1 To restriction_end_point + 1 '변수 호출의 끝 부분 찾기 769 | If Not (Mid(Target, i, 1) = "ㅋ" Or Mid(Target, i, 1) = "크") Or (i = restriction_end_point + 1) Then 770 | tmp_end_point = i - 1 771 | Exit For 772 | End If 773 | Next 774 | 775 | end_point = tmp_end_point 776 | 777 | Exit Function 778 | 779 | ElseIf (Mid(Target, start_point, 1) = "어") Then '값으로 변수 호출(v3) 또는 대입 없는 변수 호출 780 | tmp_end_point = -1 781 | 782 | n_start_point = start_point + 1 'N 값의 시작 부분 783 | 784 | tmp_end_point = is_called_for_v3_last_k - 1 'N 값의 끝 부분 785 | 786 | 'N 값 계산 787 | tmp_number = CalculateNumber(Target, n_start_point, tmp_end_point, error_code) 788 | If (error_code < 0) Then 789 | ParseVariable = -1 790 | Exit Function 791 | End If 792 | 793 | ParseVariable = tmp_number 794 | is_called = True 795 | 796 | For i = tmp_end_point + 1 To restriction_end_point + 1 '변수 호출의 끝 부분 찾기 797 | If (i = restriction_end_point + 1) Then 798 | tmp_end_point = i - 1 799 | ElseIf Not (Mid(Target, i, 1) = "ㅋ" Or Mid(Target, i, 1) = "크") Then 800 | tmp_end_point = i 801 | Exit For 802 | End If 803 | Next 804 | 805 | end_point = tmp_end_point 806 | Exit Function 807 | 808 | is_called = True 809 | ParseVariable = 1 810 | Exit Function 811 | End If 812 | 813 | error_code = -201 814 | Exit Function 815 | End Function 816 | 817 | Function CalculateNumber(ByVal Target As Variant, ByVal start_point As Long, ByVal end_point As Long, ByRef error_code As Integer) As Long 818 | 'MsgBox "target:" & target & "start_point: " & start_point & "end_point: " & end_point 819 | Dim list_infix(), list_postfix(), stack_translate(), stack_calc() As Variant 820 | Dim prev_char As String 821 | Dim count As Long 822 | 823 | Dim number_of_uk As Integer 824 | number_of_uk = 0 825 | 826 | '첫 글자가 아닌 "엌"을 "어ㅋ"로 변환 827 | For i = start_point To end_point 828 | If (Mid(Target, i, 1) = "엌" And i <> 1) Then 829 | number_of_uk = number_of_uk + 1 830 | Exit For 831 | End If 832 | Next 833 | 834 | If (number_of_uk <> 0) Then 835 | Target = Left(Target, 1) & Replace(Target, "엌", "어ㅋ", 2) 836 | End If 837 | 838 | end_point = end_point + number_of_uk 839 | 840 | If (start_point > 1) Then 841 | prev_char = Mid(Target, start_point - 1, 1) 842 | Else '명령어의 첫 번째 글자부터 파싱됨 843 | prev_char = vbNullString 844 | End If 845 | count = 0 846 | 847 | For i = start_point To end_point 848 | If (Mid(Target, i, 1) <> prev_char) Then 849 | 'prev_char = Mid(target, i, 1) 850 | count = count + 1 851 | End If 852 | Next 853 | 854 | '연산자와 피연산자를 담을 중위 표기 배열 생성 855 | ReDim list_infix(2 * count + 10), list_postfix(2 * count + 10), stack_translate(2 * count + 10), stack_calc(2 * count + 10) 856 | Dim list_infix_pointer As Long, list_postfix_pointer As Long, stack_translate_pointer As Long, stack_calc_pointer As Long 857 | Dim count_for_num As Variant 858 | Dim successive_minus As Long, variable_count As Long 859 | Dim var_end_point As Long 860 | Dim has_v3_var_pos As Long 861 | Dim is_minus As Boolean, is_called As Boolean, has_v3_var As Boolean 862 | 863 | has_v3_var = False 864 | has_v3_var_pos = 0 865 | 866 | If (start_point > 1) Then 867 | prev_char = Mid(Target, start_point - 1, 1) 868 | Else '명령어의 첫 번째 글자부터 파싱됨 869 | prev_char = vbNullString 870 | End If 871 | 872 | list_infix_pointer = -1 873 | list_postfix_pointer = -1 874 | stack_translate_pointer = -1 875 | stack_calc_pointer = -1 876 | 877 | count_for_num = 0 878 | is_minus = False 879 | successive_minus = 1 880 | 881 | variable_count = 0 882 | is_called = True 883 | 884 | var_end_point = 0 885 | 886 | If (start_point > end_point) Then '입력 영역의 길이가 음수일 때 887 | CalculateNumber = 0 888 | Exit Function 889 | End If 890 | 891 | Dim iii 892 | iii = start_point - 1 893 | Do 894 | iii = iii + 1 895 | If (iii > end_point + 1) Then 896 | Exit Do 897 | End If 898 | 899 | If (iii - 1 > 0) Then 900 | prev_char = Mid(Target, iii - 1, 1) 901 | Else '명령어의 첫 번째 글자부터 파싱됨 902 | prev_char = vbNullString 903 | End If 904 | 905 | If (iii = end_point + 1) Then '배열 끝 부분 906 | If (prev_char = "." Or prev_char = ",") Then '앞쪽에 상수가 있는 경우 907 | '앞쪽 수를 배열에 삽입 908 | list_infix_pointer = list_infix_pointer + 1 909 | list_infix(list_infix_pointer) = count_for_num 910 | count_for_num = 0 911 | ElseIf (prev_char = "어" Or prev_char = "?" Or prev_char = "ㅋ" Or prev_char = "크") Then '앞쪽에 변수 또는 입력값이 있는 경우 912 | '앞쪽 수를 배열에 삽입 913 | list_infix_pointer = list_infix_pointer + 1 914 | list_infix(list_infix_pointer) = count_for_num 915 | count_for_num = 0 916 | Else '매열 끝이 숫자가 아님 917 | CalculateNumber = 0 918 | error_code = -303 'Error 303 919 | Exit Function 920 | End If 921 | 922 | Exit Do 923 | End If 924 | 925 | Select Case Mid(Target, iii, 1) 926 | Case "." '증가 기호 927 | If (prev_char = "." Or prev_char = ",") Then '연이은 증가, 감소 후 증가 928 | count_for_num = count_for_num + 1 929 | ElseIf (iii = start_point) Then '맨 앞 증가 기호(주의 : "어(값)ㅋ"을 포함) 930 | count_for_num = 1 931 | ElseIf (prev_char = "어" Or prev_char = "?" Or prev_char = "ㅋ" Or prev_char = "크") Then '변수 + 1(주의: "어(값)ㅋ"와 혼동하면 안됨), 입력값 + 1 932 | '앞쪽 변수와 더하기 기호를 배열에 삽입 후 1부터 시작 933 | list_infix_pointer = list_infix_pointer + 1 934 | list_infix(list_infix_pointer) = count_for_num 935 | 936 | list_infix_pointer = list_infix_pointer + 1 937 | list_infix(list_infix_pointer) = "p" 938 | 939 | count_for_num = 1 940 | ElseIf (prev_char = " ") Then '앞쪽에 곱하기 기호가 있는 경우 941 | '곱하기 기호를 배열에 삽입 942 | list_infix_pointer = list_infix_pointer + 1 943 | list_infix(list_infix_pointer) = "m" 944 | 945 | count_for_num = 1 946 | End If 947 | 948 | Case "," '감소 기호 949 | If (prev_char = "." Or prev_char = ",") Then '연이은 감소, 증가 후 감소 950 | count_for_num = count_for_num - 1 951 | ElseIf (iii = start_point) Then '맨 앞 감소 기호 952 | count_for_num = -1 953 | ElseIf (prev_char = "어" Or prev_char = "?" Or prev_char = "ㅋ" Or prev_char = "크") Then '변수 + (-1), 입력값 + (-1) 954 | '앞쪽 변수와 더하기 기호를 배열에 삽입 후 -1부터 시작 955 | list_infix_pointer = list_infix_pointer + 1 956 | list_infix(list_infix_pointer) = count_for_num 957 | 958 | list_infix_pointer = list_infix_pointer + 1 959 | list_infix(list_infix_pointer) = "p" 960 | 961 | count_for_num = -1 962 | ElseIf (prev_char = " ") Then '앞쪽에 곺하기 기호가 있는 경우 963 | '곱하기 기호를 배열에 삽입 964 | list_infix_pointer = list_infix_pointer + 1 965 | list_infix(list_infix_pointer) = "m" 966 | 967 | count_for_num = -1 968 | End If 969 | 970 | Case " " '곱하기 기호 971 | If (iii = end_point) Then '곱하기 기호 뒤에 아무것도 없는 경우(오류) 972 | CalculateNumber = 0 973 | error_code = -304 'Error 304 974 | Exit Function 975 | ElseIf (prev_char = " ") Then '연이은 곱하기 기호 976 | error_code = 351 'Warn 351 977 | ElseIf (prev_char = "." Or prev_char = ",") Then '상수 뒤 곱하기 기호 978 | '앞쪽 수를 배열에 삽입 979 | list_infix_pointer = list_infix_pointer + 1 980 | list_infix(list_infix_pointer) = count_for_num 981 | count_for_num = 0 982 | ElseIf (prev_char = "어" Or prev_char = "?" Or prev_char = "ㅋ" Or prev_char = "크") Then '변수 또는 입력값 뒤 곱하기 기호 983 | '앞쪽 변수를 배열에 삽입 984 | list_infix_pointer = list_infix_pointer + 1 985 | list_infix(list_infix_pointer) = count_for_num 986 | count_for_num = 0 987 | Else '앞쪽 피연산자 없는 곱하기 기호 988 | CalculateNumber = 0 989 | error_code = -302 'Error 302 990 | Exit Function 991 | End If 992 | 993 | Case "어" '변수 호출(R-Value) 994 | If (prev_char = "." Or prev_char = ",") Then '상수 뒤 변수 995 | '앞쪽 수와 더하기 기호를 배열에 삼입 996 | list_infix_pointer = list_infix_pointer + 1 997 | list_infix(list_infix_pointer) = count_for_num 998 | 999 | list_infix_pointer = list_infix_pointer + 1 1000 | list_infix(list_infix_pointer) = "p" 1001 | 1002 | count_for_num = 0 1003 | ElseIf (prev_char = " ") Then '곱하기 기호 뒤 변수 1004 | '곱하기 기호를 배열에 삽입 1005 | list_infix_pointer = list_infix_pointer + 1 1006 | list_infix(list_infix_pointer) = "m" 1007 | ElseIf (prev_char = "어" Or prev_char = "?" Or prev_char = "ㅋ" Or prev_char = "크") Then '입력값 및 변수("어...ㅋ") 뒤 변수 1008 | '입력값과 더하기 기호를 배열에 삽입 1009 | list_infix_pointer = list_infix_pointer + 1 1010 | list_infix(list_infix_pointer) = count_for_num 1011 | 1012 | list_infix_pointer = list_infix_pointer + 1 1013 | list_infix(list_infix_pointer) = "p" 1014 | 1015 | count_for_num = 0 1016 | ElseIf (iii = start_point) Then '첫 부분 1017 | count_for_num = 0 1018 | Else 1019 | End If 1020 | 1021 | has_v3_var = False 1022 | has_v3_var_pos = 0 1023 | 1024 | 'v3 형태의 변수가 맨 앞에 있는지 확인 1025 | For k = iii + 1 To end_point 1026 | If (Mid(Target, k, 1) = "어") Then 1027 | 'v3 형태의 변수가 맨 앞에 있음(맨 뒤의 ㅋ을 탐색) 1028 | For k2 = end_point To k + 1 Step -1 1029 | If (Mid(Target, k2, 1) = "ㅋ" Or Mid(Target, k2, 1) = "크") Then 1030 | has_v3_var = True 1031 | has_v3_var_pos = k2 1032 | Exit For 1033 | End If 1034 | Next 1035 | 1036 | Exit For 1037 | ElseIf (k = end_point) Then 1038 | 'v3 형태의 변수가 맨 앞에 있음(맨 앞의 ㅋ을 탐색) 1039 | For k3 = iii + 1 To end_point 1040 | If (Mid(Target, k3, 1) = "ㅋ" Or Mid(Target, k3, 1) = "크") Then 1041 | has_v3_var = True 1042 | has_v3_var_pos = k3 1043 | Exit For 1044 | End If 1045 | Next 1046 | 1047 | Exit For 1048 | End If 1049 | Next 1050 | 1051 | Dim result As Long 1052 | result = 0 1053 | 1054 | If (has_v3_var) Then 'v3 형태의 변수가 맨 앞에 있으면 1055 | Call RunCalculateNumber(Target, iii + 1, has_v3_var_pos - 1, error_code, result) '어~(맨 뒤의 ㅋ, 단, 마지막으로 나타나는 "어"면 첫 번째의 ㅋ) 사이에 있는 값 계산 1056 | variable_count = result 1057 | var_end_point = has_v3_var_pos 1058 | Else '연음 형태의 변수가 맨 앞에 있으면 1059 | variable_count = ParseVariable(Target, iii, end_point, var_end_point, is_called, error_code) 1060 | End If 1061 | 1062 | If Not (is_called) Then 1063 | CalculateNumber = 0 1064 | error_code = -202 'Error 202 1065 | Exit Function 1066 | End If 1067 | 1068 | If Not (visual) Then '호출한 변수를 표시 1069 | If (variable_count > 0) Then 1070 | Cells(4 + variable_count, 11).Font.ColorIndex = 33 1071 | Worksheets("변수").Cells(4 + variable_count, 3).Value = 1 1072 | If (updated_max_var < variable_count) Then '최대 변수 1073 | updated_max_var = variable_count 1074 | End If 1075 | ElseIf (variable_count <= 0) Then 1076 | Cells(16 - variable_count, 8).Font.ColorIndex = 33 1077 | Worksheets("변수").Cells(5 - variable_count, 7).Value = 1 1078 | If (updated_min_var > variable_count) Then '최소 변수 1079 | updated_min_var = variable_count 1080 | End If 1081 | End If 1082 | End If 1083 | 1084 | count_for_num = count_for_num + FindVarPos(variable_count, error_code) 1085 | iii = var_end_point '변수 부분 이후로 점프 1086 | 1087 | Case "식" '입력값 1088 | If (prev_char = "." Or prev_char = ",") Then '상수 뒤 입력값 1089 | '앞쪽 수와 더하기 기호를 배열에 삼입 1090 | list_infix_pointer = list_infix_pointer + 1 1091 | list_infix(list_infix_pointer) = count_for_num 1092 | 1093 | list_infix_pointer = list_infix_pointer + 1 1094 | list_infix(list_infix_pointer) = "p" 1095 | 1096 | count_for_num = 0 1097 | ElseIf (prev_char = " ") Then '곱하기 기호 뒤 입력값 1098 | '곱하기 기호를 배열에 삽입 1099 | list_infix_pointer = list_infix_pointer + 1 1100 | list_infix(list_infix_pointer) = "m" 1101 | ElseIf (prev_char = "어" Or prev_char = "?") Then '변수 뒤 입력값, 입력값 뒤 입력값 1102 | '앞 값과 더하기 기호를 배열에 삽입 1103 | list_infix_pointer = list_infix_pointer + 1 1104 | list_infix(list_infix_pointer) = count_for_num 1105 | 1106 | list_infix_pointer = list_infix_pointer + 1 1107 | list_infix(list_infix_pointer) = "p" 1108 | 1109 | count_for_num = 0 1110 | ElseIf (iii = start_point) Then '첫 부분 1111 | count_for_num = 0 1112 | Else 1113 | End If 1114 | 1115 | 1116 | '입력을 받는 형태인지 확인 후 맞으면 입력을 받음 1117 | If Not (Mid(Target, iii + 1, 1) = "?") Then '식?의 형태가 아닐 경우 1118 | CalculateNumber = 0 1119 | error_code = -104 'Error 104 1120 | Exit Function 1121 | End If 1122 | 1123 | '입력받은 값 가져오기 1124 | count_for_num = InputNum() 1125 | iii = iii + 1 1126 | 1127 | If Not (is_running) Then '입력 도중 종료 명령이 들어왔을 때 1128 | CalculateNumber = 0 1129 | Exit Function 1130 | End If 1131 | 1132 | Case "ㅋ", "크" '잉여 ㅋ 1133 | 1134 | 1135 | Case Else '허용되지 않은 문자 1136 | CalculateNumber = 0 1137 | error_code = -305 'Error 305 1138 | Exit Function 1139 | End Select 1140 | Loop 1141 | 1142 | Dim item As Variant 1143 | 1144 | '중위 표기를 후위 표기로 변경 1145 | For i = 0 To list_infix_pointer 1146 | item = list_infix(i) 1147 | 1148 | If (item = "p" Or item = "s") Then '더하기 또는 빼기 1149 | If (stack_translate_pointer = -1) Then '스택이 비었을 때 1150 | stack_translate_pointer = stack_translate_pointer + 1 1151 | stack_translate(stack_translate_pointer) = item 1152 | Else '곱하기 기호가 들어 있을 때 1153 | list_postfix_pointer = list_postfix_pointer + 1 1154 | list_postfix(list_postfix_pointer) = stack_translate(stack_translate_pointer) 1155 | stack_translate(stack_translate_pointer) = item 1156 | End If 1157 | ElseIf (item = "m") Then '곱하기 1158 | '스택이 비었을 때 and (더하기 or 빼기 기호가 들어 있을 때) 1159 | stack_translate_pointer = stack_translate_pointer + 1 1160 | stack_translate(stack_translate_pointer) = item 1161 | Else '숫자 1162 | list_postfix_pointer = list_postfix_pointer + 1 1163 | list_postfix(list_postfix_pointer) = item 1164 | End If 1165 | Next 1166 | 1167 | '스택 비우기 1168 | For i = stack_translate_pointer To 0 Step -1 1169 | list_postfix_pointer = list_postfix_pointer + 1 1170 | list_postfix(list_postfix_pointer) = stack_translate(i) 1171 | Next 1172 | 1173 | '연산 1174 | For i = 0 To list_postfix_pointer 1175 | Dim temp_calc As Variant 1176 | temp_calc = 0 1177 | item = list_postfix(i) 1178 | 1179 | If (item = "p") Then '더하기 연산 1180 | temp_calc = stack_calc(stack_calc_pointer - 1) + stack_calc(stack_calc_pointer) 1181 | stack_calc(stack_calc_pointer - 1) = temp_calc 1182 | stack_calc_pointer = stack_calc_pointer - 1 1183 | ElseIf (item = "s") Then '빼기 연산 1184 | temp_calc = stack_calc(stack_calc_pointer - 1) - stack_calc(stack_calc_pointer) 1185 | stack_calc(stack_calc_pointer - 1) = temp_calc 1186 | stack_calc_pointer = stack_calc_pointer - 1 1187 | ElseIf (item = "m") Then '곱하기 연산 1188 | temp_calc = stack_calc(stack_calc_pointer - 1) * stack_calc(stack_calc_pointer) 1189 | stack_calc(stack_calc_pointer - 1) = temp_calc 1190 | stack_calc_pointer = stack_calc_pointer - 1 1191 | Else '숫자 1192 | item = OverFlow(item) '오버플로 처리 1193 | 1194 | stack_calc_pointer = stack_calc_pointer + 1 1195 | stack_calc(stack_calc_pointer) = item 1196 | End If 1197 | Next 1198 | 1199 | CalculateNumber = OverFlow(stack_calc(0)) '오버플로 처리 1200 | End Function 1201 | 1202 | Function OverFlow(ByVal number As Variant) As Long '32비트 정수형 기준으로 처리 1203 | Dim power31 As Variant 1204 | power31 = 2 ^ 31 1205 | 1206 | Do 1207 | For i = 62 To 32 Step -1 1208 | If (number > (2 ^ i)) Then '양수 오버플로 1209 | number = number - (2 ^ i) 1210 | ElseIf (number < -(2 ^ i)) Then '음수 오버플로 1211 | number = number + (2 ^ i) 1212 | End If 1213 | Next 1214 | 1215 | If (number > power31 - 1) Then '양수 오버플로 1216 | number = number - power31 * 2 '2^32 1217 | ElseIf (number < -1 * power31) Then '음수 오버플로 1218 | number = number + power31 * 2 '2^32 1219 | Else 1220 | Exit Do 1221 | End If 1222 | Loop 1223 | 1224 | OverFlow = number 1225 | End Function 1226 | 1227 | Function InputNum() As Long 1228 | If (has_input_list) Then 1229 | If Not IsEmpty(Worksheets("변수").Cells(4 + input_to_use, 10)) Then 1230 | InputNum = Worksheets("변수").Cells(4 + input_to_use, 10).Value 1231 | input_to_use = input_to_use + 1 1232 | Exit Function 1233 | Else '입력값이 다 떨어졌으면 새로 받기 1234 | End If 1235 | End If 1236 | 1237 | Application.ScreenUpdating = True 1238 | Application.EnableEvents = True 1239 | 1240 | '입력 받기 1241 | Dim input_num 1242 | input_num = 0 1243 | 1244 | If Not (IsEmpty(Cells(current_console_row + 4, 6))) Then '현재 칸에 이미 출력이 있을 때 1245 | current_console_row = current_console_row + 1 1246 | End If 1247 | Cells(current_console_row + 4, 6).NumberFormatLocal = "0" '셀 서식 변경 1248 | 1249 | is_on_console = True 1250 | Cells(current_console_row + 4, 5).Value = ">" 1251 | Cells(current_console_row + 4, 6).Select 1252 | prev_cell_row = current_console_row + 4 1253 | prev_cell_col = 6 1254 | 1255 | Do 1256 | If Not (is_running) Then '입력 도중 종료 명령이 들어왔을 때 1257 | InputNum = 0 1258 | Exit Function 1259 | End If 1260 | 1261 | If Not (Selection.Row = current_console_row + 4 And Selection.Column = 6) Then '셀 변경 1262 | If Not (is_running) Then '입력 도중 종료 명령이 들어왔을 때 1263 | InputNum = 0 1264 | Exit Function 1265 | End If 1266 | 1267 | If Not (IsEmpty(Cells(current_console_row + 4, 6))) Then '입력 O 1268 | If Not (WorksheetFunction.IsNumber(Cells(current_console_row + 4, 6))) Then '입력받은 값이 숫자가 아님 1269 | Cells(current_console_row + 4, 6).Value = "(숫자가 아닌 값)" 1270 | is_on_console = True 1271 | ElseIf (Int(Cells(current_console_row + 4, 6)) - Cells(current_console_row + 4, 6).Value <> 0) Then '입력받은 값이 정수가 아님 1272 | Cells(current_console_row + 4, 6).Value = "(정수가 아닌 값)" 1273 | is_on_console = True 1274 | Else 1275 | current_console_row = current_console_row + 1 1276 | is_on_console = False 1277 | Exit Do 1278 | End If 1279 | 1280 | current_console_row = current_console_row + 1 1281 | Cells(current_console_row + 4, 5).Value = ">" 1282 | Cells(current_console_row + 4, 6).NumberFormatLocal = "0" '셀 서식 변경 1283 | Cells(current_console_row + 4, 6).Select 1284 | Else '입력 X 1285 | If Not (is_running) Then '입력 도중 종료 명령이 들어왔을 때 1286 | InputNum = 0 1287 | Exit Function 1288 | End If 1289 | 1290 | Cells(current_console_row + 4, 6).Select 1291 | End If 1292 | End If 1293 | 1294 | Call Delay(0.01) 1295 | Loop 1296 | 1297 | InputNum = Cells(current_console_row - 1 + 4, 6).Value 1298 | 1299 | If (visual) Then 1300 | Application.ScreenUpdating = False 1301 | Application.EnableEvents = False 1302 | End If 1303 | 1304 | End Function 1305 | 1306 | Sub PrintToConsole(ByVal Target As Variant, ByRef error_code As Integer) 1307 | Dim is_numeral As Boolean 1308 | Dim character As String 1309 | Dim output_num As Long, max_code As Long 1310 | is_numeral = True 1311 | character = vbNullString 1312 | output_num = 0 1313 | max_code = Worksheets("유니코드").Cells(1, 1).Value 'DB의 끝 부분 1314 | 1315 | output_num = ParseOutput(Target, is_numeral, error_code) 1316 | 1317 | If (error_code <> 0 Or Not is_running) Then '입력 중 중단 명령이 들어왔을 때 1318 | Exit Sub 1319 | End If 1320 | 1321 | If (current_console_row = 1) Then '첫 출력 1322 | current_console_row = current_console_row + 1 1323 | Cells(current_console_row + 4, 6).NumberFormatLocal = "0" '셀 서식 변경 1324 | End If 1325 | 1326 | If (is_numeral) Then '정수 1327 | If (IsEmpty(Cells(current_console_row + 4, 6))) Then '빈 줄에 숫자 입력 1328 | Cells(current_console_row + 4, 6).NumberFormatLocal = "0" '셀 서식 변경 1329 | End If 1330 | 1331 | Cells(current_console_row + 4, 6).Value = Cells(current_console_row + 4, 6).Value & output_num 1332 | Else '문자일 경우 1333 | If (output_num < 0) Then '음수 코드 1334 | error_code = -403 1335 | Exit Sub 1336 | End If 1337 | 1338 | If (Len(Target) = 2) Then '"식ㅋ" = 개행 1339 | current_console_row = current_console_row + 1 1340 | ElseIf (output_num = 0) Then '코드 0 1341 | current_console_row = current_console_row + 1 1342 | 1343 | error_code = 151 'Warn 151 1344 | Exit Sub 1345 | Else 1346 | If (output_num <= max_code) Then '범위 이하의 경우 1347 | character = Worksheets("유니코드").Cells(output_num Mod 1000, (output_num \ 1000) * 3 + 3).Value '한셀 호환 1348 | Else 1349 | character = WorksheetFunction.Unichar(output_num) 'MS Office Excel, LibreOffice Calc 전용 1350 | End If 1351 | 1352 | Cells(current_console_row + 4, 6).NumberFormatLocal = "@" '셀 서식 변경 1353 | 1354 | Cells(current_console_row + 4, 6).Value = Cells(current_console_row + 4, 6).Value & character 1355 | End If 1356 | End If 1357 | 1358 | If (visual) Then 1359 | Cells(current_console_row + 4, 6).Select 1360 | End If 1361 | End Sub 1362 | 1363 | Function ParseOutput(ByVal Target As Variant, ByRef is_numeral As Boolean, ByRef error_code As Integer) As Long 1364 | Dim print_end_point As Long 1365 | is_numeral = True '정수 혹은 문자 1366 | print_end_point = 1 1367 | 1368 | If (Right(Target, 1) = "!") Then '정수 1369 | print_end_point = i 1370 | ElseIf (Right(Target, 1) = "ㅋ" Or Right(Target, 1) = "크") Then '문자 1371 | is_numeral = False 1372 | print_end_point = i 1373 | Else '명령어 끝 부분에 "!", "ㅋ", "크"가 없음 1374 | ParseOutput = -1 1375 | error_code = -105 'Error 105 1376 | Exit Function 1377 | End If 1378 | 1379 | Dim output_num As Long 1380 | output_num = 0 1381 | output_num = CalculateNumber(Target, 2, Len(Target) - 1, error_code) 1382 | 1383 | ParseOutput = output_num 1384 | End Function 1385 | 1386 | Sub RunCalculateNumber(ByVal Target As Variant, ByVal start_point As Long, ByVal end_point As Long, ByRef error_code As Integer, ByRef result As Long) 1387 | result = CalculateNumber(Target, start_point, end_point, error_code) 1388 | End Sub 1389 | 1390 | Function FindVarPos(ByVal index As Long, ByRef error_code As Integer) As Variant 1391 | If (index > 0) Then 1392 | FindVarPos = Cells(4 + index, 11).Value 1393 | ElseIf (index <= 0) Then 1394 | FindVarPos = Cells(16 - index, 8).Value 1395 | End If 1396 | End Function 1397 | 1398 | Sub MapVar(ByVal index As Long, ByVal num As Long, ByRef error_code As Integer) 1399 | If (index > 0) Then 1400 | If (index > 1048572) Then 1401 | error_code = -204 1402 | Exit Sub 1403 | End If 1404 | 1405 | Cells(4 + index, 11).Value = num 1406 | ElseIf (index <= 0) Then 1407 | If (index < -1048560) Then 1408 | error_code = -204 1409 | Exit Sub 1410 | End If 1411 | 1412 | Cells(16 - index, 8).Value = num 1413 | End If 1414 | End Sub 1415 | 1416 | Sub Enable_visual() 1417 | visual = False 1418 | End Sub 1419 | 1420 | Sub Disable_visual() 1421 | visual = True 1422 | End Sub 1423 | -------------------------------------------------------------------------------- /umjunsik-lang-vba/README.md: -------------------------------------------------------------------------------- 1 | # 엄랭 VBA 구현체 2 | * VBA: Visual Basic for Applacation 3 | 4 | ## 테스트한 환경 5 | ※ VBA가 지원된다면 이 외의 환경에서도 작동할 수**도** 있습니다. 6 | 7 | * Windows 10 + MS Office Excel(365, v2201): 한 셀에 들어가는 문자열의 최대 길이가 [32,767자](https://support.microsoft.com/ko-kr/office/excel-%ec%82%ac%ec%96%91-%eb%b0%8f-%ec%a0%9c%ed%95%9c-1672b34d-7043-467e-8e27-269d656771c3?ui=ko-kr&rs=ko-kr&ad=kr#ID0EBABAAA=%EC%B5%9C%EC%8B%A0_%EB%B2%84%EC%A0%84)여서 99병의 맥주 예시는 작동되지 않습니다. 8 | * Windows 10 및 Ubuntu 20.04 + LibreOffice Calc(7.3.0.3): 한 셀에 들어가는 문자열의 최대 길이가 [2^31자](https://wiki.documentfoundation.org/Faq/Calc/0220)여서 99병의 맥주 예시도 잘 돌아갑니다. 9 | * Windows 10 + 한컴오피스 한셀(2018): 단 기본적으로 `식(값)ㅋ`에서 32≤(값)≤127일 때만 작동하게 설정되어 있으며, 이 범위를 늘리려면 `유니코드` 시트에 문자를 추가로 집어넣어야 합니다.
※ 실제로 2^16개의 문자를 전부 집어넣으면 파일의 용량이 24 MB까지 늘어납니다. 10 | 11 | ## 업데이트 내역 12 | | 버전 | 날짜 | 내역 | 지원 버전 | 13 | |------|------|------|------| 14 | | v1.2 | 2022-03-12 | 1. 속도 최적화 | 엄랭v2
~~엄랭v3~~(초안) | 15 | | v1.1 | 2022-02-26 | 1. 원라인(one-line) 코드 해석 기능 추가
2. LibreOffice에서 체크박스가 작동하지 않는 문제 해결 | 엄랭v2
~~엄랭v3~~(초안) | 16 | | v1.0 | 2022-02-18 | 1. 최초 출시 | 엄랭v2
~~엄랭v3~~(초안) | 17 | -------------------------------------------------------------------------------- /umjunsik-lang-vba/Sheet1.vb: -------------------------------------------------------------------------------- 1 | Private Sub Worksheet_Change(ByVal Target As Range) '콘솔에 값을 입력하고 선택 셀을 바꿨올 때 2 | If (is_running) Then 3 | If (is_on_console) Then 4 | If (Target = Cells(current_console_row + 4, 6)) Then 5 | prev_cell_row = prev_cell_row + 1 6 | Cells(prev_cell_row, prev_cell_col).Select 7 | is_on_console = False '입력 모드에서 빠져나음 8 | End If 9 | Else 10 | End If 11 | End If 12 | End Sub 13 | 14 | Private Sub Worksheet_SelectionChange(ByVal Target As Range) 15 | If (is_running) Then 16 | Cells(prev_cell_row, prev_cell_col).Select 17 | End If 18 | End Sub 19 | 20 | -------------------------------------------------------------------------------- /umjunsik-lang-vba/ThisWorkbook.vb: -------------------------------------------------------------------------------- 1 | Private Sub Workbook_Open() 2 | is_debugging = False 3 | visual = False 4 | End Sub -------------------------------------------------------------------------------- /umjunsik-lang-vba/interpreter.xlsm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rycont/umjunsik-lang/e973f9d22b9803ee86b53d8e60f1b65ab08c7547/umjunsik-lang-vba/interpreter.xlsm -------------------------------------------------------------------------------- /umjunsik-lang-web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 웹-엄 11 | 12 | 13 |
14 |

15 | 웹-엄: 자바스크립트로 만들어진 웹용 엄랭 처리기 16 |

17 |

18 | 이 처리기는 자바스크립트로 된 아희 처리기를 본따 만들었습니다.
19 | DOM의 특성상 출력이 느려 다른 처리기 보다 느릴 수 있습니다. 속도를 원하신다면 다른 처리기를 찾아보는건 어떠신가요? 20 |

21 | 22 | 23 | 24 | 25 | 41 | 45 | 46 | 47 |
26 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 | 37 |
38 | 39 | 40 |
42 | 43 | 44 |
48 |
49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /umjunsik-lang-web/src/main.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --spacing: 0.2rem; 3 | } 4 | 5 | td { 6 | border: 0; 7 | } 8 | 9 | .container { 10 | padding: 30px 0; 11 | } -------------------------------------------------------------------------------- /umjunsik-lang-web/src/main.js: -------------------------------------------------------------------------------- 1 | let STOP = false; 2 | 3 | const codeElem = document.getElementsByName('code')[0]; 4 | const inputElem = document.getElementsByName('input')[0]; 5 | const outputElem = document.getElementsByName('output')[0]; 6 | const dumpsElem = document.getElementsByName('dumps')[0]; 7 | 8 | const runElem = document.getElementsByName('run')[0]; 9 | const stopElem = document.getElementsByName('stop')[0]; 10 | // const stepElem = document.getElementsByName('step')[0]; 11 | const clearElem = document.getElementsByName('clear')[0]; 12 | const resetElem = document.getElementsByName('reset')[0]; 13 | 14 | const speedElem = document.getElementsByName('speed')[0]; 15 | const splabelElem = document.getElementsByName('splabel')[0]; 16 | 17 | splabelElem.innerText = '실행 속도: ' + speedElem.value + 'ms당 1스텝'; 18 | 19 | 20 | runElem.onclick = () => run(codeElem.value, inputElem.value); 21 | stopElem.onclick = () => STOP = true; 22 | clearElem.onclick = () => { 23 | dumpsElem.value = ''; 24 | outputElem.value = ''; 25 | outputElem.style.borderColor = ''; 26 | }; 27 | resetElem.onclick = () => { 28 | codeElem.value = ''; 29 | dumpsElem.value = ''; 30 | inputElem.value = ''; 31 | outputElem.value = ''; 32 | outputElem.style.borderColor = ''; 33 | }; 34 | speedElem.oninput = () => splabelElem.innerText = '실행 속도: ' + speedElem.value + 'ms당 1스텝'; 35 | 36 | function run(code, input) { 37 | STOP = false; 38 | outputElem.value = ''; 39 | runElem.disabled = true; 40 | speedElem.disabled = true; 41 | outputElem.style.borderColor = ''; 42 | 43 | const statements = code.trim().split(code.includes('~') ? '~' : '\n').map(line => line.trim()); 44 | const inputs = input.replace(/\n{1,}/g, ' ').replace(/\s{2,}/g, ' ').trim().split(' ').map(n => Number(n)); 45 | if (statements[0] !== '어떻게' || !statements.slice(-1)[0].startsWith('이 사람이름이냐')) { 46 | runElem.disabled = false; 47 | speedElem.disabled = false; 48 | outputElem.style.borderColor = 'red'; 49 | return outputElem.value = '어떻게 이 코드가 엄랭이냐ㅋㅋ'; 50 | } 51 | 52 | const variables = []; 53 | let pointer = 0; 54 | let inputpointer = 0; 55 | 56 | function execute(statement) { 57 | if (statement.includes('동탄') && statement.includes('?')) { // IF GOTO 58 | const condition = evaluate(statement.substring(2, statement.lastIndexOf('?'))); 59 | if (condition === 0) return execute(statement.substr(statement.lastIndexOf('?') + 1)); 60 | return; 61 | } 62 | 63 | if (statement.includes('엄')) { 64 | const variablePointer = statement.split('엄')[0].split('어').length; 65 | const setteeValue = evaluate(statement.split('엄')[1]); 66 | variables[variablePointer] = setteeValue; 67 | } 68 | 69 | if (statement.includes('식') && statement[statement.length - 1] === '!') { 70 | printOut(String(evaluate(statement.slice(1, -1)))); 71 | } 72 | 73 | if (statement.includes('식') && statement[statement.length - 1] === 'ㅋ') { 74 | if (statement === '식ㅋ') printOut('\n'); 75 | printOut(stringify(evaluate(statement.slice(1, -1)))); 76 | } 77 | 78 | if (statement.includes('준')) { 79 | pointer = evaluate(statement.split('준')[1]) - 1; 80 | } 81 | 82 | if (statement.indexOf('화이팅!') === 0) { 83 | return evaluate(statement.split('화이팅!')[1]); 84 | } 85 | } 86 | 87 | function parse() { 88 | if (statements[pointer].startsWith('이 사람이름이냐')) stop(); 89 | if (STOP) { 90 | STOP = false; 91 | stop(); 92 | } 93 | 94 | const statement = statements[pointer++]; 95 | const evaluated = execute(statement); 96 | dumpsElem.value = 97 | 'Variables:\n' + variables.reduce((prev, curr, i) => prev + (i + '. ' + curr) + '\n', '') + 98 | '\n\nStatement: (' + pointer + '/' + statements.length + ')\n' + (statements[pointer] || '') + 99 | (typeof evaluated !== 'undefined' ? '\n\nReturned: ' + evaluated : ''); 100 | if (typeof evaluated !== 'undefined') stop(); 101 | } 102 | 103 | const interval = setInterval(parse, speedElem.value); 104 | 105 | // --- utilities 106 | 107 | function printOut(str) { 108 | outputElem.value += str; 109 | outputElem.scrollTo(0, 9999); 110 | } 111 | 112 | function stop() { 113 | runElem.disabled = false; 114 | speedElem.disabled = false; 115 | clearInterval(interval); 116 | } 117 | 118 | function evaluate(x) { 119 | let n = 0; 120 | if (x.includes(' ')) return x.split(' ').map(evaluate).reduce((a, b) => Math.imul(a, b)); 121 | while (x.includes('식?')) { 122 | const answer = inputs[inputpointer++]; 123 | x = x.replace('식?', ''); 124 | n += answer; 125 | } 126 | if (x.includes('어')) n += variables[x.split('어').length - 1] | 0; 127 | if (x.includes('.')) n += x.split('.').length - 1; 128 | if (x.includes(',')) n -= x.split(',').length - 1; 129 | return (n + 2158221066240) % 4294967296 - 2147483648; 130 | } 131 | } 132 | 133 | function stringify(unicode) { 134 | const char = String.fromCharCode(unicode); 135 | return char.match(/[\x00-\x1F]/) ? '' : char; 136 | } 137 | --------------------------------------------------------------------------------