├── LICENSE ├── README.md ├── docs └── optimizate.txt ├── feature.md ├── feature └── variable.md ├── src ├── compile │ ├── codegen.cc │ ├── gen.cc │ ├── gen.h │ ├── scope.h │ ├── target.cc │ └── target.h ├── core │ ├── ast.cc │ ├── ast.h │ ├── builtin.cc │ ├── builtin.h │ ├── error.cc │ ├── error.h │ ├── splitfix.h │ ├── type.cc │ └── type.h ├── def.cc ├── global.h ├── parse │ ├── analysis.cc │ ├── analysis.h │ ├── build.cc │ ├── build.h │ ├── element.cc │ ├── element.h │ ├── envir.cc │ ├── envir.h │ ├── filter.cc │ ├── filter.h │ ├── service.cc │ ├── service.h │ ├── stack.cc │ ├── stack.h │ ├── tokenizer.cc │ └── tokenizer.h ├── sys │ ├── debug.cc │ └── debug.h └── util │ ├── argv.cc │ ├── argv.h │ ├── fs.h │ ├── path.cc │ ├── path.h │ └── str.h ├── test ├── def.bat ├── index.def └── script │ ├── class │ ├── common.def │ ├── copy.def │ ├── reference.def │ └── structure.def │ ├── controlflow │ ├── if.def │ ├── scope.def │ └── while.def │ ├── datastruct │ ├── common.def │ ├── inclass.def │ ├── infun.def │ ├── struct.def │ └── tuple.def │ ├── function │ ├── common.def │ ├── lambda.def │ ├── nested.def │ ├── recurse.def │ └── template.def │ ├── macro │ ├── common.def │ ├── std.def │ ├── stdtest.def │ └── uvn.def │ ├── stl │ ├── tpltype.def │ ├── vector1.def │ └── vector2.def │ ├── type.def │ └── variable.def └── www ├── about.php ├── css ├── about.css ├── document.css ├── donate.css ├── download.css ├── global.css ├── index.css └── manual.css ├── document └── index.php ├── donate └── index.php ├── download └── index.php ├── favicon.ico ├── footer.php ├── header.php ├── img ├── 2wm │ ├── donate1.png │ ├── donate2.png │ ├── qqq1.png │ ├── qqq2.png │ ├── weibo.png │ └── zhihu.png ├── forkme.png ├── logo.png └── logo_small.png ├── index.php ├── js └── jquery.min.js └── manual └── index.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 杨捷 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. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Def 2 | === 3 | 4 | ### 可扩展的编程语言 5 | 6 | ![Def Logo](http://www.deflang.org/img/logo_small.png) 7 | 8 | ### 简介 9 | 10 | Def 致力于提供: 11 | 12 | 1. 类、泛型等不损失效率的抽象 13 | 2. 重载、宏等可扩展的元编程 14 | 3. 符号绑定等自定义语法 15 | 4. 缩减代码长度提升编码和编译效率 16 | 17 | 通过编译强类型、完全类型推导、函数模板、嵌套函数、函数重载、类模板、扩展宏、模式匹配、 lambda表达式、闭包、操作符绑定等等一系列特征完成 Def 的目标:**将 C++ 的高效抽象和 Lisp 的元编程融为一体**。 18 | 19 | ### 链接 20 | 21 | [官网](http://deflang.org/)  [教程](http://deflang.org/manual/)  [文档](http://deflang.org/document/)  [关于](http://deflang.org/about.php) 22 | 23 | ### 代码示例 24 | 25 | ```INI 26 | ;; 自定义类型 27 | type Point ( 28 | Int x 29 | Int y 30 | ) 31 | ;; 定义变量并初始化 32 | var p1 Point 1 2 ; 类型初始化语法与函数调用相同 33 | var p2 Point 3 4 34 | ;; 重载 add 函数 35 | fun add(Point a Point b)( 36 | ret Point ; 缩进和换行不是必须,仅为了排版美观 37 | add 38 | elmget a x ; elmget 表示类成员访问 39 | elmget b x 40 | add 41 | elmget a y 42 | elmget b y 43 | ) 44 | ;; 重载函数调用 45 | add p1 p2 46 | 47 | ;; 添加操作符绑定 48 | let ( a + b ) ( add a b ) 49 | let ( a := b ) ( var a b ) 50 | let ( a.b ) ( elmget a b ) 51 | ;; 自定义类型 52 | type Point ( 53 | Int x 54 | Int y 55 | ) 56 | ;; 定义变量并初始化 57 | p1 := Point 1 2 ; 类型初始化语法与函数调用相同 58 | p2 := Point 3 4 59 | ;; 重载 add 函数,利用函数模板 60 | tpf add(a b)( ; tpf 定义函数模板 61 | Point (a.x)+(a.y) (b.x)+(b.y) 62 | ) 63 | ;; 重载的模板函数调用 64 | p1 + p2 65 | 66 | ;; Def 多返回值函数 67 | fun getTuple()( 68 | ret tuple ( ; 返回元组类型 69 | 10 70 | 9.9 71 | 'a' 72 | ) 73 | ) 74 | ;; 得到元组并使用 75 | var tp getTuple ; 是的,函数调用不需要括号 76 | var num elmget tp 0 ; num = tp[0] 77 | 78 | ;; 定义元组拆包宏 79 | let upk(names val)( ; upk 为 unpack 的缩写 80 | mcrfor(names)( var _v elmget val _i ) 81 | ; mcrfor 表示宏参数循环 _v 为值 _i 为循环索引 82 | ) 83 | 84 | ;; 使用拆包宏 85 | upk(a b c) tp 86 | ``` 87 | 88 | ### 许可 89 | 90 | MIT 91 | -------------------------------------------------------------------------------- /docs/optimizate.txt: -------------------------------------------------------------------------------- 1 | 2 | ## 等待优化列表 3 | 4 | 1. 类型包含初始化折叠(省去子类型内存分配) 5 | 6 | 2. 函数返回结构值时分配栈空间和拷贝(在调用出分配内存并传入指针供数据载入) 7 | 8 | 3. 变量赋值及内层函数捕获变量时,必须传递内存地址,当检测到未赋值只有读取时,直接使用寄存器而不分配内存 9 | 10 | -------------------------------------------------------------------------------- /feature.md: -------------------------------------------------------------------------------- 1 | Def 语言设计原则 2 | === 3 | 4 | 1. 面向底层和系统,编译为机器码 5 | 2. 零成本抽象(不使用的特性不支付成本)最小化运行时 6 | 3. 强类型,内存安全(生命周期)多线程安全,错误处理安全 7 | 4. 面向"类型"编程,函数类型和类类型都是一等公民 8 | 5. 全面的类型推导,现代范型系统,静态派发和动态派发自动识别,类型别名、类型扩展 9 | 6. 类型默认实现,范型偏特化,自动识别接口 10 | 7. 图灵完备的现代宏,元编程范式,语法糖开关 11 | 8. 变量、函数、方法、运算符重载 12 | 9. 用注释实现编译器标注、提示。意味着编译器可以无视、酌情处理这些标注 13 | 10. 标准库定制开关化(以适用嵌入式平台或高级操作系统编程) 14 | 15 | 代价: 16 | 1. 编译器实现复杂 17 | 2. 编译时间长(可通过部分编译、增量编译缓存优化) 18 | 3. 学习曲线陡峭 19 | 20 | 关键特性: 21 | 1. 自动类型推导:静态派发和动态派发,默认类型实现,默认函数实现 22 | 2. 已知尺寸类型,未知尺寸类型,自动识别和包装 23 | 3. 生命周期推断:编译期确定,运行期确定 24 | 25 | 26 | --------------------------------- 27 | 28 | 1. 内存空间 29 | --- 30 | 31 | 变量由储存空间及管理方式区分,分为三种: 32 | 33 | - 炉: 仅作用域, 创建关键字: var , 局部变量,迭代变量, 34 | - 栈: 仅作用域, 创建关键字: let , 局部定值、函数参数,【不可变】 35 | - 池: 垃圾回收, 创建关键字: allot , 36 | - 堆: 手动管理, 创建关键字: new , 【不可变】 37 | - 铸: 全局存在, 创建关键字: const, 静态变量、常量、字符串、函数、编译器参数等,【不可变】 38 | 39 | 40 | 41 | 2. 结构化 42 | --- 43 | 44 | struct 45 | class 46 | interface 47 | -------------------------------------------------------------------------------- /feature/variable.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | let a 1 5 | 6 | var b "str" 7 | 8 | allot c 123 9 | 10 | new d "string" 11 | 12 | const e 99.8 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/compile/codegen.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | 5 | #include "llvm/IR/Function.h" 6 | 7 | 8 | #include "gen.h" 9 | 10 | #include "../sys/debug.h" 11 | 12 | #include "../core/splitfix.h" 13 | #include "../core/ast.h" 14 | #include "../core/error.h" 15 | #include "../core/splitfix.h" 16 | #include "../parse/analysis.h" 17 | 18 | using namespace std; 19 | using namespace llvm; 20 | using namespace def::parse; 21 | using namespace def::core; 22 | 23 | 24 | #define T Object::Type 25 | 26 | 27 | /** 28 | * 获取静态对象的 llvm IR 29 | */ 30 | Value* ASTConstant::codegen(Gen & gen) 31 | { 32 | // cout<<"-Codegen::Gen Constant-"<(type) 35 | 36 | 37 | if (ISTY(Bool)) { 38 | return ConstantInt::get( 39 | gen.builder.getInt1Ty(), 40 | value=="true" ? 1 : 0, 41 | false); 42 | 43 | } else if (ISTY(Int)) { 44 | return ConstantInt::get( 45 | gen.builder.getInt32Ty(), 46 | Str::s2l(value), 47 | true); 48 | 49 | } else if (ISTY(Float)) { 50 | return ConstantFP::get( 51 | gen.builder.getFloatTy(), 52 | Str::s2d(value) 53 | ); 54 | 55 | } else if (ISTY(Char)) { 56 | return ConstantInt::get( 57 | gen.builder.getInt32Ty(), 58 | (int)value[0], 59 | false); 60 | 61 | } else if (ISTY(String)) { 62 | return gen.builder.CreateGlobalStringPtr(value); 63 | 64 | } 65 | 66 | return nullptr; 67 | 68 | #undef ISTY 69 | 70 | } 71 | 72 | /** 73 | * new 堆对象创建 74 | */ 75 | Value* ASTNew::codegen(Gen & gen) 76 | { 77 | return obj->codegen(gen); 78 | } 79 | 80 | /** 81 | * malloc 堆内存申请 82 | */ 83 | Value* ASTMalloc::codegen(Gen & gen) 84 | { 85 | // 类型尺寸大小 86 | size_t size = gen.getTypeBitSize(type); 87 | Value *newsz(nullptr); 88 | // FATAL(type->str() + " size " + Str::l2s(size)) 89 | if (auto*cons=dynamic_cast(len)) { 90 | size = size * Str::s2l(cons->value); 91 | newsz = ConstantInt::get(gen.builder.getInt32Ty(), size, true); 92 | } else { 93 | newsz = gen.builder.CreateMul( 94 | ConstantInt::get(gen.builder.getInt32Ty(), size, true), 95 | gen.createLoad(len) 96 | ); 97 | } 98 | // 申请内存空间 99 | auto intty = def::core::Type::get("Int"); 100 | auto ftype = TypeFunction("malloc", intty); 101 | ftype.add(intty); 102 | Function *func = gen.getCLibFunc(ftype); 103 | // 解析参数 104 | std::vector argvs; 105 | argvs.push_back(gen.createLoad( newsz )); 106 | // 新分配的内存地址 107 | Value *vptr = gen.builder.CreateCall(func, argvs); 108 | // 类型转换 109 | // 引用值的类型 110 | llvm::Type* vty = gen.fixType(type); 111 | if (is_array) { // new array 堆数组空间 112 | vty = ArrayType::get(vty, 0); 113 | } 114 | // 转换成指针类型 115 | llvm::Type* vpty = PointerType::get(vty, 0); 116 | // 地址值 117 | Value* v = gen.createLoad(vptr); 118 | // int 转 pointer 119 | return gen.builder.CreateIntToPtr(v, vpty); 120 | } 121 | 122 | /** 123 | * delete 堆内存释放 124 | */ 125 | Value* ASTDelete::codegen(Gen & gen) 126 | { 127 | /* 128 | // 引用类型用 int 32 储存 129 | llvm::Type* vty = gen.fixType(vptr->getType()); 130 | // 地址值 131 | Value* v = gen.varyPointer(vptr); 132 | 133 | // pointer 转 int 134 | Value* adr = gen.builder.CreatePtrToInt(v, nullptr); 135 | */ 136 | 137 | auto intty = def::core::Type::get("Int"); 138 | auto ftype = TypeFunction("free", Type::get("Nil")); 139 | ftype.add(intty); 140 | Function *func = gen.getCLibFunc(ftype); 141 | // 解析参数 142 | std::vector argvs; 143 | Value* vp = vptr->codegen(gen); 144 | if (auto *ins=cast(vp)) { 145 | vp = ins->getOperand(0); 146 | } else { 147 | FATAL("codegen delete error !") 148 | // vp = gen.builder.CreatePtrToInt(vp, gen.fixType(vptr->getType())); 149 | } 150 | argvs.push_back(vp); 151 | // 新分配的内存地址 152 | /*vp->dump(); 153 | func->dump();*/ 154 | Value *freecall = gen.builder.CreateCall(func, argvs); 155 | 156 | return freecall; 157 | } 158 | 159 | /** 160 | * copy 拷贝对象 161 | */ 162 | Value* ASTCopy::codegen(Gen & gen) 163 | { 164 | // 类型 165 | StructType *scty = (StructType*)gen.fixType( value->getType() ); 166 | 167 | // 分配内存 168 | Value *structval = gen.builder.CreateAlloca(scty); 169 | 170 | // 拷贝内存 171 | Value *val = gen.createLoad( value ); 172 | // Value *ptr = gen.builder.CreateGEP(scty, structval, gen.getGEPidxary(0)); 173 | gen.builder.CreateStore(val, structval); 174 | 175 | // 返回新地址 176 | return structval; 177 | 178 | } 179 | 180 | /** 181 | * 获取 Quote 引用对象的 IR 182 | */ 183 | Value* ASTQuote::codegen(Gen & gen) 184 | { 185 | // 引用类型用 int 32 储存 186 | llvm::Type* vty = gen.fixType(type); 187 | // 地址值 188 | Value* v = gen.varyPointer(value); 189 | 190 | // pointer 转 int 191 | return gen.builder.CreatePtrToInt(v, vty); 192 | } 193 | 194 | /** 195 | * 从引用载入对象 196 | */ 197 | Value* ASTLoad::codegen(Gen & gen) 198 | { 199 | auto *qty = dynamic_cast(type); 200 | if (!qty) { // 载入必须为引用类型 201 | FATAL("ASTLoad must be !") 202 | } 203 | // 引用值的类型 204 | llvm::Type* vty = gen.fixType(qty->type); 205 | // 转换成指针类型 206 | llvm::Type* vpty = PointerType::get(vty, 0); 207 | // 地址值 208 | Value* v = gen.createLoad(value); 209 | // int 转 pointer 210 | return gen.builder.CreateIntToPtr(v, vpty); 211 | } 212 | 213 | /** 214 | * 数组对象构造 215 | */ 216 | Value* ASTArrayConstruct::codegen(Gen & gen) 217 | { 218 | // 数组类型 219 | llvm::Type* arrty = gen.fixType(type); 220 | 221 | // 数组空间分配 222 | return gen.builder.CreateAlloca(arrty); 223 | } 224 | 225 | /** 226 | * 数组元素访问 227 | */ 228 | Value* ASTArrayVisit::codegen(Gen & gen) 229 | { 230 | def::core::Type* tarty = instance->getType(); 231 | if (auto*p=dynamic_cast(tarty)) { 232 | tarty = p->type; 233 | } 234 | ArrayType *scty = (ArrayType*)gen.fixType(tarty); 235 | 236 | // 数组值 237 | Value* arrval = instance->codegen(gen); 238 | 239 | // 索引值 240 | Value* inxval = gen.createLoad(index->codegen(gen)); 241 | // 数组元素指针 242 | vector idxlist = gen.getGEPidxary(0); 243 | idxlist.push_back(inxval); 244 | 245 | // 返回数组访问 246 | return gen.builder.CreateGEP(arrval, idxlist); 247 | 248 | 249 | } 250 | 251 | /** 252 | * 数组元素赋值 253 | */ 254 | Value* ASTArrayAssign::codegen(Gen & gen) 255 | { 256 | def::core::Type* tarty = instance->getType(); 257 | if (auto*p=dynamic_cast(tarty)) { 258 | tarty = p->type; 259 | } 260 | ArrayType *scty = (ArrayType*)gen.fixType(tarty); 261 | 262 | // 数组值 263 | Value* arrval = instance->codegen(gen); 264 | 265 | // 索引值 266 | Value* inxval = gen.createLoad(index->codegen(gen)); 267 | 268 | // 数组元素指针 269 | vector idxlist = gen.getGEPidxary(0); 270 | idxlist.push_back(inxval); 271 | Value* elmptr = gen.builder.CreateGEP(arrval, idxlist); 272 | 273 | // 赋值 274 | Value* putval = gen.createLoad(value->codegen(gen)); 275 | 276 | //return putval; 277 | 278 | // 返回数组访问 279 | return gen.builder.CreateStore(putval, elmptr); 280 | 281 | } 282 | 283 | /** 284 | * Group 285 | */ 286 | Value* ASTGroup::codegen(Gen & gen) 287 | { 288 | Value* last = nullptr; 289 | for (auto &one : childs) { 290 | // delete last; 291 | if (one) { 292 | auto *li = one->codegen(gen); 293 | if (li) { 294 | last = li; 295 | } 296 | } 297 | } 298 | return last; 299 | } 300 | 301 | /** 302 | * 获取静态对象的 llvm IR 303 | */ 304 | Value* ASTFunctionCall::codegen(Gen & gen) 305 | { 306 | string fname = fndef->ftype->name; 307 | string idname = fndef->getIdentify(); 308 | 309 | #define X DEF_SPLITFIX_FUNCARGV 310 | // 内置操作 311 | if (idname=="bool" X "Int") { 312 | Value* v1 = gen.createLoad(params[0]); 313 | Value* res = gen.builder.CreateICmpNE( 314 | v1, ConstantInt::get( gen.builder.getInt32Ty(), 0, true)); 315 | return res; 316 | } 317 | // 内置操作 + 318 | if (idname=="add" X "Int" X "Int") { 319 | Value* v1 = gen.createLoad(params[0]); 320 | Value* v2 = gen.createLoad(params[1]); 321 | // v1->dump(); 322 | // v2->dump(); 323 | Value* res = gen.builder.CreateAdd(v1, v2); 324 | return res; 325 | } 326 | // 内置操作 - 327 | if (idname=="sub" X "Int" X "Int") { 328 | Value* v1 = gen.createLoad(params[0]); 329 | Value* v2 = gen.createLoad(params[1]); 330 | Value* res = gen.builder.CreateSub(v1, v2); 331 | return res; 332 | } 333 | // 内置操作 * 334 | if (idname=="mul" X "Int" X "Int") { 335 | Value* v1 = gen.createLoad(params[0]); 336 | Value* v2 = gen.createLoad(params[1]); 337 | Value* res = gen.builder.CreateMul(v1, v2); 338 | return res; 339 | } 340 | // 内置操作 / 341 | if (idname=="div" X "Int" X "Int") { 342 | Value* v1 = gen.createLoad(params[0]); 343 | Value* v2 = gen.createLoad(params[1]); 344 | Value* res = gen.builder.CreateSDiv(v1, v2); 345 | return res; 346 | } 347 | // 内置操作 348 | if (idname=="add" X "Float" X "Int") { 349 | Value *pv1 = gen.builder.CreateFPToSI( 350 | gen.createLoad(params[0]), 351 | gen.builder.getInt32Ty()); 352 | Value* res = gen.builder.CreateAdd( 353 | pv1, 354 | gen.createLoad(params[1]) 355 | ); 356 | return res; 357 | } 358 | // 内置操作 359 | if (idname=="add" X "Int" X "Float") { 360 | Value *pv2 = gen.builder.CreateFPToSI( 361 | gen.createLoad(params[1]), 362 | gen.builder.getInt32Ty()); 363 | Value* res = gen.builder.CreateAdd( 364 | gen.createLoad(params[0]), 365 | pv2 366 | ); 367 | return res; 368 | } 369 | // 内置操作 370 | if (idname=="add" X "Float" X "Float") { 371 | Value* res = gen.builder.CreateFAdd( 372 | gen.createLoad(params[0]), 373 | gen.createLoad(params[1]) 374 | ); 375 | return gen.builder.CreateFPToSI(res, gen.builder.getInt32Ty()); 376 | } 377 | 378 | // 条件判断 379 | if (idname=="eq" X "Int" X "Int") { 380 | return gen.builder.CreateICmpEQ( 381 | gen.createLoad(params[0]), 382 | gen.createLoad(params[1]) 383 | ); 384 | } 385 | 386 | 387 | 388 | 389 | 390 | #ifdef DEBUG 391 | string llvmvn("ctmp."+fname); 392 | #else 393 | string llvmvn(""); // release 版本显示函数返回值变量名 394 | #endif 395 | 396 | 397 | // 内置函数 398 | if (idname == "putchar" X "Int") { 399 | idname = "putchar" X "Char"; // 统一输出 int 和 char 400 | } 401 | if ( 402 | idname == "putchar" X "Char" || 403 | idname == "abs" X "Int" 404 | // ... 其它内置函数 405 | ) { 406 | 407 | Function *func = gen.getCLibFunc(*fndef->ftype); 408 | 409 | // 解析参数 410 | std::vector argvs; 411 | for (auto &p : params) { 412 | Value *val = gen.createLoad( p ); 413 | argvs.push_back(val); 414 | } 415 | return gen.builder.CreateCall(func, argvs, llvmvn); 416 | } 417 | 418 | #undef X 419 | 420 | 421 | // 获得函数 422 | Function *func = gen.createFunction(this); 423 | 424 | // 解析参数 425 | std::vector argvs; 426 | // 函数调用,捕获的变量,先查找真实名字,再查全局唯一名称 427 | for (auto &p : fndef->cptvar) { 428 | string real_name = p.first; 429 | string unique_name = get<1>(p.second); 430 | Value *ov = gen.values->get(real_name); 431 | if(!ov){ 432 | ov = gen.unique_values->get(unique_name); 433 | } 434 | ASSERT(ov, "ASTFunctionCall::codegen: cptvar '"+real_name+"' not find !") 435 | Value *pv = gen.varyPointer(ov); 436 | argvs.push_back(pv); 437 | // pv->dump(); 438 | } 439 | // 实际参数 440 | for (auto &p : params) { 441 | // 转换结构或数组值参数为指针 442 | Value *pv; 443 | def::core::Type *pty = p->getType(); 444 | auto *ptty = dynamic_cast(pty); 445 | auto *stty = dynamic_cast(pty); 446 | auto *arty = dynamic_cast(pty); 447 | if(ptty){ 448 | pv = gen.varyPointer(p); 449 | } else if (stty || arty) { 450 | pv = gen.varyPointer(p); 451 | if (arty) { // 如果实参为数组且长度大于形参,则转换实参类型 452 | size_t pmidx = argvs.size(); 453 | auto *vsarty = dynamic_cast( 454 | fndef->ftype->types[pmidx]); 455 | // 数组类型长度转换 456 | if (arty->len > vsarty->len) { 457 | Value *vint = gen.builder.CreatePtrToInt(pv, gen.builder.getInt32Ty()); 458 | auto *pty = PointerType::get( 459 | ArrayType::get(gen.fixType(arty->type), vsarty->len), 0); 460 | pv = gen.builder.CreateIntToPtr(vint, pty); 461 | } else { 462 | FATAL("Function argument is an array,The actual length should be looger than the declare !"); 463 | } 464 | 465 | } 466 | } else { 467 | pv = gen.createLoad(p); 468 | } 469 | argvs.push_back(pv); 470 | // pv->dump(); 471 | } 472 | 473 | 474 | // 创建调用 475 | /* 476 | if (0==argvs.size()) { 477 | // 无参函数 478 | return gen.builder.CreateCall(func, None, "noargvcalltmp"); 479 | } 480 | */ 481 | 482 | // 创建调用,得到返回数据的地址 483 | /* 484 | func->dump(); 485 | cout << "gen.builder.CreateCall: " << idname 486 | << " param num: " << func->arg_size() 487 | << " argv num: " << argvs.size() << endl; 488 | */ 489 | Value *retptr = gen.builder.CreateCall(func, argvs, llvmvn); 490 | 491 | // 如果返回值是对象 则取其地址 492 | // (临时做法:分配内存,再拷贝函数返回值进入) 493 | /* 494 | auto rty = fndef->ftype->ret; 495 | if (dynamic_cast(rty)) { 496 | Value *retaoc = gen.builder.CreateAlloca( 497 | gen.fixType(rty)); 498 | gen.builder.CreateStore(retptr, retaoc); // 复制返回值 499 | return retaoc; // 返回内存地址 500 | // return gen.builder.CreateLoad(callret); 501 | // callret = gen.builder.CreateGEP(gen.fixType(frty), callret, 0); 502 | } 503 | */ 504 | 505 | 506 | 507 | return retptr; 508 | } 509 | 510 | /** 511 | * 成员函数调用 512 | */ 513 | Value* ASTMemberFunctionCall::codegen(Gen & gen) 514 | { 515 | string tyname = call->fndef->ftype->name; 516 | string idname = call->fndef->getIdentify(); 517 | 518 | // 创建获取函数 519 | Function *func = gen.createFunction(call); 520 | 521 | // 解析参数 522 | std::vector argvs; 523 | 524 | // 类实例(非静态) 525 | if( ! call->fndef->is_static_member ){ 526 | Value *pv = gen.varyPointer(instance); 527 | argvs.push_back(pv); 528 | // pv->dump(); 529 | } 530 | 531 | // 实际参数 532 | for (auto &p : call->params) { 533 | // 转换结构值参数为结构指针 534 | Value *pv; 535 | if (p->getType()->isAtomType()) { 536 | pv = gen.createLoad(p); 537 | }else{ 538 | pv = gen.varyPointer(p); 539 | } 540 | argvs.push_back(pv); 541 | // pv->dump(); 542 | } 543 | 544 | // 创建调用 545 | /* 546 | func->dump(); 547 | cout << "gen.builder.CreateCall: " << idname 548 | << " param num: " << func->arg_size() 549 | << " argv num: " << argvs.size() << endl; 550 | cout << " ========================== " << endl; 551 | */ 552 | 553 | // 如果是构造函数 554 | if (call->fndef->is_construct) 555 | { 556 | gen.builder.CreateCall(func, argvs); 557 | return argvs[0]; // 返回类实例指针 558 | } 559 | 560 | // 普通成员函数 561 | Value *retptr = gen.builder.CreateCall(func, argvs); 562 | 563 | return retptr; 564 | } 565 | 566 | /** 567 | * 成员访问 568 | */ 569 | Value* ASTMemberVisit::codegen(Gen & gen) 570 | { 571 | def::core::Type* tarty = instance->getType(); 572 | if (auto*p=dynamic_cast(tarty)) { 573 | tarty = p->type; 574 | } 575 | StructType *scty = (StructType*)gen.fixType(tarty); 576 | 577 | Value* structval = gen.varyPointer(instance); 578 | return gen.builder.CreateStructGEP(scty, structval, index); 579 | 580 | /* 581 | Value* structval = instance->codegen(gen); 582 | 583 | // 结构值(如函数返回值) 584 | if ( isa(scty) ) { 585 | return gen.builder.CreateStructGEP( scty, structval, index); 586 | } else { 587 | return gen.builder.CreateExtractValue(structval, index); 588 | } 589 | */ 590 | 591 | } 592 | 593 | /** 594 | * 成员赋值 595 | */ 596 | Value* ASTMemberAssign::codegen(Gen & gen) 597 | { 598 | def::core::Type* tarty = instance->getType(); 599 | if (auto*p=dynamic_cast(tarty)) { 600 | tarty = p->type; 601 | } 602 | StructType *scty = (StructType*)gen.fixType(tarty); 603 | 604 | // Value* structval = instance->codegen(gen); 605 | Value* putval = gen.createLoad(value); // argvs[1]->codegen(gen); 606 | 607 | Value* structval = gen.varyPointer(instance); 608 | Value* ptr = gen.builder.CreateStructGEP( scty, structval, index); 609 | return gen.builder.CreateStore(putval, ptr); 610 | 611 | /* 612 | // 结构值(如函数返回值) 613 | if ( ! isa(structval->getType())) { 614 | // Value *ptr = gen.builder.CreateExtractValue(structval, pos); 615 | return gen.builder.CreateInsertValue(putval, structval, index); 616 | } else { // 结构值指针 617 | Value* ptr = gen.builder.CreateStructGEP( scty, structval, index); 618 | return gen.builder.CreateStore(putval, ptr); 619 | } 620 | */ 621 | } 622 | 623 | /** 624 | * 获取类型构造调用的 IR 625 | */ 626 | Value* ASTTypeConstruct::codegen(Gen & gen) 627 | { 628 | // 创建函数 629 | StructType *scty = (StructType*)gen.fixType( type ); 630 | 631 | Value *structval = instance // 已经分配了内存 632 | ? instance->codegen(gen) 633 | : gen.builder.CreateAlloca(scty); 634 | 635 | if (! bare ) { // 不是空构造 636 | int len = childs.size(); 637 | for (int i = 0; i < len; i++) { 638 | AST *child = childs[i]; 639 | Value *val = gen.createLoad( child ); 640 | Value *ptr = gen.builder.CreateStructGEP( 641 | scty, structval, i); 642 | gen.builder.CreateStore(val, ptr); 643 | } 644 | } 645 | 646 | return structval; // gen.builder.CreateLoad(structval); 647 | } 648 | 649 | /** 650 | * 变量初始化 IR 651 | */ 652 | Value* ASTVariableDefine::codegen(Gen & gen) 653 | { 654 | Value *val = value->codegen(gen); 655 | ASSERT(val, "Variable define null value : "+name) 656 | /*if (value->getType()->isAtomType()) { 657 | val = gen.createLoad(val); // 原子类型传值,类和数组传引用 658 | } else{ 659 | val = gen.varyPointer(val); 660 | }*/ 661 | val = gen.varyPointer(val); 662 | gen.values->put(name, val); // 放入真实名字 663 | gen.unique_values->put(unique_name, val); // 放入全局唯一名字 664 | return val; 665 | } 666 | 667 | /** 668 | * 变量赋值 669 | */ 670 | Value* ASTVariableAssign::codegen(Gen & gen) 671 | { 672 | string vname = name; // 变量名 673 | 674 | Value *val = value->codegen(gen); 675 | ASSERT(val, "Variable assign null value : "+name) 676 | 677 | Value *old = gen.values->get(vname); 678 | if(!old){ 679 | // 支持从名字空间导入不在当前作用域的变量 680 | old = gen.unique_values->get(unique_name); 681 | vname = unique_name; 682 | } 683 | ASSERT(old, "Variable assign not find the value : "+vname) 684 | old = gen.varyPointer(old); 685 | 686 | // 赋值 687 | Value * sto = gen.builder.CreateStore(val, old); 688 | ASSERT(sto, "Variable assign cannot CreateStore"); 689 | 690 | // 放入(必须为 Store 节点!) 691 | gen.values->put(name, sto); 692 | if(unique_name!=""){ // 可能为参数赋值 693 | gen.unique_values->put(unique_name, sto); 694 | } 695 | 696 | return val; 697 | } 698 | 699 | /** 700 | * 变量值 IR 701 | */ 702 | Value* ASTVariable::codegen(Gen & gen) 703 | { 704 | Value* v = gen.values->get(name); 705 | if (!v) { 706 | // 支持从名字空间导入不在当前作用域的变量 707 | v = gen.unique_values->get(unique_name); 708 | } 709 | ASSERT(v, "codegen: Cannot find variable: " + name) 710 | return v; 711 | } 712 | 713 | /** 714 | * 指令 IR 715 | */ 716 | Value* ASTRet::codegen(Gen & gen) 717 | { 718 | if (!value) { 719 | return gen.builder.CreateRetVoid(); 720 | } 721 | // 函数返回 722 | Value *retval(nullptr); 723 | AST *ret(nullptr); 724 | /* 725 | if (auto*astv=dynamic_cast(value)) { 726 | ret = astv->origin; 727 | } else { 728 | ret = value; 729 | } 730 | // 返回堆上的指针对象 731 | if (dynamic_cast(ret)) { 732 | */ 733 | if (dynamic_cast(value->getType())) { 734 | retval = value->codegen(gen); 735 | } else { 736 | retval = gen.createLoad(value); 737 | } 738 | // 返回 739 | ASSERT(retval, "ASTRet null return value") 740 | return gen.builder.CreateRet( retval ); 741 | } 742 | 743 | /** 744 | * if 条件分支 745 | */ 746 | Value* ASTIf::codegen(Gen & gen) 747 | { 748 | // if 节点返回值 749 | Value *v_ret(nullptr); 750 | auto *thefunc = gen.builder.GetInsertBlock()->getParent(); 751 | 752 | Value *v_cond = cond->codegen(gen); 753 | auto *b_then = BasicBlock::Create(gen.context, "then", thefunc); 754 | auto *b_else = BasicBlock::Create(gen.context, "else", thefunc); 755 | auto *b_merge = BasicBlock::Create(gen.context, "ifcont", thefunc); 756 | 757 | // 跳转分支 758 | gen.builder.CreateCondBr(v_cond, b_then, b_else); 759 | 760 | // then block 761 | gen.builder.SetInsertPoint(b_then); 762 | Value *v_then = pthen->codegen(gen); 763 | gen.builder.CreateBr(b_merge); 764 | b_then = gen.builder.GetInsertBlock(); 765 | 766 | // else block 767 | gen.builder.SetInsertPoint(b_else); 768 | Value *v_else = pelse ? pelse->codegen(gen) : nullptr; 769 | gen.builder.CreateBr(b_merge); 770 | b_else = gen.builder.GetInsertBlock(); 771 | 772 | // merge block 773 | gen.builder.SetInsertPoint(b_merge); 774 | // if 分支类型一致 HasHungOffUses 775 | if (canphi) { 776 | PHINode *phi = gen.builder.CreatePHI( 777 | v_then->getType(), 2, "iftmp"); 778 | phi->addIncoming(v_then, b_then); 779 | phi->addIncoming(v_else, b_else); 780 | v_ret = phi; 781 | } 782 | 783 | return v_ret; 784 | } 785 | 786 | /** 787 | * while 循环 788 | */ 789 | Value* ASTWhile::codegen(Gen & gen) 790 | { 791 | 792 | 793 | // while 节点返回值 794 | Value *v_ret(nullptr); 795 | auto *thefunc = gen.builder.GetInsertBlock()->getParent(); 796 | // BasicBlock *b_current = gen.builder.GetInsertBlock(); 797 | auto *b_cond = BasicBlock::Create(gen.context, "loopcond", thefunc); 798 | auto *b_loop = BasicBlock::Create(gen.context, "loopbody", thefunc); 799 | auto *b_end = BasicBlock::Create(gen.context, "loopend", thefunc); 800 | // 循环条件判断 801 | gen.builder.CreateBr(b_cond); 802 | gen.builder.SetInsertPoint(b_cond); 803 | Value *v_cond = cond->codegen(gen); 804 | gen.builder.CreateCondBr(v_cond, b_loop, b_end); 805 | // 执行循环体 806 | gen.builder.SetInsertPoint(b_loop); 807 | Value *v_body = body->codegen(gen); 808 | gen.builder.CreateBr(b_cond); 809 | 810 | /* 811 | PHINode *phi = gen.builder.CreatePHI( 812 | gen.builder.getInt1Ty(), 2, "whilecond"); 813 | phi->addIncoming(v_start, b_current); 814 | */ 815 | 816 | gen.builder.SetInsertPoint(b_end); 817 | 818 | return nullptr; 819 | 820 | 821 | 822 | 823 | } 824 | 825 | /** 826 | * 子作用域 827 | */ 828 | Value* ASTChildScope::codegen(Gen & gen) 829 | { 830 | // 栈重置 831 | auto ostk = gen.values; 832 | auto nstk = new Scope(ostk); 833 | gen.values = nstk; 834 | // 解析子句 835 | Value* last(nullptr); 836 | for(auto li : childs){ 837 | last = li->codegen(gen); 838 | } 839 | // 栈复位 840 | delete nstk; 841 | gen.values = ostk; 842 | return last; 843 | } 844 | 845 | /** 846 | * lambda 调用 847 | */ 848 | Value* ASTLambdaCall::codegen(Gen & gen) 849 | { 850 | auto intv = address->codegen(gen); 851 | auto fty = (FunctionType*)gen.fixType(ftype); 852 | auto pfty = PointerType::get(fty, 0); 853 | auto funcptr = gen.builder.CreateIntToPtr(intv, pfty); 854 | // 解析函数参数 855 | std::vector argvs; 856 | for(auto &li : params){ 857 | argvs.push_back(li->codegen(gen)); 858 | } 859 | 860 | auto result = gen.builder.CreateCall(funcptr, argvs); 861 | return result; 862 | 863 | // return ConstantInt::get(gen.builder.getInt32Ty(), 1, false); 864 | } 865 | 866 | /** 867 | * lambda 定义 868 | */ 869 | Value* ASTLambdaDefine::codegen(Gen & gen) 870 | { 871 | auto fun = gen.createFunctionByDefine(func); 872 | auto intv = gen.builder.CreatePtrToInt(fun, gen.builder.getInt32Ty()); 873 | 874 | return intv; 875 | // return ConstantInt::get(gen.builder.getInt32Ty(), 1, false); 876 | // return nullptr; 877 | } 878 | 879 | /** 880 | * 数据打包 881 | */ 882 | Value* ASTValPtrZip::codegen(Gen & gen) 883 | { 884 | // 创建包装类型 885 | StructType *scty = (StructType*)gen.fixType( type ); 886 | Value *structval = gen.builder.CreateAlloca(scty); 887 | int len = values.size(); 888 | for (int i = 0; i < len; i++) { 889 | AST *child = values[i]; 890 | Value *val = gen.varyPointer( child ); 891 | Value *ptr = gen.builder.CreateStructGEP( 892 | scty, structval, i); 893 | gen.builder.CreateStore(val, ptr); 894 | } 895 | // 转换为 int 896 | auto intv = gen.builder.CreatePtrToInt( 897 | structval, gen.builder.getInt32Ty()); 898 | return intv; 899 | 900 | } 901 | 902 | 903 | /** 904 | * 数据拆包 905 | */ 906 | Value* ASTValPtrUnzip::codegen(Gen & gen) 907 | { 908 | // 创建包装类型 909 | auto scty = (StructType*)gen.fixType(type); 910 | auto scptrty = PointerType::get(scty, 0); 911 | auto lbdthis = gen.createLoad(value); 912 | auto stptr = gen.builder.CreateIntToPtr(lbdthis, scptrty); 913 | 914 | Value *last = nullptr; 915 | int len = type->types.size(); 916 | for (int i = 0; i < len; i++) { // 全部解包 917 | Value *liptr = gen.builder.CreateStructGEP( 918 | scty, stptr, i); 919 | last = gen.builder.CreateLoad(liptr); 920 | // 注册变量 921 | gen.values->put(type->tabs[i], last); 922 | } 923 | 924 | return last; 925 | 926 | } 927 | 928 | -------------------------------------------------------------------------------- /src/compile/gen.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/compile/gen.cc -------------------------------------------------------------------------------- /src/compile/gen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "llvm/IR/LLVMContext.h" 5 | #include "llvm/IR/IRBuilder.h" 6 | #include "llvm/IR/Module.h" 7 | #include "llvm/IR/ConstantFolder.h" 8 | 9 | #include "../global.h" 10 | #include "../core/type.h" 11 | #include "./scope.h" 12 | 13 | 14 | namespace def { 15 | namespace core { 16 | class AST; 17 | } 18 | } 19 | 20 | 21 | namespace def { 22 | namespace compile { 23 | 24 | using namespace std; 25 | using namespace llvm; 26 | using namespace def::core; 27 | 28 | 29 | class Gen{ 30 | 31 | public: 32 | 33 | LLVMContext & context; 34 | IRBuilder<> builder; 35 | Module module; 36 | Function * main; 37 | BasicBlock * entry; 38 | 39 | Gen(LLVMContext & con, const string & m = "main") 40 | : context(con) 41 | , builder(con) 42 | , module(m, con) 43 | { 44 | FunctionType *fty = FunctionType::get(builder.getVoidTy(), false); 45 | main = Function::Create(fty, Function::ExternalLinkage, "main", &module); 46 | entry = BasicBlock::Create(context, "entry", main); 47 | builder.SetInsertPoint(entry); 48 | // 变量栈 49 | unique_values = values = new Scope(); 50 | } 51 | 52 | // codegen 完成后的收尾工作 53 | void finish() { 54 | // builder.SetInsertPoint(entry); 55 | builder.CreateRetVoid(); 56 | } 57 | 58 | ~Gen(){ 59 | // delete main; 60 | // delete entry; 61 | } 62 | 63 | // Type 类型映射 64 | llvm::Type* fixType( 65 | def::core::Type*, 66 | vector* append=nullptr // 追加的类型参数 67 | ); 68 | llvm::Type* fixBuiltinFunctionType(def::core::TypeFunction*); 69 | 70 | // 通用处理 71 | Value* varyPointer(AST*); // 将 AST 处理成可以作为函数参数使用 72 | Value* varyPointer(Value*); 73 | Value* createLoad(AST*); 74 | Value* createLoad(Value*); 75 | 76 | Function* createFunction(AST*); 77 | Function* createFunctionByCall(AST*); 78 | Function* createFunctionByDefine(AST*); 79 | 80 | // 变量操作 81 | // Value* getValue(const string &); 82 | // Value* putValue(const string &, Value*); // 返回旧变量 83 | 84 | // 获取子元素指针选择器 85 | vector getGEPidxary(int=0,int=-1); 86 | 87 | // 获取变量内存宽度 88 | int getTypeBitSize(def::core::Type*); 89 | 90 | // 获取 C 库函数 91 | Function * getCLibFunc(def::core::TypeFunction); 92 | 93 | 94 | public: 95 | 96 | // 当前可见作用域创建的变量 97 | // map values; 98 | Scope * values; 99 | Scope * unique_values; // 函数作用域的全局唯一名称变量 100 | 101 | }; 102 | 103 | 104 | 105 | 106 | } // --end-- namespace compile 107 | } // --end-- namespace def 108 | 109 | -------------------------------------------------------------------------------- /src/compile/scope.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/compile/scope.h -------------------------------------------------------------------------------- /src/compile/target.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/compile/target.cc -------------------------------------------------------------------------------- /src/compile/target.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/compile/target.h -------------------------------------------------------------------------------- /src/core/ast.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/core/ast.cc -------------------------------------------------------------------------------- /src/core/ast.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/core/ast.h -------------------------------------------------------------------------------- /src/core/builtin.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/core/builtin.cc -------------------------------------------------------------------------------- /src/core/builtin.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/core/builtin.h -------------------------------------------------------------------------------- /src/core/error.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/core/error.cc -------------------------------------------------------------------------------- /src/core/error.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/core/error.h -------------------------------------------------------------------------------- /src/core/splitfix.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/core/splitfix.h -------------------------------------------------------------------------------- /src/core/type.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/core/type.cc -------------------------------------------------------------------------------- /src/core/type.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jojoin/Def/4dad74162da555ef02177f5e00f04210da0fca17/src/core/type.h -------------------------------------------------------------------------------- /src/def.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Def 虚拟机入口 4 | */ 5 | 6 | /* 7 | 8 | 9 | 1. 统一表达形式 10 | 2. 可扩展的内核 11 | 3. 操作符绑定 12 | 4. 面向对象 13 | 5. 类型推导 14 | 6. 模式匹配:参数值匹配,精确条件匹配,参数类型匹配 15 | 16 | 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "llvm/Support/raw_ostream.h" 25 | #include "llvm/Analysis/Passes.h" 26 | #include "llvm/IR/LegacyPassManager.h" 27 | #include "llvm/Transforms/Scalar.h" 28 | #include "llvm/IR/Verifier.h" 29 | 30 | // 编译执行 31 | #include "llvm/ExecutionEngine/GenericValue.h" 32 | #include "llvm/ExecutionEngine/MCJIT.h" 33 | 34 | #include "./global.h" 35 | #include "./sys/debug.h" 36 | 37 | #include "./util/str.h" 38 | #include "./util/fs.h" 39 | #include "./util/path.h" 40 | #include "./util/argv.h" 41 | 42 | #include "./parse/tokenizer.h" 43 | #include "./parse/analysis.h" 44 | 45 | #include "./compile/gen.h" 46 | #include "./compile/target.h" 47 | 48 | #include "./core/error.h" 49 | 50 | 51 | 52 | using namespace std; 53 | 54 | using namespace def::util; 55 | using namespace def::sys; 56 | using namespace def::parse; 57 | // using namespace def::compile; 58 | 59 | 60 | 61 | /** 62 | * 添加命令行参数处理 63 | */ 64 | void addArgvOption(argv::OptionParser & parser) 65 | { 66 | // 开启指定调试代码 67 | parser.add_option("-d", "--debug") 68 | .help("open the specified debug code"); 69 | // 打印 llvm ir 70 | parser.add_option("-p", "--print") 71 | // .action("store_true") 72 | .help("print llvm IR(ir), assembly file(asm) in console"); 73 | // 输出内容到文件 74 | parser.add_option("-e", "--emit") 75 | .set_default("obj") 76 | .help("emit llvm IR file(ir), assembly file(asm) or object file(obj)"); 77 | // 直接执行代码 78 | parser.add_option("-o", "--output") 79 | .help("output file for emit"); 80 | // 直接执行代码 81 | parser.add_option("-r", "--run") 82 | .help("run the code immediately"); 83 | 84 | 85 | 86 | 87 | 88 | } 89 | 90 | 91 | /** 92 | * 添加命令行参数处理 93 | */ 94 | argv::Values getArgs(int argc, char*argv[]) 95 | { 96 | const string usage = "usage: %prog DIR [FILE]... [OPTION]..."; 97 | const string version = "0.1.0"; 98 | const string desc = "Def is a ..."; 99 | const string epilog = "end of Def"; 100 | // 命令行参数处理 101 | argv::OptionParser argvparser = argv::OptionParser() 102 | .usage(usage) 103 | .version(version) 104 | .description(desc) 105 | .epilog (epilog ) 106 | ; 107 | // 添加解析 108 | addArgvOption(argvparser); 109 | // 解析参数 110 | argv::Values& options = argvparser.parse_args(argc, argv); 111 | vector args = argvparser.args(); 112 | size_t len = 0; 113 | for (vector::const_iterator it = args.begin(); 114 | it != args.end(); ++it, ++len) { 115 | options.set("_"+Str::l2s(len)+"_", *it); 116 | // cout << "arg: " << *it << endl; 117 | } 118 | // 解析参数 119 | return options; 120 | } 121 | 122 | 123 | /** 124 | * 开始运行 125 | */ 126 | int run(const string & file, argv::Values & options) 127 | { 128 | // 文件绝对路径 129 | string absfile = Path::absolute(file); 130 | // cout << absfile << endl; 131 | 132 | // 初始化词法分析器 133 | Tokenizer tkz(absfile); 134 | 135 | // 执行语法分析 136 | Analysis als(&tkz); 137 | als.checkSetInclude(absfile); // include唯一性 138 | AST* tree = als.createAST(); 139 | 140 | // 打印语法分析树 141 | DEBUG_WITH("ast_tree", \ 142 | cout << endl << endl << "==== AST tree ===" << endl << endl; \ 143 | tree->print(); \ 144 | cout << endl << "====== end ======" << endl << endl;\ 145 | ) 146 | 147 | // 打印语法分析栈 148 | DEBUG_WITH("als_stack", \ 149 | cout << endl << endl << "==== Analysis stack ( main ) ===" << endl << endl; \ 150 | als.stack->print(); \ 151 | cout << endl << "====== end ======" << endl << endl; \ 152 | ) 153 | 154 | 155 | // LLVM CodeGen 156 | LLVMContext context; 157 | Gen gen(context, "main"); 158 | // 生成代码 159 | llvm::Value* value = tree->codegen(gen); 160 | gen.finish(); 161 | 162 | // 优化方案 163 | /* 164 | auto theFPM = legacy::FunctionPassManager(&gen->module); 165 | theFPM.add(createBasicAliasAnalysisPass()); 166 | theFPM.add(createInstructionCombiningPass()); 167 | theFPM.add(createReassociatePass()); 168 | theFPM.add(createGVNPass()); 169 | theFPM.add(createCFGSimplificationPass()); 170 | */ 171 | 172 | // 打印内容 173 | if (options.is_set("print")) { 174 | string print = options["print"]; 175 | if (print=="ir") { 176 | gen.module.dump(); 177 | } 178 | } 179 | 180 | // 输出内容至文件 181 | if (options.is_set("emit")&&options.is_set("output")) { 182 | string emit = options["emit"]; 183 | string filename = options["output"]; 184 | // ast tree 185 | if (emit=="ast") { 186 | ofstream outfile(filename); 187 | streambuf *oldbuf = cout.rdbuf(); 188 | cout.rdbuf(outfile.rdbuf()); 189 | tree->print(); // 重定向 cout 流 190 | cout.rdbuf(oldbuf);// 复位 191 | // llvm IR 192 | } else if (emit=="ir") { 193 | std::error_code cd; 194 | raw_fd_ostream ofile(filename, cd, llvm::sys::fs::OpenFlags(8)); 195 | ofile << gen.module; 196 | ofile.close(); 197 | // 汇编 198 | } else if(emit=="obj" || emit=="asm") { 199 | def::compile::Target tar(context, gen.module); 200 | TargetMachine::CodeGenFileType cgft; 201 | // 输出类型 202 | if (emit == "asm") { 203 | cgft = TargetMachine::CGFT_AssemblyFile; 204 | } else if (emit == "obj") { 205 | cgft = TargetMachine::CGFT_ObjectFile; 206 | } 207 | // 执行输出 208 | tar.output(filename, cgft); 209 | } 210 | } 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | return 0; 219 | } 220 | 221 | 222 | 223 | 224 | 225 | /** 226 | * 入口 227 | */ 228 | int main(int argc, char *argv[]) 229 | { 230 | // 命令行参数 231 | argv::Values & options = getArgs(argc, argv); 232 | 233 | // 设置调试打印模式 234 | if (options.is_set("debug")) { 235 | vector ds; 236 | Str::split(options["debug"], ",", ds); 237 | vector::iterator it = ds.begin(); 238 | int len = 1; 239 | for (; it != ds.end(); ++it, ++len) { 240 | Str::trim(*it); 241 | Debug::SetType(*it, len); 242 | //cout << "[" << *it << "]" < Other input will be treated as def code file to run, like 'hello.def'"<>>"; 363 | string input; 364 | getline(cin, input); 365 | str = input; 366 | if(input=="quit"){ // 退出 367 | break; 368 | }else if(input==""){ // 进入多行模式 369 | while(1){ 370 | cout<<" "; 371 | getline(cin, input); 372 | if(input==""){ // 退出多行 373 | break; 374 | } 375 | str += " "+input; 376 | } 377 | } 378 | // cin >> input; 379 | // cout<Print(true); // 递归打印 383 | cout< 6 | 7 | #include "tokenizer.h" 8 | 9 | #include "../core/error.h" 10 | #include "../util/fs.h" 11 | #include "../util/str.h" 12 | #include "../sys/debug.h" 13 | 14 | using namespace std; 15 | using namespace def::util; 16 | using namespace def::sys; 17 | using namespace def::core; 18 | 19 | 20 | namespace def { 21 | namespace parse { 22 | 23 | 24 | #define ERR(str) cerr<=part.size()) { 152 | return '\0'; // 结束 153 | } 154 | */ 155 | // 读取单个字符 156 | char t = part[part_seek]; 157 | seek(1); // 向前一步 158 | if(t=='\n'){ 159 | curline++; // 换行 160 | cursor = 0; 161 | } 162 | return t; 163 | 164 | } 165 | 166 | 167 | /** 168 | * 获取转义字符 169 | */ 170 | char Tokenizer::escape(const char & t) 171 | { 172 | switch (t) { 173 | case '\'': // fall through 174 | case '"' : // fall through 175 | case '\\': 176 | return t; 177 | case '0' : return '\0'; //NULL空字符 178 | case 'a' : return '\a'; //响铃 179 | case 'b' : return '\b'; //退格 180 | case 'f' : return '\f'; //换页 181 | case 'n' : return '\n'; //换行 182 | case 'r' : return '\r'; //回车 183 | case 't' : return '\t'; //水平制表 184 | } 185 | return t; 186 | } 187 | 188 | 189 | /** 190 | * 判断是否为合法的符号 191 | */ 192 | bool Tokenizer::isoperator(const char & t) 193 | { 194 | // 保留符号 () ' " ` ; 195 | string opts = "~!@#$%^&*-+=/\\,.:?|<>[]{}"; 196 | int pos = opts.find_first_of(t); 197 | return pos==-1 ? false : true; 198 | } 199 | bool Tokenizer::isoperator(const string & tok) 200 | { 201 | int len = tok.length(); 202 | for(int i=0; i='a' && tok<='z') || 217 | (tok>='A' && tok<='Z') || 218 | tok=='_' 219 | ){ //字母或下划线 220 | return State::Character; 221 | } 222 | 223 | if( tok==' ' || tok=='\t'){ // 空格或tab 224 | return State::Space; 225 | } 226 | 227 | if( tok>='0' && tok<='9' ){ // 数字 228 | return State::Number; 229 | } 230 | 231 | if (tok == DEF_RESERVED_TOK_ANNOTA) { // 注释 232 | return State::Annotation; 233 | } 234 | 235 | if( tok=='"' ){ // 双引号 字符串 236 | return State::String; 237 | } 238 | if( tok=='\'' ){ // 单引号 字符 239 | return State::Char; 240 | } 241 | 242 | if (tok == '(' || tok == ')') { // 保留符号 243 | return State::Sign; 244 | } 245 | 246 | if( tok==DEF_RESERVED_TOK_SIGN ){ // 符号引用 247 | return State::QuoteOperator; 248 | } 249 | 250 | //有效符号 251 | if( isoperator(tok) ){ 252 | return State::Operator; 253 | } 254 | 255 | if( tok=='\n' ){ //结束 256 | return State::NewLine; 257 | } 258 | 259 | if( tok=='\0' ){ //结束 260 | return State::End; 261 | } 262 | 263 | return State::Unknow; 264 | 265 | 266 | } 267 | 268 | 269 | 270 | #define S State 271 | #define OS(T) os==S::T 272 | #define TS(T) ts==S::T 273 | #define RESET(T) ts = S::T; 274 | #define UP(T) os = S::T; continue; 275 | #define BUF() curword.append(1,t); continue; 276 | #define RET(T) \ 277 | if(TS(Character)||TS(Number)||TS(Sign)\ 278 | ||TS(Operator)||TS(Char)||TS(String)||TS(QuoteOperator)\ 279 | ){ seek(-1); } \ 280 | return Tokenizer::Word{ Tokenizer::State::T, curword }; 281 | 282 | 283 | /** 284 | * 取得一个单词并移动游标 285 | */ 286 | Tokenizer::Word Tokenizer::gain() 287 | { 288 | 289 | char prev(' '); 290 | string curword(""); 291 | 292 | S os = S::Normal; 293 | 294 | while (1) { 295 | 296 | char t = getchar(); 297 | S ts = state( t ); 298 | 299 | // 文件读取结束 300 | if(TS(End)){ 301 | finish = true; // 结束标记 302 | if (curword!="") { // 返回最后一个token 303 | return Tokenizer::Word( os, curword ); 304 | } 305 | // 返回结束 306 | return Tokenizer::Word( 307 | Tokenizer::State::End, ""); 308 | } 309 | 310 | // 开始 311 | if(OS(Normal)){ 312 | 313 | // 无需缓存的 314 | if(TS(NewLine)||TS(Space)){ 315 | continue; 316 | } else if (TS(Annotation)) { // 注释 317 | char ct = getchar(); 318 | if (ct == '-') { 319 | UP(BlockAnnotation) 320 | } else if (ct == '\n') { 321 | UP(Normal) // 单行注释结束 322 | } else { 323 | UP(Annotation) 324 | } 325 | } else if (TS(Char) 326 | ||TS(String) 327 | ||TS(QuoteOperator)) { 328 | os = ts; // 切换状态 329 | continue; 330 | } 331 | // 需要缓存的 332 | os = ts; 333 | BUF() 334 | 335 | // 注释 336 | } else if (OS(Annotation)){ 337 | if(TS(NewLine)){ 338 | UP(Normal) // 单行注释结束,恢复状态 339 | } 340 | 341 | // 块注释 342 | } else if (OS(BlockAnnotation)){ 343 | char ct = getchar(); 344 | while(1){ 345 | if (prev == '-'&&ct == DEF_RESERVED_TOK_ANNOTA) { 346 | break; // 块注释结束 347 | } 348 | prev = ct; 349 | ct = getchar(); 350 | } 351 | UP(Normal) // 恢复状态 352 | 353 | 354 | // 名字 355 | } else if (OS(Character)){ 356 | if(TS(Character)||TS(Number)){ 357 | BUF() 358 | } 359 | RET(Character) 360 | 361 | // 数字 362 | } else if (OS(Number)){ 363 | if( TS(Number) || t=='.' ){ 364 | BUF() 365 | } 366 | RET(Number) 367 | 368 | // 符号 369 | } else if (OS(Sign)){ 370 | RET(Sign) 371 | 372 | // 操作符 373 | } else if (OS(Operator)){ 374 | if (TS(Operator)) { 375 | BUF() 376 | } else { // 结束 377 | RET(Operator) 378 | } 379 | 380 | // 引用操作符(将单词变为操作符) 381 | } else if (OS(QuoteOperator)){ 382 | if(t=='\\'){ // 转义 383 | curword.append(1, escape( getchar() ) ); 384 | continue; 385 | }else if( TS(NewLine) ){ 386 | FATAL("Quote Sign Missing End !") 387 | }else if(TS(QuoteOperator)){ 388 | RESET(Normal) // 复位 389 | RET(Operator) 390 | } 391 | BUF() 392 | 393 | // 单字符 394 | } else if (OS(Char)){ 395 | // 允许保存多个 char 兼容 UTF8 编码 396 | if (TS(Char)) { // 结束 397 | RESET(Normal) // 复位 398 | RET(Char) 399 | } 400 | if(t=='\\'){ // 转义 401 | t = escape( getchar() ); 402 | } 403 | BUF() 404 | 405 | // 双字符串 406 | } else if (OS(String)){ 407 | if(t=='\\'){ // 转义 408 | curword.append(1, escape( getchar() ) ); 409 | continue; 410 | }else if(TS(String)){ 411 | RESET(Normal) // 复位 412 | RET(String) 413 | } 414 | BUF() 415 | } 416 | } 417 | } 418 | 419 | 420 | #undef S 421 | #undef OS 422 | #undef TS 423 | #undef BUF 424 | #undef RET 425 | 426 | 427 | 428 | 429 | //判断是否为浮点数 430 | bool Tokenizer::isfloat(const string & str) 431 | { 432 | // npos 表示未找到 433 | if(str.find(".")!=string::npos){ 434 | return true; 435 | } 436 | return false; 437 | } 438 | 439 | 440 | 441 | 442 | 443 | 444 | } // --end-- namespace parse 445 | } // --end-- namespace def 446 | 447 | 448 | -------------------------------------------------------------------------------- /src/parse/tokenizer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | // 保留字符定义 9 | #define DEF_RESERVED_TOK_SIGN '`' 10 | #define DEF_RESERVED_TOK_STR '"' 11 | #define DEF_RESERVED_TOK_ANNOTA ';' // 注释 12 | 13 | 14 | namespace def { 15 | namespace parse { 16 | 17 | using namespace std; 18 | 19 | 20 | 21 | /** 22 | * 词法分析器 23 | */ 24 | class Tokenizer 25 | { 26 | 27 | public: 28 | // 单词状态 29 | enum class State { 30 | Normal, // 默认 31 | Character, // 英文字母(变量名和关键字) 32 | Number, // 数字 33 | Sign, // 标记 34 | Operator, // 操作符 35 | QuoteOperator, // 引用操作符 36 | Char, // 字符 ' 37 | String, // 字符串 " 38 | Annotation, // 单行注释 39 | BlockAnnotation, // 块注释 40 | Space, // 空格、tab等制表符 41 | NewLine, // 换行 42 | Unknow, // 不明字符 43 | End // 结束符 44 | }; 45 | // 单词 46 | struct Word { 47 | State state; 48 | string value; 49 | string str(); 50 | Word(State s=State::Unknow, const string &v="") 51 | : state(s) 52 | , value(v) 53 | {} 54 | bool inline operator==(const Word &w){ 55 | return state == w.state && value == w.value; 56 | }; 57 | }; // 缓存的 58 | 59 | 60 | public: 61 | 62 | string file; // 文件 63 | 64 | size_t cursor; // 当前游标 65 | size_t curline; // 当前行号 66 | 67 | private: 68 | 69 | ifstream fin; // 文件读入流 70 | 71 | void readpart(); // 读取文件的一部分 72 | string part; // 文件部分缓存 73 | size_t part_seek; // 读取游标 74 | bool finish; // 文件是否读取完毕 75 | 76 | inline void seek(int s = 1) { 77 | cursor += s; 78 | part_seek += s; 79 | } 80 | 81 | inline char escape(const char & t); // 获取转义 82 | inline char getchar(); // 读取一个字符,并移动游标 83 | 84 | public: 85 | 86 | Tokenizer(const string & filepath, bool checkfile=true); // 初始化 87 | ~Tokenizer() { 88 | } 89 | Word gain(); // 读取一个单词 90 | void jumpWhitespace(); // 跳过空白字符 91 | 92 | public: 93 | 94 | static State state(const char & t); // 获取单个字符的类型 95 | static bool isoperator(const string & tok); 96 | static bool isoperator(const char & t); 97 | static bool isfloat(const string &); // 判断是否为浮点数 98 | 99 | }; 100 | 101 | 102 | } // --end-- namespace parse 103 | } // --end-- namespace def 104 | -------------------------------------------------------------------------------- /src/sys/debug.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 调试类型 3 | */ 4 | 5 | #include "./debug.h" 6 | 7 | using namespace def::sys; 8 | 9 | std::string Debug::type_1 = ""; 10 | std::string Debug::type_2 = ""; 11 | std::string Debug::type_3 = ""; 12 | std::string Debug::type_4 = ""; 13 | std::string Debug::type_5 = ""; 14 | -------------------------------------------------------------------------------- /src/sys/debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /** 4 | * 调试打印类 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | 11 | #include "../global.h" 12 | 13 | 14 | /** 调试处理 **/ 15 | 16 | 17 | namespace def { 18 | namespace sys { 19 | 20 | using namespace std; 21 | 22 | 23 | 24 | 25 | class Debug 26 | { 27 | static std::string type_1; 28 | static std::string type_2; 29 | static std::string type_3; 30 | static std::string type_4; 31 | static std::string type_5; 32 | 33 | public: 34 | static bool CheckType(const std::string & t) 35 | { 36 | if (t == type_1 37 | || t == type_2 38 | || t == type_3 39 | || t == type_4 40 | || t == type_5) { 41 | return true; 42 | } 43 | return false; 44 | } 45 | static void SetType(const std::string & t, size_t n = 1) { 46 | if (1 == n) type_1 = t; 47 | if (2 == n) type_2 = t; 48 | if (3 == n) type_3 = t; 49 | if (4 == n) type_4 = t; 50 | if (5 == n) type_5 = t; 51 | } 52 | }; 53 | 54 | 55 | } 56 | } 57 | 58 | 59 | // 打印指定类型的错误 60 | #ifdef _DEBUG 61 | #define DEBUG_WITH(T,D) \ 62 | if(Debug::CheckType(T)){ \ 63 | D \ 64 | } 65 | #define DEBUG_COUT(T,D) \ 66 | if(Debug::CheckType(T)){ \ 67 | cout< 3 | * License: your favourite BSD-style license 4 | * 5 | * See OptionParser.h for help. 6 | */ 7 | 8 | #include "./argv.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #if defined(ENABLE_NLS) && ENABLE_NLS 16 | # include 17 | # define _(s) gettext(s) 18 | #else 19 | # define _(s) ((const char *) (s)) 20 | #endif 21 | 22 | using namespace std; 23 | using namespace def::util::argv; 24 | 25 | 26 | ////////// auxiliary (string) functions { ////////// 27 | class str_wrap { 28 | public: 29 | str_wrap(const string& l, const string& r) : lwrap(l), rwrap(r) {} 30 | str_wrap(const string& w) : lwrap(w), rwrap(w) {} 31 | string operator() (const string& s) { return lwrap + s + rwrap; } 32 | const string lwrap, rwrap; 33 | }; 34 | template 35 | static string str_join_trans(const string& sep, InputIterator begin, InputIterator end, UnarySign op) { 36 | string buf; 37 | for (InputIterator it = begin; it != end; ++it) { 38 | if (it != begin) 39 | buf += sep; 40 | buf += op(*it); 41 | } 42 | return buf; 43 | } 44 | template 45 | static string str_join(const string& sep, InputIterator begin, InputIterator end) { 46 | return str_join_trans(sep, begin, end, str_wrap("")); 47 | } 48 | static string& str_replace(string& s, const string& patt, const string& repl) { 49 | size_t pos = 0, n = patt.length(); 50 | while (true) { 51 | pos = s.find(patt, pos); 52 | if (pos == string::npos) 53 | break; 54 | s.replace(pos, n, repl); 55 | pos += repl.size(); 56 | } 57 | return s; 58 | } 59 | static string str_replace(const string& s, const string& patt, const string& repl) { 60 | string tmp = s; 61 | str_replace(tmp, patt, repl); 62 | return tmp; 63 | } 64 | static string str_format(const string& s, size_t pre, size_t len, bool indent_first = true) { 65 | stringstream ss; 66 | string p; 67 | if (indent_first) 68 | p = string(pre, ' '); 69 | 70 | size_t pos = 0, linestart = 0; 71 | size_t line = 0; 72 | while (true) { 73 | bool wrap = false; 74 | 75 | size_t new_pos = s.find_first_of(" \n\t", pos); 76 | if (new_pos == string::npos) 77 | break; 78 | if (s[new_pos] == '\n') { 79 | pos = new_pos + 1; 80 | wrap = true; 81 | } 82 | if (line == 1) 83 | p = string(pre, ' '); 84 | if (wrap || new_pos + pre > linestart + len) { 85 | ss << p << s.substr(linestart, pos - linestart - 1) << endl; 86 | linestart = pos; 87 | line++; 88 | } 89 | pos = new_pos + 1; 90 | } 91 | ss << p << s.substr(linestart) << endl; 92 | return ss.str(); 93 | } 94 | static string str_inc(const string& s) { 95 | stringstream ss; 96 | string v = (s != "") ? s : "0"; 97 | long i; 98 | istringstream(v) >> i; 99 | ss << i+1; 100 | return ss.str(); 101 | } 102 | static unsigned int cols() { 103 | unsigned int n = 80; 104 | #ifndef _WIN32 105 | const char *s = getenv("COLUMNS"); 106 | if (s) 107 | istringstream(s) >> n; 108 | #endif 109 | return n; 110 | } 111 | static string basename(const string& s) { 112 | string b = s; 113 | size_t i = b.find_last_not_of('/'); 114 | if (i == string::npos) { 115 | if (b[0] == '/') 116 | b.erase(1); 117 | return b; 118 | } 119 | b.erase(i+1, b.length()-i-1); 120 | i = b.find_last_of("/"); 121 | if (i != string::npos) 122 | b.erase(0, i+1); 123 | return b; 124 | } 125 | ////////// } auxiliary (string) functions ////////// 126 | 127 | 128 | ////////// class OptionParser { ////////// 129 | OptionParser::OptionParser() : 130 | _usage(_("%prog [options]")), 131 | _add_help_option(true), 132 | _add_version_option(true), 133 | _interspersed_args(true) {} 134 | 135 | Option& OptionParser::add_option(const string& opt) { 136 | const string tmp[1] = { opt }; 137 | return add_option(vector(&tmp[0], &tmp[1])); 138 | } 139 | Option& OptionParser::add_option(const string& opt1, const string& opt2) { 140 | const string tmp[2] = { opt1, opt2 }; 141 | return add_option(vector(&tmp[0], &tmp[2])); 142 | } 143 | Option& OptionParser::add_option(const string& opt1, const string& opt2, const string& opt3) { 144 | const string tmp[3] = { opt1, opt2, opt3 }; 145 | return add_option(vector(&tmp[0], &tmp[3])); 146 | } 147 | Option& OptionParser::add_option(const vector& v) { 148 | _opts.resize(_opts.size()+1); 149 | Option& option = _opts.back(); 150 | string dest_fallback; 151 | for (vector::const_iterator it = v.begin(); it != v.end(); ++it) { 152 | if (it->substr(0,2) == "--") { 153 | const string s = it->substr(2); 154 | if (option.dest() == "") 155 | option.dest(str_replace(s, "-", "_")); 156 | option._long_opts.insert(s); 157 | _optmap_l[s] = &option; 158 | } else { 159 | const string s = it->substr(1,1); 160 | if (dest_fallback == "") 161 | dest_fallback = s; 162 | option._short_opts.insert(s); 163 | _optmap_s[s] = &option; 164 | } 165 | } 166 | if (option.dest() == "") 167 | option.dest(dest_fallback); 168 | return option; 169 | } 170 | 171 | OptionParser& OptionParser::add_option_group(const OptionGroup& group) { 172 | for (list