main.ha (4067B)
1 use bufio; 2 use fmt; 3 use hare::ast; 4 use hare::lex; 5 use hare::lex::{ltok}; 6 use hare::parse; 7 use hare::types; 8 use io; 9 use os; 10 use regex; 11 use strings; 12 13 let ioctlre: regex::regex = regex::regex { ... }; 14 let typedefre: regex::regex = regex::regex { ... }; 15 16 @init fn init() void = { 17 ioctlre = regex::compile(`@(_IO[RW]*)\((.*)\)`)!; 18 typedefre = regex::compile(`^(export )?type `)!; 19 }; 20 21 @fini fn fini() void = { 22 regex::finish(&ioctlre); 23 regex::finish(&typedefre); 24 }; 25 26 type dir = enum u32 { 27 IO = 0, 28 IOW = 1, 29 IOR = 2, 30 IOWR = IOW | IOR, 31 }; 32 33 type ioctl = (dir, rune, u32, const nullable *types::_type); 34 35 export fn main() void = { 36 // TODO: Configurable arch 37 const store = types::store(types::x86_64, null, null); 38 defer types::store_free(store); 39 40 for (true) { 41 const line = match (bufio::scanline(os::stdin)!) { 42 case io::EOF => 43 break; 44 case let line: []u8 => 45 yield strings::fromutf8(line)!; 46 }; 47 defer free(line); 48 49 if (regex::test(&typedefre, line)) { 50 bufio::unreadrune(os::stdin, '\n'); 51 bufio::unread(os::stdin, strings::toutf8(line)); 52 loadtype(store); 53 continue; 54 }; 55 56 let groups = regex::find(&ioctlre, line); 57 defer free(groups); 58 if (len(groups) == 0) { 59 fmt::println(line)!; 60 continue; 61 }; 62 63 const dir = switch (groups[1].content) { 64 case "_IO" => 65 yield dir::IO; 66 case "_IOR" => 67 yield dir::IOR; 68 case "_IOW" => 69 yield dir::IOW; 70 case "_IOWR" => 71 yield dir::IOWR; 72 case => 73 fmt::fatalf("Unknown ioctl direction {}", 74 groups[1].content); 75 }; 76 const ioctl = parseioctl(store, dir, groups[2].content); 77 78 const prefix = strings::sub(line, 0, groups[1].start - 1); 79 fmt::printfln("{}0x{:x};", prefix, ioctlno(&ioctl))!; 80 }; 81 }; 82 83 fn loadtype(store: *types::typestore) void = { 84 const tee = io::tee(os::stdin, os::stdout); 85 const lex = lex::init(&tee, "<ioctl>"); 86 defer lex::finish(&lex); 87 const decl = match (parse::decl(&lex)) { 88 case let err: parse::error => 89 fmt::fatal("Error parsing type declaration:", 90 parse::strerror(err)); 91 case let decl: ast::decl => 92 yield decl; 93 }; 94 95 const tdecl = decl.decl as []ast::decl_type; 96 if (len(tdecl) != 1) { 97 fmt::fatal("Multiple type declarations are unsupported"); 98 }; 99 const tdecl = tdecl[0]; 100 const of = types::lookup(store, &tdecl._type)!; 101 types::newalias(store, tdecl.ident, of); 102 }; 103 104 fn parseioctl(store: *types::typestore, d: dir, params: str) ioctl = { 105 const buf = bufio::fixed(strings::toutf8(params), io::mode::READ); 106 const lex = lex::init(&buf, "<ioctl>"); 107 108 const rn = expect(&lex, ltok::LIT_RUNE).1 as rune; 109 expect(&lex, ltok::COMMA); 110 const num = expect(&lex, ltok::LIT_ICONST).1 as u64; 111 112 if (d == dir::IO) { 113 return (d, rn, num: u32, null); 114 }; 115 116 expect(&lex, ltok::COMMA); 117 const ty = match (parse::_type(&lex)) { 118 case let ty: ast::_type => 119 yield ty; 120 case let err: parse::error => 121 fmt::fatal("Error:", parse::strerror(err)); 122 }; 123 124 const ty = match (types::lookup(store, &ty)) { 125 case let err: types::error => 126 fmt::fatal("Error:", types::strerror(err)); 127 case types::deferred => 128 fmt::fatal("Error: this tool does not support forward references"); 129 case let ty: const *types::_type => 130 yield ty; 131 }; 132 133 return (d, rn, num: u32, ty); 134 }; 135 136 fn expect(lex: *lex::lexer, want: ltok) lex::token = { 137 match (lex::lex(lex)) { 138 case let err: lex::error => 139 fmt::fatal("Error:", lex::strerror(err)); 140 case let tok: lex::token => 141 if (tok.0 != want) { 142 fmt::fatalf("Error: unexpected {}", lex::tokstr(tok)); 143 }; 144 return tok; 145 }; 146 }; 147 148 def IOC_NRBITS: u32 = 8; 149 def IOC_TYPEBITS: u32 = 8; 150 def IOC_SIZEBITS: u32 = 14; // XXX: Arch-specific 151 def IOC_DIRBITS: u32 = 2; // XXX: Arch-specific 152 153 def IOC_NRSHIFT: u32 = 0; 154 def IOC_TYPESHIFT: u32 = IOC_NRSHIFT + IOC_NRBITS; 155 def IOC_SIZESHIFT: u32 = IOC_TYPESHIFT + IOC_TYPEBITS; 156 def IOC_DIRSHIFT: u32 = IOC_SIZESHIFT + IOC_SIZEBITS; 157 158 fn ioctlno(io: *ioctl) u32 = { 159 const ty = match (io.3) { 160 case let ty: const *types::_type => 161 yield ty.sz; 162 case null => 163 yield 0z; 164 }; 165 return (io.0: u32 << IOC_DIRSHIFT) | 166 (io.1: u32 << IOC_TYPESHIFT) | 167 (io.2 << IOC_NRSHIFT) | 168 (ty: u32 << IOC_SIZESHIFT); 169 };