6
\$\begingroup\$

Let's assume we've got an imaginary assembler. The assembler supports numerical labels. An infinite loop example:

:1
    jmp 1

Your task is, to write a preprocessor for this assembler supporting named labels (instead of numerical ones; with up to 8 characters in length), so the label name is replaced to it's numerical value.

The assembler uses a dot (.) to express a character constant, for example:

mov dl, .A

Will store ASCII(65) - 'A', in the register dl. The assembler supports string constants in double quotes too:

:20
db "Hello, world!"

So, to sum things up, you need to be aware of character constants, and the fact that you can't perform any substitution inside quote-enclosed strings.

The label declaration character and reference character is up to your choice, but for the sake of completness I will use a $ to refer to a label, and @ to denote a label.

The label' number might be any natural number not equal to zero.

You may assume that assembly on the input is perfectly valid.

Let's look at a few examples:

@loop
    jmp $loop
:1
    jmp 1

jmp $skip
mov dl, .@
@skip
cmp dl, .$
jmp 1
mov dl, .@
:1
cmp dl, .$

@x
db "$a @b"
@a
    jmp $a
    @b
        jmp $b
:1
db "$a @b"
:2
    jmp 2
    :3
        jmp 3

This is a code golf, so the smallest answer wins. Standard rules and loopholes apply.

You can safetly assume that the user won't use numerical labels anymore, and the labels contain just A-Za-z letters.

Label declaration and reference character has to be different.

\$\endgroup\$
15
  • 2
    \$\begingroup\$ May the strings contain escaped double-quotes? (e.g. db "this is \"bad\"") \$\endgroup\$
    – Arnauld
    Commented Oct 9, 2019 at 16:20
  • 1
    \$\begingroup\$ (Or maybe more generally: may a genuine reference to a label be followed by anything other than an end of line?) \$\endgroup\$
    – Arnauld
    Commented Oct 9, 2019 at 17:11
  • 2
    \$\begingroup\$ Can anything be on the same line as a label? \$\endgroup\$ Commented Oct 9, 2019 at 23:07
  • 1
    \$\begingroup\$ Can newlines be inside quoted strings? \$\endgroup\$ Commented Oct 9, 2019 at 23:09
  • 1
    \$\begingroup\$ Can quote characters appear anywhere for any other purpose? \$\endgroup\$ Commented Oct 9, 2019 at 23:11

6 Answers 6

4
\$\begingroup\$

JavaScript (ES6), 96 bytes

Uses @label for a declaration and %label for a reference.

s=>s.replace(o=/^\s*@(.+)/gm,(_,s)=>':'+(o[s]=++n),n=0).replace(/".*?"|%(\w+)/g,(s,x)=>x?o[x]:s)

Try it online!

Commented

(alternate slash characters are used below to prevent the SE syntax highligter from going mad)

s =>                  // s = input string
  s.replace(          // 1st pass:
    o =               //   assign the regex object to o; we'll use it to store the labels
    ∕^\s*@(.+)∕gm,    //   look for [start] + [optional whitespace] + '@' + [label]
    (_, s) =>         //   replace with:
      ':' +           //     ':' + label ID
      (o[s] = ++n),   //     increment n and store the label in o
    n = 0             //   start with n = 0
  )                   // end of replace()
  .replace(           // 2nd pass:
    ∕".*?"|%(\w+)∕g,  //   look for either ".*?" (non-greedily) or %label
    (s, x) =>         //   replace with:
      x ? o[x]        //     o[label] if x is defined,
        : s           //     or the original string otherwise
  )                   // end of replace()
\$\endgroup\$
11
  • \$\begingroup\$ Nice! Would you like to add explaination? \$\endgroup\$ Commented Oct 9, 2019 at 19:14
  • \$\begingroup\$ I might have stolen your RegEx idea (embarrassed face). \$\endgroup\$
    – Night2
    Commented Oct 9, 2019 at 19:32
  • \$\begingroup\$ @Night2 My RegEx! Where's my RegEx?! :p \$\endgroup\$
    – Arnauld
    Commented Oct 9, 2019 at 19:41
  • \$\begingroup\$ /".*?"|%(\w+)/g, ported it to /".*?"|([@_]\w+)/ for my usage! \$\endgroup\$
    – Night2
    Commented Oct 9, 2019 at 19:43
  • \$\begingroup\$ Btw, invalidated: Doesn't work if there is whitespace at the start of the line. \$\endgroup\$ Commented Oct 10, 2019 at 16:07
2
\$\begingroup\$

PHP (7.4), 148 143 bytes

-5 bytes by stealing RegEx idea from @Arnauld.

<?=preg_replace_callback('/".*?"|([@_]\w+)/',fn($m)=>$m[1]?[':'][$m[0][0]>A].($_GET[$w=substr($m[0],1)]?:$_GET[$w]=++$_GET[0]):$m[0],$argv[1]);

Try it online!

Define labels with @ and refer to them with _.

Captures any @<label> or _<label> which aren't inside double quotes ("...") and replaces them with a unique number for every unique label, starting from 1. Also adds the : when replacing labels that have @ before them.

PHP's global variable $_GET is used to store and access last used id and unique ids for each label inside the arrow function. $_GET[0] holds last used id and $_GET[<label>] holds unique id for <label>.

\$\endgroup\$
1
  • \$\begingroup\$ Nice job! Quite small one. \$\endgroup\$ Commented Oct 9, 2019 at 18:55
2
\$\begingroup\$

Retina 0.8.2, 97 bytes

ms(1`^@
:@
+`(.*^:(1*).*?^)@
$1:1$2@
^:1*
:$.&
\$(.+?)$(?<=(?=.*^:(\d+)@\1$).+)
$2
^(:\d+).*?$
$1

Try it online! Uses the provided symbols (could save 1 byte by using a different symbol). Explanation:

ms(

Run everything in single multiline mode, where . matches newlines and ^ and $ match at the beginning and end of each line.

1`^@
:@

Prefix a : to the first label.

+`(.*^:(1*).*?^)@
$1:1$2@

Number the labels in unary.

^:1*
:$.&

Convert to decimal.

\$(.+?)$(?<=(?=.*^:(\d+)@\1$).+)
$2

Find all matching references and replace them with the number.

^(:\d+).*?$
$1

Delete the label names.

\$\endgroup\$
2
\$\begingroup\$

Python 3, 136 117 bytes

New and improved:

import re;d={}
f=lambda s:re.sub(r'(".+?")|([@$])(\w+)',lambda m:m[1]or d.setdefault(m[3],f":{m.end()}")[m[2]<='@':],s)

Try it online!

Uses the position of the match.end() as the integer for a label.

Old code

import re;d={};n=[*range(9999)]
f=lambda s:re.sub(r'(".+?")|([@$])(\w+)',lambda m:m[1]or d.setdefault(m[3],f":{n.pop()}")[m[2]<='@':],s)

Try it online!

Labels start at 9998 and count downward. Some numbers may be skipped. It will handle about 5000 labels, which should be enough for any sane asm program, but the number can be increased at 1 byte for each order of magnitude increase in range.

\$\endgroup\$
2
+100
\$\begingroup\$

Perl 5 (-p), 57 bytes

s/^\s*\K@(\w+)/":".($$1=++$,)/mge;s/".*?"\K|\$(\w+)/$$1/g

Try it online!

  • $, : global variable used as counter
  • s/^\s*\K@(\w+)/":".($$1=++$,)/mge : replaces labels "@[label]" by ":[counter]", increment counter and store counter in variable label name's variable
  • ".*?"\K| : regex part used to ignore strings between ""
  • s/...\$(\w+)/$$1/g : replaces references by variables value
\$\endgroup\$
3
  • \$\begingroup\$ Hell yeah, that's what I've been looking for. Classy, write-only Perl snippet. \$\endgroup\$ Commented Oct 17, 2019 at 14:19
  • \$\begingroup\$ See nothing about ignoring comments starting from semicolon. Or we don't need to preserve them? \$\endgroup\$
    – Qwertiy
    Commented Oct 17, 2019 at 14:28
  • \$\begingroup\$ indeed, it's similar lbl, instead of :. Just strings handling seems easier to maintain when matching first unwanted in alternation \$\endgroup\$ Commented Oct 17, 2019 at 19:38
0
\$\begingroup\$

Javascript ES6, 71 char

s=>s.replace(/(;.*|".*?")|:(:?)(\w+)/gm,(m,s,c,l)=>s||c+parseInt(l,36))

Conditions:

  • :: to introduce the label
  • : to use the label
  • Labels are case insensitive
  • ; starts comment till the end of the line
  • Quoted strings may not have " or linebreak inside
  • Charecter constants may not be followed by colon or letter like .:a or .::
  • Classic numeric labels starting from : are disallowed

Test:

console.log((

s=>s.replace(/(;.*|".*?")|:(:?)(\w+)/gm,(m,s,c,l)=>s||c+parseInt(l,36))

)(`
::loop
    jmp :loop

jmp :skip
mov dl, .:
::skip
cmp dl, .:

::x
db ":a ::b"
::a
    jmp :a
    ::b
        jmp :b
`))
.as-console-wrapper.as-console-wrapper{max-height:100vh}

\$\endgroup\$
5
  • \$\begingroup\$ Your assumptions on character constants make the submission invalid, but the example output is proving your submission is right. Please clarify your points. \$\endgroup\$ Commented Oct 17, 2019 at 14:34
  • \$\begingroup\$ @KrzysztofSzewczyk, character constant is . followed by any single char. .: is character constant (and it works fine). I require it not to be followed by letter or colon, so .:a and .:: should not be in the program. I don't see points why that makes submission invalid. \$\endgroup\$
    – Qwertiy
    Commented Oct 17, 2019 at 14:47
  • \$\begingroup\$ You should use conjunction instead of alternative. \$\endgroup\$ Commented Oct 17, 2019 at 15:38
  • \$\begingroup\$ @KrzysztofSzewczyk, don't understand you. \$\endgroup\$
    – Qwertiy
    Commented Oct 17, 2019 at 15:55
  • \$\begingroup\$ You should have used AND instead of OR for the sentence to be true. \$\endgroup\$ Commented Oct 17, 2019 at 16:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.