5
\$\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\$
  • 2
    \$\begingroup\$ May the strings contain escaped double-quotes? (e.g. db "this is \"bad\"") \$\endgroup\$ – Arnauld Oct 9 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 Oct 9 at 17:11
  • 2
    \$\begingroup\$ Can anything be on the same line as a label? \$\endgroup\$ – Jonathan Allan Oct 9 at 23:07
  • 1
    \$\begingroup\$ Can newlines be inside quoted strings? \$\endgroup\$ – Jonathan Allan Oct 9 at 23:09
  • 1
    \$\begingroup\$ Can quote characters appear anywhere for any other purpose? \$\endgroup\$ – Jonathan Allan Oct 9 at 23:11
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\$
  • \$\begingroup\$ Nice! Would you like to add explaination? \$\endgroup\$ – Krzysztof Szewczyk Oct 9 at 19:14
  • \$\begingroup\$ I might have stolen your RegEx idea (embarrassed face). \$\endgroup\$ – Night2 Oct 9 at 19:32
  • \$\begingroup\$ @Night2 My RegEx! Where's my RegEx?! :p \$\endgroup\$ – Arnauld Oct 9 at 19:41
  • \$\begingroup\$ /".*?"|%(\w+)/g, ported it to /".*?"|([@_]\w+)/ for my usage! \$\endgroup\$ – Night2 Oct 9 at 19:43
  • \$\begingroup\$ Btw, invalidated: Doesn't work if there is whitespace at the start of the line. \$\endgroup\$ – Krzysztof Szewczyk Oct 10 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\$
  • \$\begingroup\$ Nice job! Quite small one. \$\endgroup\$ – Krzysztof Szewczyk Oct 9 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\$
  • \$\begingroup\$ Hell yeah, that's what I've been looking for. Classy, write-only Perl snippet. \$\endgroup\$ – Krzysztof Szewczyk 2 days ago
  • \$\begingroup\$ See nothing about ignoring comments starting from semicolon. Or we don't need to preserve them? \$\endgroup\$ – Qwertiy 2 days ago
  • \$\begingroup\$ you don't need to preserve them. \$\endgroup\$ – Krzysztof Szewczyk 2 days ago
  • \$\begingroup\$ Also, I wrote a perl implementation too for this challenge, but it differs from the specification (as it's suited for my assembler), you might want to check it out if you want ;) github.com/KrzysztofSzewczyk/asmbf/blob/master/labels.pl \$\endgroup\$ – Krzysztof Szewczyk 2 days ago
  • \$\begingroup\$ indeed, it's similar lbl, instead of :. Just strings handling seems easier to maintain when matching first unwanted in alternation \$\endgroup\$ – Nahuel Fouilleul 2 days ago
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\$
  • \$\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\$ – Krzysztof Szewczyk 2 days ago
  • \$\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 2 days ago
  • \$\begingroup\$ You should use conjunction instead of alternative. \$\endgroup\$ – Krzysztof Szewczyk 2 days ago
  • \$\begingroup\$ @KrzysztofSzewczyk, don't understand you. \$\endgroup\$ – Qwertiy 2 days ago
  • \$\begingroup\$ You should have used AND instead of OR for the sentence to be true. \$\endgroup\$ – Krzysztof Szewczyk 2 days ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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