From 6ca563dd2e6380e4e2062b9129f582a4910baf68 Mon Sep 17 00:00:00 2001 From: Dmitry Atamanov Date: Fri, 5 Jan 2018 19:36:56 +0300 Subject: [PATCH] Add a more number parsers to the scanf macro (#6985) --- lib/pure/parseutils.nim | 17 +++++++++++++++++ lib/pure/strscans.nim | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index a602b0e1be..57387e62ed 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -87,6 +87,23 @@ proc parseOct*(s: string, number: var int, start = 0): int {. inc(i) if foundDigit: result = i-start +proc parseBin*(s: string, number: var int, start = 0): int {. + rtl, extern: "npuParseBin", noSideEffect.} = + ## parses an binary number and stores its value in ``number``. Returns + ## the number of the parsed characters or 0 in case of an error. + var i = start + var foundDigit = false + if s[i] == '0' and (s[i+1] == 'b' or s[i+1] == 'B'): inc(i, 2) + while true: + case s[i] + of '_': discard + of '0'..'1': + number = number shl 1 or (ord(s[i]) - ord('0')) + foundDigit = true + else: break + inc(i) + if foundDigit: result = i-start + proc parseIdent*(s: string, ident: var string, start = 0): int = ## parses an identifier and stores it in ``ident``. Returns ## the number of the parsed characters or 0 in case of an error. diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index f33e7451fc..42bb281eb1 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -31,7 +31,10 @@ As can be seen from the examples, strings are matched verbatim except for substrings starting with ``$``. These constructions are available: ================= ======================================================== -``$i`` Matches an integer. This uses ``parseutils.parseInt``. +``$b`` Matches an decimal integer. This uses ``parseutils.parseBin``. +``$o`` Matches an octal integer. This uses ``parseutils.parseOct``. +``$i`` Matches an decimal integer. This uses ``parseutils.parseInt``. +``$h`` Matches an hex integer. This uses ``parseutils.parseHex``. ``$f`` Matches a floating pointer number. Uses ``parseFloat``. ``$w`` Matches an ASCII identifier: ``[A-Z-a-z_][A-Za-z_0-9]*``. ``$s`` Skips optional whitespace. @@ -335,11 +338,29 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b else: error("no string var given for $w") inc i + of 'b': + if i < results.len or getType(results[i]).typeKind != ntyInt: + matchBind "parseBin" + else: + error("no int var given for $b") + inc i + of 'o': + if i < results.len or getType(results[i]).typeKind != ntyInt: + matchBind "parseOct" + else: + error("no int var given for $o") + inc i of 'i': if i < results.len or getType(results[i]).typeKind != ntyInt: matchBind "parseInt" else: - error("no int var given for $d") + error("no int var given for $i") + inc i + of 'h': + if i < results.len or getType(results[i]).typeKind != ntyInt: + matchBind "parseHex" + else: + error("no int var given for $h") inc i of 'f': if i < results.len or getType(results[i]).typeKind != ntyFloat: @@ -645,6 +666,14 @@ when isMainModule: doAssert intval == 89 doAssert floatVal == 33.25 + var binval: int + var octval: int + var hexval: int + doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binval, octval, hexval) + doAssert binval == 0b0101 + doAssert octval == 0o1234 + doAssert hexval == 0xabcd + let xx = scanf("$abc", "$$$i", intval) doAssert xx == false