source: CLRX/CLRadeonExtender/trunk/amdasm/Assembler.cpp @ 2593

Last change on this file since 2593 was 2593, checked in by matszpk, 3 years ago

CLRadeonExtender: Asm: Move parsring of dimensions to AsmParseUtils?.

File size: 72.9 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2016 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <string>
22#include <cassert>
23#include <fstream>
24#include <vector>
25#include <stack>
26#include <unordered_set>
27#include <utility>
28#include <algorithm>
29#include <CLRX/utils/Utilities.h>
30#include <CLRX/utils/MemAccess.h>
31#include <CLRX/utils/GPUId.h>
32#include <CLRX/amdasm/Assembler.h>
33#include "AsmInternals.h"
34
35using namespace CLRX;
36
37bool AsmSection::addRegVar(const CString& name, const AsmRegVar& var)
38{ return regVars.insert(std::make_pair(name, var)).second; }
39
40bool AsmSection::getRegVar(const CString& name, const AsmRegVar*& regVar) const
41{ 
42    auto it = regVars.find(name);
43    if (it==regVars.end())
44        return false;
45    regVar = &it->second;
46    return true;
47}
48
49const cxbyte CLRX::tokenCharTable[96] =
50{
51    //' '   '!'   '"'   '#'   '$'   '%'   '&'   '''
52    0x00, 0x01, 0x02, 0x03, 0x90, 0x85, 0x06, 0x07,
53    //'('   ')'   '*'   '+'   ','   '-'   '.'   '/'
54    0x88, 0x88, 0x8a, 0x0b, 0x0c, 0x8d, 0x90, 0x0f,
55    //'0'   '1'   '2'   '3'   '4'   '5'   '6'   '7' 
56    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
57    //'8'   '9'   ':'   ';'   '<'   '='   '>'   '?'
58    0x90, 0x90, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
59    //'@'   'A'   'B'   'C'   'D'   'E'   'F'   'G'
60    0x26, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
61    //'H'   'I'   'J'   'K'   'L'   'M'   'N'   'O'
62    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
63    //'P'   'Q'   'R'   'S'   'T'   'U'   'V'   'W'
64    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
65    //'X'   'Y'   'Z'   '['   '\'   ']'   '^'   '_'
66    0x90, 0x90, 0x90, 0x91, 0x92, 0x93, 0x14, 0x90,
67    //'`'   'a'   'b'   'c'   'd'   'e'   'f'   'g'
68    0x16, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
69    //'h'   'i'   'j'   'k'   'l'   'm'   'n'   'o'
70    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
71    //'p'   'q'   'r'   's'   't'   'u'   'v'   'w'
72    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
73    //'x'   'y'   'z'   '{'   '|'   '}'   '~'   ''
74    0x90, 0x90, 0x90, 0x97, 0x18, 0x99, 0x1a, 0x1b
75};
76
77void CLRX::skipSpacesAndLabels(const char*& linePtr, const char* end)
78{
79    const char* stmtStart;
80    while (true)
81    {
82        skipSpacesToEnd(linePtr, end);
83        stmtStart = linePtr;
84        // skip labels and macro substitutions
85        while (linePtr!=end && (isAlnum(*linePtr) || *linePtr=='$' || *linePtr=='.' ||
86            *linePtr=='_' || *linePtr=='\\'))
87        {
88            if (*linePtr!='\\')
89                linePtr++;
90            else
91            {   /* handle \@ and \() for correct parsing */
92                linePtr++;
93                if (linePtr!=end)
94                {
95                    if (*linePtr=='@')
96                        linePtr++;
97                    if (*linePtr=='(')
98                    {
99                        linePtr++;
100                        if (linePtr!=end && *linePtr==')')
101                            linePtr++;
102                    }
103                }
104            }
105        }
106        skipSpacesToEnd(linePtr, end);
107        if (linePtr==end || *linePtr!=':')
108            break;
109        linePtr++; // skip ':'
110    }
111    linePtr = stmtStart;
112}
113
114bool AsmParseUtils::checkGarbagesAtEnd(Assembler& asmr, const char* linePtr)
115{
116    skipSpacesToEnd(linePtr, asmr.line + asmr.lineSize);
117    if (linePtr != asmr.line + asmr.lineSize)
118    {
119        asmr.printError(linePtr, "Garbages at end of line");
120        return false;
121    }
122    return true;
123}
124
125bool AsmParseUtils::getAbsoluteValueArg(Assembler& asmr, uint64_t& value,
126                      const char*& linePtr, bool requiredExpr)
127{
128    const char* end = asmr.line + asmr.lineSize;
129    skipSpacesToEnd(linePtr, end);
130    const char* exprPlace = linePtr;
131    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr, false, true));
132    if (expr == nullptr)
133        return false;
134    if (expr->isEmpty() && requiredExpr)
135    {
136        asmr.printError(exprPlace, "Expected expression");
137        return false;
138    }
139    if (expr->isEmpty()) // do not set if empty expression
140        return true;
141    cxuint sectionId; // for getting
142    if (!expr->evaluate(asmr, value, sectionId)) // failed evaluation!
143        return false;
144    else if (sectionId != ASMSECT_ABS)
145    {   // if not absolute value
146        asmr.printError(exprPlace, "Expression must be absolute!");
147        return false;
148    }
149    return true;
150}
151
152bool AsmParseUtils::getAnyValueArg(Assembler& asmr, uint64_t& value,
153                   cxuint& sectionId, const char*& linePtr)
154{
155    const char* end = asmr.line + asmr.lineSize;
156    skipSpacesToEnd(linePtr, end);
157    const char* exprPlace = linePtr;
158    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr, false, true));
159    if (expr == nullptr)
160        return false;
161    if (expr->isEmpty())
162    {
163        asmr.printError(exprPlace, "Expected expression");
164        return false;
165    }
166    if (!expr->evaluate(asmr, value, sectionId)) // failed evaluation!
167        return false;
168    return true;
169}
170
171bool AsmParseUtils::getJumpValueArg(Assembler& asmr, uint64_t& value,
172            std::unique_ptr<AsmExpression>& outTargetExpr, const char*& linePtr)
173{
174    const char* end = asmr.line + asmr.lineSize;
175    skipSpacesToEnd(linePtr, end);
176    const char* exprPlace = linePtr;
177    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr, false, false));
178    if (expr == nullptr)
179        return false;
180    if (expr->isEmpty())
181    {
182        asmr.printError(exprPlace, "Expected expression");
183        return false;
184    }
185    if (expr->getSymOccursNum()==0)
186    {
187        cxuint sectionId;
188        if (!expr->evaluate(asmr, value, sectionId)) // failed evaluation!
189            return false;
190        if (sectionId != asmr.currentSection)
191        {   // if jump outside current section (.text)
192            asmr.printError(exprPlace, "Jump over current section!");
193            return false;
194        }
195        return true;
196    }
197    else
198    {
199        outTargetExpr = std::move(expr);
200        return true;
201    }
202}
203
204bool AsmParseUtils::getNameArg(Assembler& asmr, CString& outStr, const char*& linePtr,
205            const char* objName, bool requiredArg, bool skipCommaAtError)
206{
207    const char* end = asmr.line + asmr.lineSize;
208    outStr.clear();
209    skipSpacesToEnd(linePtr, end);
210    if (linePtr == end)
211    {
212        if (!requiredArg)
213            return true; // succeed
214        asmr.printError(linePtr, (std::string("Expected ")+objName).c_str());
215        return false;
216    }
217    const char* nameStr = linePtr;
218    if (isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.')
219    {
220        linePtr++;
221        while (linePtr != end && (isAlnum(*linePtr) ||
222            *linePtr == '_' || *linePtr == '.')) linePtr++;
223    }
224    else
225    {
226        if (!requiredArg)
227            return true; // succeed
228        asmr.printError(linePtr, (std::string("Some garbages at ")+objName+
229                        " place").c_str());
230        if (!skipCommaAtError)
231            while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
232        else
233            while (linePtr != end && !isSpace(*linePtr)) linePtr++;
234        return false;
235    }
236    outStr.assign(nameStr, linePtr);
237    return true;
238}
239
240bool AsmParseUtils::getNameArg(Assembler& asmr, size_t maxOutStrSize, char* outStr,
241               const char*& linePtr, const char* objName, bool requiredArg,
242               bool ignoreLongerName, bool skipCommaAtError)
243{
244    const char* end = asmr.line + asmr.lineSize;
245    skipSpacesToEnd(linePtr, end);
246    if (linePtr == end)
247    {
248        if (!requiredArg)
249        {
250            outStr[0] = 0;
251            return true; // succeed
252        }
253        asmr.printError(linePtr, (std::string("Expected ")+objName).c_str());
254        return false;
255    }
256    const char* nameStr = linePtr;
257    if (isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.')
258    {
259        linePtr++;
260        while (linePtr != end && (isAlnum(*linePtr) ||
261            *linePtr == '_' || *linePtr == '.')) linePtr++;
262    }
263    else
264    {
265        if (!requiredArg)
266        {
267            outStr[0] = 0;
268            return true; // succeed
269        }
270        asmr.printError(linePtr, (std::string("Some garbages at ")+objName+
271                " place").c_str());
272       
273        if (!skipCommaAtError)
274            while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
275        else
276            while (linePtr != end && !isSpace(*linePtr)) linePtr++;
277        return false;
278    }
279    if (maxOutStrSize-1 < size_t(linePtr-nameStr))
280    {
281        if (ignoreLongerName)
282        {   // return empty string
283            outStr[0] = 0; // null-char
284            return true;
285        }
286        asmr.printError(linePtr, (std::string(objName)+" is too long").c_str());
287        return false;
288    }
289    const size_t outStrSize = std::min(maxOutStrSize-1, size_t(linePtr-nameStr));
290    std::copy(nameStr, nameStr+outStrSize, outStr);
291    outStr[outStrSize] = 0; // null-char
292    return true;
293}
294
295bool AsmParseUtils::skipComma(Assembler& asmr, bool& haveComma, const char*& linePtr)
296{
297    const char* end = asmr.line + asmr.lineSize;
298    skipSpacesToEnd(linePtr, end);
299    if (linePtr == end)
300    {
301        haveComma = false;
302        return true;
303    }
304    if (*linePtr != ',')
305    {
306        asmr.printError(linePtr, "Expected ',' before argument");
307        return false;
308    }
309    linePtr++;
310    haveComma = true;
311    return true;
312}
313
314bool AsmParseUtils::skipRequiredComma(Assembler& asmr, const char*& linePtr)
315{
316    const char* end = asmr.line + asmr.lineSize;
317    skipSpacesToEnd(linePtr, end);
318    if (linePtr == end || *linePtr != ',')
319    {
320        asmr.printError(linePtr, "Expected ',' before argument");
321        return false;
322    }
323    linePtr++;
324    return true;
325}
326
327bool AsmParseUtils::skipCommaForMultipleArgs(Assembler& asmr, const char*& linePtr)
328{
329    const char* end = asmr.line + asmr.lineSize;
330    skipSpacesToEnd(linePtr, end); // spaces before ','
331    if (linePtr == end)
332        return false;
333    if (*linePtr != ',')
334    {
335        asmr.printError(linePtr, "Expected ',' before next value");
336        linePtr++;
337        return false;
338    }
339    else
340        skipCharAndSpacesToEnd(linePtr, end);
341    return true;
342}
343
344bool AsmParseUtils::getEnumeration(Assembler& asmr, const char*& linePtr,
345              const char* objName, size_t tableSize,
346              const std::pair<const char*, cxuint>* table, cxuint& value,
347              const char* prefix)
348{
349    const char* end = asmr.line + asmr.lineSize;
350    char name[72];
351    skipSpacesToEnd(linePtr, end);
352    const char* namePlace = linePtr;
353    if (getNameArg(asmr, 72, name, linePtr, objName))
354    {
355        toLowerString(name);
356        size_t namePos = 0;
357        if (prefix!=nullptr)
358        {
359            size_t psize = ::strlen(prefix);
360            namePos = ::memcmp(name, prefix, psize)==0 ? psize : 0;
361        }
362        cxuint index = binaryMapFind(table, table + tableSize, name+namePos, CStringLess())
363                        - table;
364        if (index != tableSize)
365            value = table[index].second;
366        else // end of this map
367        {
368            asmr.printError(namePlace, (std::string("Unknown ")+objName).c_str());
369            return false;
370        }
371        return true;
372    }
373    return false;
374}
375
376bool AsmParseUtils::parseDimensions(Assembler& asmr, const char*& linePtr, cxuint& dimMask)
377{
378    const char* end = asmr.line + asmr.lineSize;
379    skipSpacesToEnd(linePtr, end);
380    const char* dimPlace = linePtr;
381    char buf[10];
382    dimMask = 0;
383    if (getNameArg(asmr, 10, buf, linePtr, "dimension set", false))
384    {
385        toLowerString(buf);
386        for (cxuint i = 0; buf[i]!=0; i++)
387            if (buf[i]=='x')
388                dimMask |= 1;
389            else if (buf[i]=='y')
390                dimMask |= 2;
391            else if (buf[i]=='z')
392                dimMask |= 4;
393            else
394            {
395                asmr.printError(dimPlace, "Unknown dimension type");
396                return false;
397            }
398    }
399    else // error
400        return false;
401    return true;
402}
403
404ISAAssembler::ISAAssembler(Assembler& _assembler) : assembler(_assembler)
405{ }
406
407ISAAssembler::~ISAAssembler()
408{ }
409
410void AsmSymbol::removeOccurrenceInExpr(AsmExpression* expr, size_t argIndex,
411               size_t opIndex)
412{
413    auto it = std::remove(occurrencesInExprs.begin(), occurrencesInExprs.end(),
414            AsmExprSymbolOccurrence{expr, argIndex, opIndex});
415    occurrencesInExprs.resize(it-occurrencesInExprs.begin());
416}
417
418void AsmSymbol::clearOccurrencesInExpr()
419{
420    /* iteration with index and occurrencesInExprs.size() is required for checking size
421     * after expression deletion that removes occurrences in exprs in this symbol */
422    for (size_t i = 0; i < occurrencesInExprs.size(); i++)
423    {
424        auto& occur = occurrencesInExprs[i];
425        if (occur.expression!=nullptr && !occur.expression->unrefSymOccursNum())
426        {   // delete and move back iteration by number of removed elements
427            const size_t oldSize = occurrencesInExprs.size();
428            AsmExpression* occurExpr = occur.expression;
429            occur.expression = nullptr;
430            delete occurExpr;
431            // subtract number of removed elements from counter
432            i -= oldSize-occurrencesInExprs.size();
433        }
434    }
435    occurrencesInExprs.clear();
436}
437
438void AsmSymbol::undefine()
439{
440    hasValue = false;
441    base = false;
442    delete expression;
443    expression = nullptr;
444    onceDefined = false;
445}
446
447/*
448 * Assembler
449 */
450
451Assembler::Assembler(const CString& filename, std::istream& input, Flags _flags,
452        BinaryFormat _format, GPUDeviceType _deviceType, std::ostream& msgStream,
453        std::ostream& _printStream)
454        : format(_format),
455          deviceType(_deviceType),
456          driverVersion(0),
457          _64bit(false),
458          isaAssembler(nullptr),
459          symbolMap({std::make_pair(".", AsmSymbol(0, uint64_t(0)))}),
460          flags(_flags), 
461          lineSize(0), line(nullptr),
462          endOfAssembly(false),
463          messageStream(msgStream),
464          printStream(_printStream),
465          // value reference and section reference from first symbol: '.'
466          currentSection(symbolMap.begin()->second.sectionId),
467          currentOutPos(symbolMap.begin()->second.value)
468{
469    filenameIndex = 0;
470    alternateMacro = (flags & ASM_ALTMACRO)!=0;
471    buggyFPLit = (flags & ASM_BUGGYFPLIT)!=0;
472    localCount = macroCount = inclusionLevel = 0;
473    macroSubstLevel = repetitionLevel = 0;
474    lineAlreadyRead = false;
475    good = true;
476    resolvingRelocs = false;
477    formatHandler = nullptr;
478    input.exceptions(std::ios::badbit);
479    std::unique_ptr<AsmInputFilter> thatInputFilter(
480                    new AsmStreamInputFilter(input, filename));
481    asmInputFilters.push(thatInputFilter.get());
482    currentInputFilter = thatInputFilter.release();
483}
484
485Assembler::Assembler(const Array<CString>& _filenames, Flags _flags,
486        BinaryFormat _format, GPUDeviceType _deviceType, std::ostream& msgStream,
487        std::ostream& _printStream)
488        : format(_format),
489          deviceType(_deviceType),
490          driverVersion(0),
491          _64bit(false),
492          isaAssembler(nullptr),
493          symbolMap({std::make_pair(".", AsmSymbol(0, uint64_t(0)))}),
494          flags(_flags), 
495          lineSize(0), line(nullptr),
496          endOfAssembly(false),
497          messageStream(msgStream),
498          printStream(_printStream),
499          // value reference and section reference from first symbol: '.'
500          currentSection(symbolMap.begin()->second.sectionId),
501          currentOutPos(symbolMap.begin()->second.value)
502{
503    filenameIndex = 0;
504    filenames = _filenames;
505    alternateMacro = (flags & ASM_ALTMACRO)!=0;
506    buggyFPLit = (flags & ASM_BUGGYFPLIT)!=0;
507    localCount = macroCount = inclusionLevel = 0;
508    macroSubstLevel = repetitionLevel = 0;
509    lineAlreadyRead = false;
510    good = true;
511    resolvingRelocs = false;
512    formatHandler = nullptr;
513    std::unique_ptr<AsmInputFilter> thatInputFilter(
514                new AsmStreamInputFilter(filenames[filenameIndex++]));
515    asmInputFilters.push(thatInputFilter.get());
516    currentInputFilter = thatInputFilter.release();
517}
518
519Assembler::~Assembler()
520{
521    delete formatHandler;
522    if (isaAssembler != nullptr)
523        delete isaAssembler;
524    while (!asmInputFilters.empty())
525    {
526        delete asmInputFilters.top();
527        asmInputFilters.pop();
528    }
529   
530    /// remove expressions before symbol map deletion
531    for (auto& entry: symbolMap)
532        entry.second.clearOccurrencesInExpr();
533    /// remove expressions before symbol snapshots
534    for (auto& entry: symbolSnapshots)
535        entry->second.clearOccurrencesInExpr();
536   
537    for (auto& entry: symbolSnapshots)
538        delete entry;
539}
540
541bool Assembler::parseString(std::string& strarray, const char*& linePtr)
542{
543    const char* end = line+lineSize;
544    const char* startPlace = linePtr;
545    skipSpacesToEnd(linePtr, end);
546    strarray.clear();
547    if (linePtr == end || *linePtr != '"')
548    {
549        while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
550        printError(startPlace, "Expected string");
551        return false;
552    }
553    linePtr++;
554   
555    while (linePtr != end && *linePtr != '"')
556    {
557        if (*linePtr == '\\')
558        {   // escape
559            linePtr++;
560            uint16_t value;
561            if (linePtr == end)
562            {
563                printError(startPlace, "Unterminated character of string");
564                return false;
565            }
566            if (*linePtr == 'x')
567            {   // hex
568                const char* charPlace = linePtr-1;
569                linePtr++;
570                if (linePtr == end)
571                {
572                    printError(startPlace, "Unterminated character of string");
573                    return false;
574                }
575                value = 0;
576                if (isXDigit(*linePtr))
577                    for (; linePtr != end; linePtr++)
578                    {
579                        cxuint digit;
580                        if (*linePtr >= '0' && *linePtr <= '9')
581                            digit = *linePtr-'0';
582                        else if (*linePtr >= 'a' && *linePtr <= 'f')
583                            digit = *linePtr-'a'+10;
584                        else if (*linePtr >= 'A' && *linePtr <= 'F')
585                            digit = *linePtr-'A'+10;
586                        else
587                            break;
588                        value = (value<<4) + digit;
589                    }
590                else
591                {
592                    printError(charPlace, "Expected hexadecimal character code");
593                    return false;
594                }
595                value &= 0xff;
596            }
597            else if (isODigit(*linePtr))
598            {   // octal
599                value = 0;
600                const char* charPlace = linePtr-1;
601                for (cxuint i = 0; linePtr != end && i < 3; i++, linePtr++)
602                {
603                    if (!isODigit(*linePtr))
604                        break;
605                    value = (value<<3) + uint64_t(*linePtr-'0');
606                    if (value > 255)
607                    {
608                        printError(charPlace, "Octal code out of range");
609                        return false;
610                    }
611                }
612            }
613            else
614            {   // normal escapes
615                const char c = *linePtr++;
616                switch (c)
617                {
618                    case 'a':
619                        value = '\a';
620                        break;
621                    case 'b':
622                        value = '\b';
623                        break;
624                    case 'r':
625                        value = '\r';
626                        break;
627                    case 'n':
628                        value = '\n';
629                        break;
630                    case 'f':
631                        value = '\f';
632                        break;
633                    case 'v':
634                        value = '\v';
635                        break;
636                    case 't':
637                        value = '\t';
638                        break;
639                    case '\\':
640                        value = '\\';
641                        break;
642                    case '\'':
643                        value = '\'';
644                        break;
645                    case '\"':
646                        value = '\"';
647                        break;
648                    default:
649                        value = c;
650                }
651            }
652            strarray.push_back(value);
653        }
654        else // regular character
655            strarray.push_back(*linePtr++);
656    }
657    if (linePtr == end)
658    {
659        printError(startPlace, "Unterminated string");
660        return false;
661    }
662    linePtr++;
663    return true;
664}
665
666bool Assembler::parseLiteral(uint64_t& value, const char*& linePtr)
667{
668    const char* startPlace = linePtr;
669    const char* end = line+lineSize;
670    if (linePtr != end && *linePtr == '\'')
671    {
672        linePtr++;
673        if (linePtr == end)
674        {
675            printError(startPlace, "Unterminated character literal");
676            return false;
677        }
678        if (*linePtr == '\'')
679        {
680            printError(startPlace, "Empty character literal");
681            return false;
682        }
683       
684        if (*linePtr != '\\')
685        {
686            value = *linePtr++;
687            if (linePtr == end || *linePtr != '\'')
688            {
689                printError(startPlace, "Missing ''' at end of literal");
690                return false;
691            }
692            linePtr++;
693            return true;
694        }
695        else // escapes
696        {
697            linePtr++;
698            if (linePtr == end)
699            {
700                printError(startPlace, "Unterminated character literal");
701                return false;
702            }
703            if (*linePtr == 'x')
704            {   // hex
705                linePtr++;
706                if (linePtr == end)
707                {
708                    printError(startPlace, "Unterminated character literal");
709                    return false;
710                }
711                value = 0;
712                if (isXDigit(*linePtr))
713                    for (; linePtr != end; linePtr++)
714                    {
715                        cxuint digit;
716                        if (*linePtr >= '0' && *linePtr <= '9')
717                            digit = *linePtr-'0';
718                        else if (*linePtr >= 'a' && *linePtr <= 'f')
719                            digit = *linePtr-'a'+10;
720                        else if (*linePtr >= 'A' && *linePtr <= 'F')
721                            digit = *linePtr-'A'+10;
722                        else
723                            break; // end of literal
724                        value = (value<<4) + digit;
725                    }
726                else
727                {
728                    printError(startPlace, "Expected hexadecimal character code");
729                    return false;
730                }
731                value &= 0xff;
732            }
733            else if (isODigit(*linePtr))
734            {   // octal
735                value = 0;
736                for (cxuint i = 0; linePtr != end && i < 3 && *linePtr != '\'';
737                     i++, linePtr++)
738                {
739                    if (!isODigit(*linePtr))
740                    {
741                        printError(startPlace, "Expected octal character code");
742                        return false;
743                    }
744                    value = (value<<3) + uint64_t(*linePtr-'0');
745                    if (value > 255)
746                    {
747                        printError(startPlace, "Octal code out of range");
748                        return false;
749                    }
750                }
751            }
752            else
753            {   // normal escapes
754                const char c = *linePtr++;
755                switch (c)
756                {
757                    case 'a':
758                        value = '\a';
759                        break;
760                    case 'b':
761                        value = '\b';
762                        break;
763                    case 'r':
764                        value = '\r';
765                        break;
766                    case 'n':
767                        value = '\n';
768                        break;
769                    case 'f':
770                        value = '\f';
771                        break;
772                    case 'v':
773                        value = '\v';
774                        break;
775                    case 't':
776                        value = '\t';
777                        break;
778                    case '\\':
779                        value = '\\';
780                        break;
781                    case '\'':
782                        value = '\'';
783                        break;
784                    case '\"':
785                        value = '\"';
786                        break;
787                    default:
788                        value = c;
789                }
790            }
791            if (linePtr == end || *linePtr != '\'')
792            {
793                printError(startPlace, "Missing ''' at end of literal");
794                return false;
795            }
796            linePtr++;
797            return true;
798        }
799    }
800    try
801    { value = cstrtovCStyle<uint64_t>(startPlace, line+lineSize, linePtr); }
802    catch(const ParseException& ex)
803    {
804        printError(startPlace, ex.what());
805        return false;
806    }
807    return true;
808}
809
810Assembler::ParseState Assembler::parseSymbol(const char*& linePtr,
811                AsmSymbolEntry*& entry, bool localLabel, bool dontCreateSymbol)
812{
813    const char* startPlace = linePtr;
814    const CString symName = extractSymName(linePtr, line+lineSize, localLabel);
815    if (symName.empty())
816    {   // this is not symbol or a missing symbol
817        while (linePtr != line+lineSize && !isSpace(*linePtr) && *linePtr != ',')
818            linePtr++;
819        entry = nullptr;
820        return Assembler::ParseState::MISSING;
821    }
822    if (symName == ".") // any usage of '.' causes format initialization
823        initializeOutputFormat();
824   
825    Assembler::ParseState state = Assembler::ParseState::PARSED;
826    bool symHasValue;
827    if (!dontCreateSymbol)
828    {   // create symbol if not found
829        std::pair<AsmSymbolMap::iterator, bool> res =
830                symbolMap.insert(std::make_pair(symName, AsmSymbol()));
831        entry = &*res.first;
832        symHasValue = res.first->second.hasValue;
833    }
834    else
835    {   // only find symbol and set isDefined and entry
836        AsmSymbolMap::iterator it = symbolMap.find(symName);
837        entry = (it != symbolMap.end()) ? &*it : nullptr;
838        symHasValue = (it != symbolMap.end() && it->second.hasValue);
839    }
840    if (isDigit(symName.front()) && symName[linePtr-startPlace-1] == 'b' && !symHasValue)
841    {   // failed at finding
842        std::string error = "Undefined previous local label '";
843        error.append(symName.begin(), linePtr-startPlace);
844        error += "'";
845        printError(linePtr, error.c_str());
846        state = Assembler::ParseState::FAILED;
847    }
848   
849    return state;
850}
851
852bool Assembler::parseMacroArgValue(const char*& string, std::string& outStr)
853{
854    const char* end = line+lineSize;
855    bool firstNonSpace = false;
856    cxbyte prevTok = 0;
857    cxuint backslash = 0;
858   
859    if ((alternateMacro && string != end && *string=='%') ||
860        (!alternateMacro && string+2 <= end && *string=='\\' && string[1]=='%'))
861    {   // alternate syntax, parse expression evaluation
862        const char* exprPlace = string + ((alternateMacro) ? 1 : 2);
863        uint64_t value;
864        if (AsmParseUtils::getAbsoluteValueArg(*this, value, exprPlace, true))
865        {
866            char buf[32];
867            itocstrCStyle<int64_t>(value, buf, 32);
868            string = exprPlace;
869            outStr = buf;
870            return true;
871        }
872        else
873        {   /* if error */
874            string = exprPlace;
875            return false;
876        }
877    }
878   
879    if (alternateMacro && string != end && (*string=='<' || *string=='\'' || *string=='"'))
880    {   /* alternate string quoting */
881        const char termChar = (*string=='<') ? '>' : *string;
882        string++;
883        bool escape = false;
884        while (string != end && (*string != termChar || escape))
885        {
886            if (!escape && *string=='!')
887            {   /* skip this escaping */
888                escape = true;
889                string++;
890            }
891            else
892            {   /* put character */
893                escape = false;
894                outStr.push_back(*string++);
895            }
896        }
897        if (string == end)
898        {   /* if unterminated string */
899            printError(string, "Unterminated quoted string");
900            return false;
901        }
902        string++;
903        return true;
904    }
905    else if (string != end && *string=='"')
906    {
907        string++;
908        while (string != end && (*string != '\"' || (backslash&1)!=0))
909        {
910            if (*string=='\\')
911                backslash++;
912            else
913                backslash = 0;
914            outStr.push_back(*string++);
915        }
916        if (string == end)
917        {
918            printError(string, "Unterminated quoted string");
919            return false;
920        }
921        string++;
922        return true;
923    }
924   
925    for (; string != end && *string != ','; string++)
926    {
927        if(*string == '"') // quoted
928            return true; // next argument
929        if (!isSpace(*string))
930        {
931            const cxbyte thisTok = (cxbyte(*string) >= 0x20 && cxbyte(*string) < 0x80) ?
932                tokenCharTable[*string-0x20] : 0;
933            bool prevTokCont = (prevTok&0x80)!=0;
934            bool thisTokCont = (thisTok&0x80)!=0;
935            if (firstNonSpace && ((prevTok!=thisTok && !(thisTokCont ^ prevTokCont)) || 
936                (prevTok==thisTok && (thisTokCont&prevTokCont))))
937                break;  // end of token list for macro arg
938            outStr.push_back(*string);
939            firstNonSpace = false;
940            prevTok = thisTok;
941        }
942        else
943        {
944            firstNonSpace = true;
945            continue; // space
946        }
947    }
948    return true;
949}
950
951bool Assembler::setSymbol(AsmSymbolEntry& symEntry, uint64_t value, cxuint sectionId)
952{
953    symEntry.second.value = value;
954    symEntry.second.expression = nullptr;
955    symEntry.second.sectionId = sectionId;
956    symEntry.second.hasValue = isResolvableSection(sectionId) || resolvingRelocs;
957    symEntry.second.regRange = false;
958    symEntry.second.base = false;
959    if (!symEntry.second.hasValue) // if not resolved we just return
960        return true; // no error
961    bool good = true;
962   
963    // resolve value of pending symbols
964    std::stack<std::pair<AsmSymbolEntry*, size_t> > symbolStack;
965    symbolStack.push(std::make_pair(&symEntry, 0));
966    symEntry.second.resolving = true;
967   
968    while (!symbolStack.empty())
969    {
970        std::pair<AsmSymbolEntry*, size_t>& entry = symbolStack.top();
971        if (entry.second < entry.first->second.occurrencesInExprs.size())
972        {
973            AsmExprSymbolOccurrence& occurrence =
974                    entry.first->second.occurrencesInExprs[entry.second];
975            AsmExpression* expr = occurrence.expression;
976            expr->substituteOccurrence(occurrence, entry.first->second.value,
977                       (!isAbsoluteSymbol(entry.first->second)) ?
978                       entry.first->second.sectionId : ASMSECT_ABS);
979            entry.second++;
980           
981            if (!expr->unrefSymOccursNum())
982            {   // expresion has been fully resolved
983                uint64_t value;
984                cxuint sectionId;
985                const AsmExprTarget& target = expr->getTarget();
986                if (!resolvingRelocs || target.type==ASMXTGT_SYMBOL)
987                {   // standard mode
988                    if (!expr->evaluate(*this, value, sectionId))
989                    {   // if failed
990                        delete occurrence.expression; // delete expression
991                        good = false;
992                        continue;
993                    }
994                }
995                // resolve expression if at resolving symbol phase
996                else if (formatHandler==nullptr ||
997                        !formatHandler->resolveRelocation(expr, value, sectionId))
998                {   // if failed
999                    delete occurrence.expression; // delete expression
1000                    good = false;
1001                    continue;
1002                }
1003               
1004                switch(target.type)
1005                {
1006                    case ASMXTGT_SYMBOL:
1007                    {    // resolve symbol
1008                        AsmSymbolEntry& curSymEntry = *target.symbol;
1009                        if (!curSymEntry.second.resolving &&
1010                            curSymEntry.second.expression==expr)
1011                        {
1012                            curSymEntry.second.value = value;
1013                            curSymEntry.second.sectionId = sectionId;
1014                            curSymEntry.second.hasValue =
1015                                isResolvableSection(sectionId) || resolvingRelocs;
1016                            symbolStack.push(std::make_pair(&curSymEntry, 0));
1017                            if (!curSymEntry.second.hasValue)
1018                                continue;
1019                            curSymEntry.second.resolving = true;
1020                        }
1021                        // otherwise we ignore circular dependencies
1022                        break;
1023                    }
1024                    case ASMXTGT_DATA8:
1025                        if (sectionId != ASMSECT_ABS)
1026                        {
1027                            printError(expr->getSourcePos(),
1028                                   "Relative value is illegal in data expressions");
1029                            good = false;
1030                        }
1031                        else
1032                        {
1033                            printWarningForRange(8, value, expr->getSourcePos());
1034                            sections[target.sectionId].content[target.offset] =
1035                                    cxbyte(value);
1036                        }
1037                        break;
1038                    case ASMXTGT_DATA16:
1039                        if (sectionId != ASMSECT_ABS)
1040                        {
1041                            printError(expr->getSourcePos(),
1042                                   "Relative value is illegal in data expressions");
1043                            good = false;
1044                        }
1045                        else
1046                        {
1047                            printWarningForRange(16, value, expr->getSourcePos());
1048                            SULEV(*reinterpret_cast<uint16_t*>(sections[target.sectionId]
1049                                    .content.data() + target.offset), uint16_t(value));
1050                        }
1051                        break;
1052                    case ASMXTGT_DATA32:
1053                        if (sectionId != ASMSECT_ABS)
1054                        {
1055                            printError(expr->getSourcePos(),
1056                                   "Relative value is illegal in data expressions");
1057                            good = false;
1058                        }
1059                        else
1060                        {
1061                            printWarningForRange(32, value, expr->getSourcePos());
1062                            SULEV(*reinterpret_cast<uint32_t*>(sections[target.sectionId]
1063                                    .content.data() + target.offset), uint32_t(value));
1064                        }
1065                        break;
1066                    case ASMXTGT_DATA64:
1067                        if (sectionId != ASMSECT_ABS)
1068                        {
1069                            printError(expr->getSourcePos(),
1070                                   "Relative value is illegal in data expressions");
1071                            good = false;
1072                        }
1073                        else
1074                            SULEV(*reinterpret_cast<uint64_t*>(sections[target.sectionId]
1075                                    .content.data() + target.offset), uint64_t(value));
1076                        break;
1077                    default: // ISA assembler resolves this dependency
1078                        if (!isaAssembler->resolveCode(expr->getSourcePos(),
1079                                target.sectionId, sections[target.sectionId].content.data(),
1080                                target.offset, target.type, sectionId, value))
1081                            good = false;
1082                        break;
1083                }
1084                delete occurrence.expression; // delete expression
1085            }
1086            else // otherwise we only clear occurrence expression
1087                occurrence.expression = nullptr; // clear expression
1088        }
1089        else // pop
1090        {
1091            entry.first->second.resolving = false;
1092            entry.first->second.occurrencesInExprs.clear();
1093            if (entry.first->second.snapshot && --(entry.first->second.refCount) == 0)
1094            {
1095                symbolSnapshots.erase(entry.first);
1096                delete entry.first; // delete this symbol snapshot
1097            }
1098            symbolStack.pop();
1099        }
1100    }
1101    return good;
1102}
1103
1104bool Assembler::assignSymbol(const CString& symbolName, const char* symbolPlace,
1105             const char* linePtr, bool reassign, bool baseExpr)
1106{
1107    skipSpacesToEnd(linePtr, line+lineSize);
1108    if (linePtr!=line+lineSize && *linePtr=='%')
1109    {
1110        if (symbolName == ".")
1111        {
1112            printError(symbolPlace, "Symbol '.' requires a resolved expression");
1113            return false;
1114        }
1115        initializeOutputFormat();
1116        ++linePtr;
1117        cxuint regStart, regEnd;
1118        const AsmRegVar* regVar;
1119        if (!isaAssembler->parseRegisterRange(linePtr, regStart, regEnd, regVar))
1120            return false;
1121        skipSpacesToEnd(linePtr, line+lineSize);
1122        if (linePtr != line+lineSize)
1123        {
1124            printError(linePtr, "Garbages at end of expression");
1125            return false;
1126        }
1127       
1128        std::pair<AsmSymbolMap::iterator, bool> res =
1129                symbolMap.insert(std::make_pair(symbolName, AsmSymbol()));
1130        if (!res.second && ((res.first->second.onceDefined || !reassign) &&
1131            res.first->second.isDefined()))
1132        {   // found and can be only once defined
1133            printError(symbolPlace, (std::string("Symbol '") + symbolName.c_str() +
1134                        "' is already defined").c_str());
1135            return false;
1136        }
1137        if (!res.first->second.occurrencesInExprs.empty())
1138        {   // found in expressions
1139            std::vector<std::pair<const AsmExpression*, size_t> > exprs;
1140            size_t i = 0;
1141            for (AsmExprSymbolOccurrence occur: res.first->second.occurrencesInExprs)
1142                exprs.push_back(std::make_pair(occur.expression, i++));
1143            // remove duplicates
1144            std::sort(exprs.begin(), exprs.end(),
1145                      [](const std::pair<const AsmExpression*, size_t>& a,
1146                         const std::pair<const AsmExpression*, size_t>& b)
1147                    {
1148                        if (a.first==b.first)
1149                            return a.second<b.second;
1150                        return a.first<b.first;
1151                    });
1152            exprs.resize(std::unique(exprs.begin(), exprs.end(),
1153                       [](const std::pair<const AsmExpression*, size_t>& a,
1154                         const std::pair<const AsmExpression*, size_t>& b)
1155                       { return a.first==b.first; })-exprs.begin());
1156           
1157            std::sort(exprs.begin(), exprs.end(),
1158                      [](const std::pair<const AsmExpression*, size_t>& a,
1159                         const std::pair<const AsmExpression*, size_t>& b)
1160                    { return a.second<b.second; });
1161            // print errors
1162            for (std::pair<const AsmExpression*, size_t> elem: exprs)
1163                printError(elem.first->getSourcePos(), "Expression have register symbol");
1164           
1165            printError(symbolPlace, (std::string("Register range symbol '") +
1166                            symbolName.c_str() + "' was used in some expressions").c_str());
1167            return false;
1168        }
1169        // setup symbol entry (required)
1170        AsmSymbolEntry& symEntry = *res.first;
1171        symEntry.second.expression = nullptr;
1172        symEntry.second.onceDefined = !reassign;
1173        symEntry.second.base = false;
1174        symEntry.second.sectionId = ASMSECT_ABS;
1175        symEntry.second.regRange = symEntry.second.hasValue = true;
1176        symEntry.second.value = (regStart | (uint64_t(regEnd)<<32));
1177        return true;
1178    }
1179   
1180    const char* exprPlace = linePtr;
1181    // make base expr if baseExpr=true and symbolName is not output counter
1182    bool makeBaseExpr = (baseExpr && symbolName != ".");
1183    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(*this, linePtr, makeBaseExpr));
1184    if (!expr) // no expression, errors
1185        return false;
1186   
1187    if (linePtr != line+lineSize)
1188    {
1189        printError(linePtr, "Garbages at end of expression");
1190        return false;
1191    }
1192    if (expr->isEmpty()) // empty expression, we treat as error
1193    {
1194        printError(exprPlace, "Expected assignment expression");
1195        return false;
1196    }
1197   
1198    if (symbolName == ".")
1199    {   // assigning '.'
1200        uint64_t value;
1201        cxuint sectionId;
1202        if (!expr->evaluate(*this, value, sectionId))
1203            return false;
1204        if (expr->getSymOccursNum()==0)
1205            return assignOutputCounter(symbolPlace, value, sectionId);
1206        else
1207        {
1208            printError(symbolPlace, "Symbol '.' requires a resolved expression");
1209            return false;
1210        }
1211    }
1212   
1213    std::pair<AsmSymbolMap::iterator, bool> res =
1214            symbolMap.insert(std::make_pair(symbolName, AsmSymbol()));
1215    if (!res.second && ((res.first->second.onceDefined || !reassign) &&
1216        res.first->second.isDefined()))
1217    {   // found and can be only once defined
1218        printError(symbolPlace, (std::string("Symbol '") + symbolName.c_str() +
1219                    "' is already defined").c_str());
1220        return false;
1221    }
1222    AsmSymbolEntry& symEntry = *res.first;
1223   
1224    if (expr->getSymOccursNum()==0)
1225    {   // can evalute, assign now
1226        uint64_t value;
1227        cxuint sectionId;
1228        if (!expr->evaluate(*this, value, sectionId))
1229            return false;
1230       
1231        setSymbol(symEntry, value, sectionId);
1232        symEntry.second.onceDefined = !reassign;
1233    }
1234    else // set expression
1235    {
1236        expr->setTarget(AsmExprTarget::symbolTarget(&symEntry));
1237        symEntry.second.expression = expr.release();
1238        symEntry.second.regRange = symEntry.second.hasValue = false;
1239        symEntry.second.onceDefined = !reassign;
1240        symEntry.second.base = baseExpr;
1241        if (baseExpr && !symEntry.second.occurrencesInExprs.empty())
1242        {   /* make snapshot now resolving dependencies */
1243            AsmSymbolEntry* tempSymEntry;
1244            if (!AsmExpression::makeSymbolSnapshot(*this, symEntry, tempSymEntry,
1245                    &symEntry.second.occurrencesInExprs[0].expression->getSourcePos()))
1246                return false;
1247            tempSymEntry->second.occurrencesInExprs =
1248                        symEntry.second.occurrencesInExprs;
1249            // clear occurrences after copy
1250            symEntry.second.occurrencesInExprs.clear();
1251            if (tempSymEntry->second.hasValue) // set symbol chain
1252                setSymbol(*tempSymEntry, tempSymEntry->second.value,
1253                          tempSymEntry->second.sectionId);
1254        }
1255    }
1256    return true;
1257}
1258
1259bool Assembler::assignOutputCounter(const char* symbolPlace, uint64_t value,
1260            cxuint sectionId, cxbyte fillValue)
1261{
1262    initializeOutputFormat();
1263    if (currentSection != sectionId && sectionId != ASMSECT_ABS)
1264    {
1265        printError(symbolPlace, "Illegal section change for symbol '.'");
1266        return false;
1267    }
1268    if (currentSection != ASMSECT_ABS && int64_t(currentOutPos) > int64_t(value))
1269    {   /* check attempt to move backwards only for section that is not absolute */
1270        printError(symbolPlace, "Attempt to move backwards");
1271        return false;
1272    }
1273    if (!isAddressableSection())
1274    {
1275        printError(symbolPlace,
1276                   "Change output counter inside non-addressable section is illegal");
1277        return false;
1278    }
1279    if (currentSection==ASMSECT_ABS && fillValue!=0)
1280        printWarning(symbolPlace, "Fill value is ignored inside absolute section");
1281    if (value-currentOutPos!=0)
1282        reserveData(value-currentOutPos, fillValue);
1283    currentOutPos = value;
1284    return true;
1285}
1286
1287bool Assembler::skipSymbol(const char*& linePtr)
1288{
1289    const char* end = line+lineSize;
1290    skipSpacesToEnd(linePtr, end);
1291    const char* start = linePtr;
1292    if (linePtr != end)
1293    {   /* skip only symbol name */
1294        if(isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.' || *linePtr == '$')
1295            for (linePtr++; linePtr != end && (isAlnum(*linePtr) || *linePtr == '_' ||
1296                 *linePtr == '.' || *linePtr == '$') ; linePtr++);
1297    }
1298    if (start == linePtr)
1299    {   // this is not symbol name
1300        while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
1301        printError(start, "Expected symbol name");
1302        return false;
1303    }
1304    return true;
1305}
1306
1307bool Assembler::isAbsoluteSymbol(const AsmSymbol& symbol) const
1308{
1309    if (symbol.sectionId == ASMSECT_ABS)
1310        return true;
1311    // otherwise check section
1312    if (sections.empty())
1313        return false; // fallback
1314    const AsmSection& section = sections[symbol.sectionId];
1315    return (section.flags&ASMSECT_ABS_ADDRESSABLE) != 0;
1316}
1317
1318void Assembler::printWarning(const AsmSourcePos& pos, const char* message)
1319{
1320    if ((flags & ASM_WARNINGS) == 0)
1321        return; // do nothing
1322    pos.print(messageStream);
1323    messageStream.write(": Warning: ", 11);
1324    messageStream.write(message, ::strlen(message));
1325    messageStream.put('\n');
1326}
1327
1328void Assembler::printError(const AsmSourcePos& pos, const char* message)
1329{
1330    good = false;
1331    pos.print(messageStream);
1332    messageStream.write(": Error: ", 9);
1333    messageStream.write(message, ::strlen(message));
1334    messageStream.put('\n');
1335}
1336
1337void Assembler::printWarningForRange(cxuint bits, uint64_t value, const AsmSourcePos& pos,
1338        cxbyte signess)
1339{
1340    if (bits < 64)
1341    {   /* signess - WS_BOTH - check value range as signed value
1342         * WS_UNSIGNED - check value as unsigned value */
1343        if (signess == WS_BOTH &&
1344            !(int64_t(value) >= (1LL<<bits) || int64_t(value) < -(1LL<<(bits-1))))
1345            return;
1346        if (signess == WS_UNSIGNED && (value < (1ULL<<bits)))
1347            return;
1348        std::string warning = "Value ";
1349        char buf[32];
1350        itocstrCStyle(value, buf, 32, 16);
1351        warning += buf;
1352        warning += " truncated to ";
1353        itocstrCStyle(value&((1ULL<<bits)-1), buf, 32, 16);
1354        warning += buf;
1355        printWarning(pos, warning.c_str());
1356    }
1357}
1358
1359bool Assembler::checkReservedName(const CString& name)
1360{
1361    return false;
1362}
1363
1364void Assembler::addIncludeDir(const CString& includeDir)
1365{
1366    includeDirs.push_back(includeDir);
1367}
1368
1369void Assembler::addInitialDefSym(const CString& symName, uint64_t value)
1370{
1371    defSyms.push_back({symName, value});
1372}
1373
1374bool Assembler::pushClause(const char* string, AsmClauseType clauseType, bool satisfied,
1375               bool& included)
1376{
1377    if (clauseType == AsmClauseType::MACRO || clauseType == AsmClauseType::IF ||
1378        clauseType == AsmClauseType::REPEAT)
1379    {   // add new clause
1380        clauses.push({ clauseType, getSourcePos(string), satisfied, { } });
1381        included = satisfied;
1382        return true;
1383    }
1384    if (clauses.empty())
1385    {   // no clauses
1386        if (clauseType == AsmClauseType::ELSEIF)
1387            printError(string, "No '.if' before '.elseif");
1388        else // else
1389            printError(string, "No '.if' before '.else'");
1390        return false;
1391    }
1392    AsmClause& clause = clauses.top();
1393    switch(clause.type)
1394    {
1395        case AsmClauseType::ELSE:
1396            if (clauseType == AsmClauseType::ELSEIF)
1397                printError(string, "'.elseif' after '.else'");
1398            else // else
1399                printError(string, "Duplicate of '.else'");
1400            printError(clause.sourcePos, "here is previous '.else'"); 
1401            printError(clause.prevIfPos, "here is begin of conditional clause"); 
1402            return false;
1403        case AsmClauseType::MACRO:
1404            if (clauseType == AsmClauseType::ELSEIF)
1405                printError(string,
1406                       "No '.if' before '.elseif' inside macro");
1407            else // else
1408                printError(string,
1409                       "No '.if' before '.else' inside macro");
1410            return false;
1411        case AsmClauseType::REPEAT:
1412            if (clauseType == AsmClauseType::ELSEIF)
1413                printError(string,
1414                       "No '.if' before '.elseif' inside repetition");
1415            else // else
1416                printError(string,
1417                       "No '.if' before '.else' inside repetition");
1418            return false;
1419        default:
1420            break;
1421    }
1422    included = satisfied && !clause.condSatisfied;
1423    clause.condSatisfied |= included;
1424    if (clause.type == AsmClauseType::IF)
1425        clause.prevIfPos = clause.sourcePos;
1426    clause.type = clauseType;
1427    clause.sourcePos = getSourcePos(string);
1428    return true;
1429}
1430
1431bool Assembler::popClause(const char* string, AsmClauseType clauseType)
1432{
1433    if (clauses.empty())
1434    {   // no clauses
1435        if (clauseType == AsmClauseType::IF)
1436            printError(string, "No conditional before '.endif'");
1437        else if (clauseType == AsmClauseType::MACRO) // macro
1438            printError(string, "No '.macro' before '.endm'");
1439        else if (clauseType == AsmClauseType::REPEAT) // repeat
1440            printError(string, "No '.rept' before '.endr'");
1441        return false;
1442    }
1443    AsmClause& clause = clauses.top();
1444    switch(clause.type)
1445    {
1446        case AsmClauseType::IF:
1447        case AsmClauseType::ELSE:
1448        case AsmClauseType::ELSEIF:
1449            if (clauseType == AsmClauseType::MACRO)
1450            {
1451                printError(string, "Ending macro across conditionals");
1452                return false;
1453            }
1454            else if (clauseType == AsmClauseType::REPEAT)
1455            {
1456                printError(string, "Ending repetition across conditionals");
1457                return false;
1458            }
1459            break;
1460        case AsmClauseType::MACRO:
1461            if (clauseType == AsmClauseType::REPEAT)
1462            {
1463                printError(string, "Ending repetition across macro");
1464                return false;
1465            }
1466            if (clauseType == AsmClauseType::IF)
1467            {
1468                printError(string, "Ending conditional across macro");
1469                return false;
1470            }
1471            break;
1472        case AsmClauseType::REPEAT:
1473            if (clauseType == AsmClauseType::MACRO)
1474            {
1475                printError(string, "Ending macro across repetition");
1476                return false;
1477            }
1478            if (clauseType == AsmClauseType::IF)
1479            {
1480                printError(string, "Ending conditional across repetition");
1481                return false;
1482            }
1483            break;
1484        default:
1485            break;
1486    }
1487    clauses.pop();
1488    return true;
1489}
1490
1491Assembler::ParseState Assembler::makeMacroSubstitution(const char* linePtr)
1492{
1493    const char* end = line+lineSize;
1494    const char* macroStartPlace = linePtr;
1495   
1496    CString macroName = extractSymName(linePtr, end, false);
1497    if (macroName.empty())
1498        return ParseState::MISSING;
1499    toLowerString(macroName);
1500    MacroMap::const_iterator it = macroMap.find(macroName);
1501    if (it == macroMap.end())
1502        return ParseState::MISSING; // macro not found
1503   
1504    /* parse arguments */
1505    RefPtr<const AsmMacro> macro = it->second;
1506    const size_t macroArgsNum = macro->getArgsNum();
1507    bool good = true;
1508    AsmMacroInputFilter::MacroArgMap argMap(macroArgsNum);
1509    for (size_t i = 0; i < macroArgsNum; i++) // set name of args
1510        argMap[i].first = macro->getArg(i).name;
1511   
1512    for (size_t i = 0; i < macroArgsNum; i++)
1513    {
1514        const AsmMacroArg& arg = macro->getArg(i);
1515       
1516        skipSpacesToEnd(linePtr, end);
1517        if (linePtr!=end && *linePtr==',' && i!=0)
1518            skipCharAndSpacesToEnd(linePtr, end);
1519       
1520        std::string macroArg;
1521        const char* argPlace = linePtr;
1522        if (!arg.vararg)
1523        {
1524            if (!parseMacroArgValue(linePtr, macroArg))
1525            {
1526                good = false;
1527                continue;
1528            }
1529        }
1530        else
1531        {   /* parse variadic arguments, they requires ',' separator */
1532            bool argGood = true;
1533            while (linePtr != end)
1534            {
1535                if (!parseMacroArgValue(linePtr, macroArg))
1536                {
1537                    argGood = good = false;
1538                    break;
1539                }
1540                skipSpacesToEnd(linePtr, end);
1541                if (linePtr!=end)
1542                {
1543                    if(*linePtr==',')
1544                    {
1545                        skipCharAndSpacesToEnd(linePtr, end);
1546                        macroArg.push_back(',');
1547                    }
1548                    else
1549                    {
1550                        printError(linePtr, "Garbages at end of line");
1551                        argGood = good = false;
1552                        break;
1553                    }
1554                }
1555            }
1556            if (!argGood) // not so good
1557                continue;
1558        }
1559        argMap[i].second = macroArg;
1560        if (arg.required && argMap[i].second.empty())
1561        {   // error, value required
1562            printError(argPlace, (std::string("Value required for macro argument '") +
1563                    arg.name.c_str() + '\'').c_str());
1564            good = false;
1565        }
1566        else if (argMap[i].second.empty())
1567            argMap[i].second = arg.defaultValue;
1568    }
1569   
1570    skipSpacesToEnd(linePtr, end);
1571    if (!good)
1572        return ParseState::FAILED;
1573    if (linePtr != end)
1574    {
1575        printError(linePtr, "Garbages at end of line");
1576        return ParseState::FAILED;
1577    }
1578   
1579    if (macroSubstLevel == 1000)
1580    {
1581        printError(macroStartPlace, "Macro substitution level is greater than 1000");
1582        return ParseState::FAILED;
1583    }
1584    // sort argmap before using
1585    mapSort(argMap.begin(), argMap.end());
1586    // create macro input filter and push to stack
1587    std::unique_ptr<AsmInputFilter> macroFilter(new AsmMacroInputFilter(macro,
1588            getSourcePos(macroStartPlace), std::move(argMap), macroCount++,
1589            alternateMacro));
1590    asmInputFilters.push(macroFilter.release());
1591    currentInputFilter = asmInputFilters.top();
1592    macroSubstLevel++;
1593    return ParseState::PARSED;
1594}
1595
1596bool Assembler::includeFile(const char* pseudoOpPlace, const std::string& filename)
1597{
1598    if (inclusionLevel == 500)
1599    {
1600        printError(pseudoOpPlace, "Inclusion level is greater than 500");
1601        return false;
1602    }
1603    std::unique_ptr<AsmInputFilter> newInputFilter(new AsmStreamInputFilter(
1604                getSourcePos(pseudoOpPlace), filename));
1605    asmInputFilters.push(newInputFilter.release());
1606    currentInputFilter = asmInputFilters.top();
1607    inclusionLevel++;
1608    return true;
1609}
1610
1611bool Assembler::readLine()
1612{
1613    line = currentInputFilter->readLine(*this, lineSize);
1614    while (line == nullptr)
1615    {   // no line
1616        if (asmInputFilters.size() > 1)
1617        {   /* decrease some level of a nesting */
1618            if (currentInputFilter->getType() == AsmInputFilterType::MACROSUBST)
1619                macroSubstLevel--;
1620            else if (currentInputFilter->getType() == AsmInputFilterType::STREAM)
1621                inclusionLevel--;
1622            else if (currentInputFilter->getType() == AsmInputFilterType::REPEAT)
1623                repetitionLevel--;
1624            delete asmInputFilters.top();
1625            asmInputFilters.pop();
1626        }
1627        else if (filenameIndex<filenames.size())
1628        {   /* handling input assembler that have many files */
1629            do { // delete previous filter
1630                delete asmInputFilters.top();
1631                asmInputFilters.pop();
1632                /// create new input filter
1633                std::unique_ptr<AsmStreamInputFilter> thatFilter(
1634                    new AsmStreamInputFilter(filenames[filenameIndex++]));
1635                asmInputFilters.push(thatFilter.get());
1636                currentInputFilter = thatFilter.release();
1637                line = currentInputFilter->readLine(*this, lineSize);
1638            } while (line==nullptr && filenameIndex<filenames.size());
1639           
1640            return (line!=nullptr);
1641        }
1642        else
1643            return false;
1644        currentInputFilter = asmInputFilters.top();
1645        line = currentInputFilter->readLine(*this, lineSize);
1646    }
1647    return true;
1648}
1649
1650cxbyte* Assembler::reserveData(size_t size, cxbyte fillValue)
1651{
1652    if (currentSection != ASMSECT_ABS)
1653    {
1654        size_t oldOutPos = currentOutPos;
1655        AsmSection& section = sections[currentSection];
1656        if ((section.flags & ASMSECT_WRITEABLE) == 0) // non writeable
1657        {
1658            currentOutPos += size;
1659            section.size += size;
1660            return nullptr;
1661        }
1662        else
1663        {
1664            section.content.insert(section.content.end(), size, fillValue);
1665            currentOutPos += size;
1666            return section.content.data() + oldOutPos;
1667        }
1668    }
1669    else
1670    {
1671        currentOutPos += size;
1672        return nullptr;
1673    }
1674}
1675
1676
1677void Assembler::goToMain(const char* pseudoOpPlace)
1678{
1679    try
1680    { formatHandler->setCurrentKernel(ASMKERN_GLOBAL); }
1681    catch(const AsmFormatException& ex) // if error
1682    { printError(pseudoOpPlace, ex.what()); }
1683   
1684    currentOutPos = sections[currentSection].getSize();
1685}
1686
1687void Assembler::goToKernel(const char* pseudoOpPlace, const char* kernelName)
1688{
1689    auto kmit = kernelMap.find(kernelName);
1690    if (kmit == kernelMap.end())
1691    {   // not found, add new kernel
1692        cxuint kernelId;
1693        try
1694        { kernelId = formatHandler->addKernel(kernelName); }
1695        catch(const AsmFormatException& ex)
1696        {   // error!
1697            printError(pseudoOpPlace, ex.what());
1698            return;
1699        }
1700        // add new kernel entries and section entry
1701        auto it = kernelMap.insert(std::make_pair(kernelName, kernelId)).first;
1702        kernels.push_back({ it->first.c_str(),  getSourcePos(pseudoOpPlace) });
1703        auto info = formatHandler->getSectionInfo(currentSection);
1704        sections.push_back({ info.name, currentKernel, info.type, info.flags, 0 });
1705        currentOutPos = 0;
1706    }
1707    else
1708    {   // found
1709        try
1710        { formatHandler->setCurrentKernel(kmit->second); }
1711        catch(const AsmFormatException& ex) // if error
1712        {
1713            printError(pseudoOpPlace, ex.what());
1714            return;
1715        }
1716       
1717        currentOutPos = sections[currentSection].getSize();
1718    }
1719}
1720
1721void Assembler::goToSection(const char* pseudoOpPlace, const char* sectionName,
1722                            uint64_t align)
1723{
1724    const cxuint sectionId = formatHandler->getSectionId(sectionName);
1725    if (sectionId == ASMSECT_NONE)
1726    {   // try to add new section
1727        cxuint sectionId;
1728        try
1729        { sectionId = formatHandler->addSection(sectionName, currentKernel); }
1730        catch(const AsmFormatException& ex)
1731        {   // error!
1732            printError(pseudoOpPlace, ex.what());
1733            return;
1734        }
1735        auto info = formatHandler->getSectionInfo(sectionId);
1736        sections.push_back({ info.name, currentKernel, info.type, info.flags, align });
1737        currentOutPos = 0;
1738    }
1739    else // if section exists
1740    {   // found, try to set
1741        try
1742        { formatHandler->setCurrentSection(sectionId); }
1743        catch(const AsmFormatException& ex) // if error
1744        {
1745            printError(pseudoOpPlace, ex.what());
1746            return;
1747        }
1748       
1749        if (align!=0)
1750            printWarning(pseudoOpPlace, "Section alignment was ignored");
1751        currentOutPos = sections[currentSection].getSize();
1752    }
1753}
1754
1755void Assembler::goToSection(const char* pseudoOpPlace, const char* sectionName,
1756        AsmSectionType type, Flags flags, uint64_t align)
1757{
1758    const cxuint sectionId = formatHandler->getSectionId(sectionName);
1759    if (sectionId == ASMSECT_NONE)
1760    {   // try to add new section
1761        cxuint sectionId;
1762        try
1763        { sectionId = formatHandler->addSection(sectionName, currentKernel); }
1764        catch(const AsmFormatException& ex)
1765        {   // error!
1766            printError(pseudoOpPlace, ex.what());
1767            return;
1768        }
1769        auto info = formatHandler->getSectionInfo(sectionId);
1770        if (info.type == AsmSectionType::EXTRA_SECTION)
1771        {
1772            info.type = type;
1773            info.flags |= flags;
1774        }
1775        else
1776            printWarning(pseudoOpPlace,
1777                     "Section type and flags was ignored for builtin section");
1778        sections.push_back({ info.name, currentKernel, info.type, info.flags, align });
1779        currentOutPos = 0;
1780    }
1781    else // if section exists
1782    {   // found, try to set
1783        try
1784        { formatHandler->setCurrentSection(sectionId); }
1785        catch(const AsmFormatException& ex) // if error
1786        {
1787            printError(pseudoOpPlace, ex.what());
1788            return;
1789        }
1790       
1791        printWarning(pseudoOpPlace, "Section type, flags and alignment was ignored");
1792        currentOutPos = sections[currentSection].getSize();
1793    }
1794}
1795
1796void Assembler::goToSection(const char* pseudoOpPlace, cxuint sectionId, uint64_t align)
1797{
1798    try
1799    { formatHandler->setCurrentSection(sectionId); }
1800    catch(const AsmFormatException& ex) // if error
1801    { printError(pseudoOpPlace, ex.what()); }
1802    if (sectionId >= sections.size())
1803    {
1804        auto info = formatHandler->getSectionInfo(sectionId);
1805        sections.push_back({ info.name, currentKernel, info.type, info.flags, align });
1806    }
1807    else if (align!=0)
1808        printWarning(pseudoOpPlace, "Section alignment was ignored");
1809   
1810    currentOutPos = sections[currentSection].getSize();
1811}
1812
1813void Assembler::initializeOutputFormat()
1814{
1815    if (formatHandler!=nullptr)
1816        return;
1817    switch(format)
1818    {
1819        case BinaryFormat::AMD:
1820            formatHandler = new AsmAmdHandler(*this);
1821            break;
1822        case BinaryFormat::AMDCL2:
1823            formatHandler = new AsmAmdCL2Handler(*this);
1824            break;
1825        case BinaryFormat::GALLIUM:
1826            formatHandler = new AsmGalliumHandler(*this);
1827            break;
1828        case BinaryFormat::ROCM:
1829            formatHandler = new AsmROCmHandler(*this);
1830            break;
1831        default:
1832            formatHandler = new AsmRawCodeHandler(*this);
1833            break;
1834    }
1835    isaAssembler = new GCNAssembler(*this);
1836    // add first section
1837    auto info = formatHandler->getSectionInfo(currentSection);
1838    sections.push_back({ info.name, currentKernel, info.type, info.flags, 0 });
1839    currentOutPos = 0;
1840}
1841
1842bool Assembler::assemble()
1843{
1844    resolvingRelocs = false;
1845   
1846    for (const DefSym& defSym: defSyms)
1847        if (defSym.first!=".")
1848            symbolMap[defSym.first] = AsmSymbol(ASMSECT_ABS, defSym.second);
1849        else if ((flags & ASM_WARNINGS) != 0)// ignore for '.'
1850            messageStream << "<command-line>: Warning: Definition for symbol '.' "
1851                    "was ignored" << std::endl;
1852   
1853    good = true;
1854    while (!endOfAssembly)
1855    {
1856        if (!lineAlreadyRead)
1857        {   // read line
1858            if (!readLine())
1859                break;
1860        }
1861        else
1862        {   // already line is read
1863            lineAlreadyRead = false;
1864            if (line == nullptr)
1865                break; // end of stream
1866        }
1867       
1868        const char* linePtr = line; // string points to place of line
1869        const char* end = line+lineSize;
1870        skipSpacesToEnd(linePtr, end);
1871        if (linePtr == end)
1872            continue; // only empty line
1873       
1874        // statement start (except labels). in this time can point to labels
1875        const char* stmtPlace = linePtr;
1876        CString firstName = extractLabelName(linePtr, end);
1877       
1878        skipSpacesToEnd(linePtr, end);
1879       
1880        bool doNextLine = false;
1881        while (!firstName.empty() && linePtr != end && *linePtr == ':')
1882        {   // labels
1883            linePtr++;
1884            skipSpacesToEnd(linePtr, end);
1885            initializeOutputFormat();
1886            if (firstName.front() >= '0' && firstName.front() <= '9')
1887            {   // handle local labels
1888                if (sections.empty())
1889                {
1890                    printError(stmtPlace, "Local label can't be defined outside section");
1891                    doNextLine = true;
1892                    break;
1893                }
1894                if (!isAddressableSection())
1895                {
1896                    printError(stmtPlace, "Local label can't be defined in "
1897                            "non-addressable section ");
1898                    doNextLine = true;
1899                    break;
1900                }
1901                /* prevLRes - iterator to previous instance of local label (with 'b)
1902                 * nextLRes - iterator to next instance of local label (with 'f) */
1903                std::pair<AsmSymbolMap::iterator, bool> prevLRes =
1904                        symbolMap.insert(std::make_pair(
1905                            std::string(firstName.c_str())+"b", AsmSymbol()));
1906                std::pair<AsmSymbolMap::iterator, bool> nextLRes =
1907                        symbolMap.insert(std::make_pair(
1908                            std::string(firstName.c_str())+"f", AsmSymbol()));
1909                /* resolve forward symbol of label now */
1910                assert(setSymbol(*nextLRes.first, currentOutPos, currentSection));
1911                // move symbol value from next local label into previous local label
1912                // clearOccurrences - obsolete - back local labels are undefined!
1913                prevLRes.first->second.value = nextLRes.first->second.value;
1914                prevLRes.first->second.hasValue = isResolvableSection();
1915                prevLRes.first->second.sectionId = currentSection;
1916                /// make forward symbol of label as undefined
1917                nextLRes.first->second.hasValue = false;
1918            }
1919            else
1920            {   // regular labels
1921                std::pair<AsmSymbolMap::iterator, bool> res = 
1922                        symbolMap.insert(std::make_pair(firstName, AsmSymbol()));
1923                if (!res.second)
1924                {   // found
1925                    if (res.first->second.onceDefined && res.first->second.isDefined())
1926                    {   // if label
1927                        printError(stmtPlace, (std::string("Symbol '")+firstName.c_str()+
1928                                    "' is already defined").c_str());
1929                        doNextLine = true;
1930                        break;
1931                    }
1932                }
1933                if (sections.empty())
1934                {
1935                    printError(stmtPlace,
1936                               "Label can't be defined outside section");
1937                    doNextLine = true;
1938                    break;
1939                }
1940                if (!isAddressableSection())
1941                {
1942                    printError(stmtPlace, "Label can't be defined in "
1943                            "non-addressable section ");
1944                    doNextLine = true;
1945                    break;
1946                }
1947               
1948                setSymbol(*res.first, currentOutPos, currentSection);
1949                res.first->second.onceDefined = true;
1950                res.first->second.sectionId = currentSection;
1951               
1952                formatHandler->handleLabel(res.first->first);
1953            }
1954            // new label or statement
1955            stmtPlace = linePtr;
1956            firstName = extractLabelName(linePtr, end);
1957        }
1958        if (doNextLine)
1959            continue;
1960       
1961        /* now stmtStartStr - points to first string of statement
1962         * (labels has been skipped) */
1963        skipSpacesToEnd(linePtr, end);
1964        if (linePtr != end && *linePtr == '=' &&
1965            // not for local labels
1966            !isDigit(firstName.front()))
1967        {   // assignment
1968            skipCharAndSpacesToEnd(linePtr, line+lineSize);
1969            if (linePtr == end)
1970            {
1971                printError(linePtr, "Expected assignment expression");
1972                continue;
1973            }
1974            assignSymbol(firstName, stmtPlace, linePtr);
1975            continue;
1976        }
1977        // make firstname as lowercase
1978        toLowerString(firstName);
1979       
1980        if (firstName.size() >= 2 && firstName[0] == '.') // check for pseudo-op
1981            parsePseudoOps(firstName, stmtPlace, linePtr);
1982        else if (firstName.size() >= 1 && isDigit(firstName[0]))
1983            printError(stmtPlace, "Illegal number at statement begin");
1984        else
1985        {   // try to parse processor instruction or macro substitution
1986            if (makeMacroSubstitution(stmtPlace) == ParseState::MISSING)
1987            { 
1988                if (firstName.empty()) // if name is empty
1989                {
1990                    if (linePtr!=end) // error
1991                        printError(stmtPlace, "Garbages at statement place");
1992                    continue;
1993                }
1994                initializeOutputFormat();
1995                // try parse instruction
1996                if (!isWriteableSection())
1997                {
1998                    printError(stmtPlace,
1999                       "Writing data into non-writeable section is illegal");
2000                    continue;
2001                }
2002                isaAssembler->assemble(firstName, stmtPlace, linePtr, end,
2003                           sections[currentSection].content);
2004                currentOutPos = sections[currentSection].getSize();
2005            }
2006        }
2007    }
2008    /* check clauses and print errors */
2009    while (!clauses.empty())
2010    {
2011        const AsmClause& clause = clauses.top();
2012        switch(clause.type)
2013        {
2014            case AsmClauseType::IF:
2015                printError(clause.sourcePos, "Unterminated '.if'");
2016                break;
2017            case AsmClauseType::ELSEIF:
2018                printError(clause.sourcePos, "Unterminated '.elseif'");
2019                printError(clause.prevIfPos, "here is begin of conditional clause"); 
2020                break;
2021            case AsmClauseType::ELSE:
2022                printError(clause.sourcePos, "Unterminated '.else'");
2023                printError(clause.prevIfPos, "here is begin of conditional clause"); 
2024                break;
2025            case AsmClauseType::MACRO:
2026                printError(clause.sourcePos, "Unterminated macro definition");
2027                break;
2028            case AsmClauseType::REPEAT:
2029                printError(clause.sourcePos, "Unterminated repetition");
2030            default:
2031                break;
2032        }
2033        clauses.pop();
2034    }
2035   
2036    resolvingRelocs = true;
2037    for (AsmSymbolEntry& symEntry: symbolMap)
2038        if (!symEntry.second.occurrencesInExprs.empty() || 
2039            (symEntry.first!="."  && !isResolvableSection(symEntry.second.sectionId)))
2040        {   // try to resolve symbols
2041            uint64_t value;
2042            cxuint sectionId;
2043            if (formatHandler!=nullptr &&
2044                formatHandler->resolveSymbol(symEntry.second, value, sectionId))
2045                setSymbol(symEntry, value, sectionId);
2046        }
2047   
2048    if ((flags&ASM_TESTRUN) == 0)
2049        for (AsmSymbolEntry& symEntry: symbolMap)
2050            if (!symEntry.second.occurrencesInExprs.empty())
2051                for (AsmExprSymbolOccurrence occur: symEntry.second.occurrencesInExprs)
2052                    printError(occur.expression->getSourcePos(),(std::string(
2053                        "Unresolved symbol '")+symEntry.first.c_str()+"'").c_str());
2054   
2055    if (good && formatHandler!=nullptr)
2056        formatHandler->prepareBinary();
2057    return good;
2058}
2059
2060void Assembler::writeBinary(const char* filename) const
2061{
2062    if (good)
2063    {
2064        const AsmFormatHandler* formatHandler = getFormatHandler();
2065        if (formatHandler!=nullptr)
2066        {
2067            std::ofstream ofs(filename, std::ios::binary);
2068            if (ofs)
2069                formatHandler->writeBinary(ofs);
2070            else
2071                throw Exception(std::string("Can't open output file '")+filename+"'");
2072        }
2073        else
2074            throw Exception("No output binary");
2075    }
2076    else // failed
2077        throw Exception("Assembler failed!");
2078}
2079
2080void Assembler::writeBinary(std::ostream& outStream) const
2081{
2082    if (good)
2083    {
2084        const AsmFormatHandler* formatHandler = getFormatHandler();
2085        if (formatHandler!=nullptr)
2086            formatHandler->writeBinary(outStream);
2087        else
2088            throw Exception("No output binary");
2089    }
2090    else // failed
2091        throw Exception("Assembler failed!");
2092}
2093
2094void Assembler::writeBinary(Array<cxbyte>& array) const
2095{
2096    if (good)
2097    {
2098        const AsmFormatHandler* formatHandler = getFormatHandler();
2099        if (formatHandler!=nullptr)
2100            formatHandler->writeBinary(array);
2101        else
2102            throw Exception("No output binary");
2103    }
2104    else // failed
2105        throw Exception("Assembler failed!");
2106}
Note: See TracBrowser for help on using the repository browser.