source: CLRX/CLRadeonExtender/trunk/amdasm/AsmSource.cpp @ 3632

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

CLRadeonExtender: Asm: Tentative implementation of '.while' pseudo-op (repetition).

File size: 57.4 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 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 <fstream>
23#include <vector>
24#include <utility>
25#include <algorithm>
26#include <CLRX/utils/Utilities.h>
27#include <CLRX/amdasm/Assembler.h>
28#include "AsmInternals.h"
29
30using namespace CLRX;
31
32/* about column counting: simple input filters (source) handles correctly column counting
33 * Unfortunatelly: macro argument substitution can change column numeration, thus
34 * macro input filters counts incorectly columns (correct solution requires
35 * cumbersome code changes) */
36
37AsmSource::~AsmSource()
38{ }
39
40AsmFile::~AsmFile()
41{ }
42
43AsmMacroSource::~AsmMacroSource()
44{ }
45
46AsmRepeatSource::~AsmRepeatSource()
47{ }
48
49/* Asm Macro */
50AsmMacro::AsmMacro(const AsmSourcePos& _pos, const Array<AsmMacroArg>& _args)
51        : contentLineNo(0), sourcePos(_pos), args(_args)
52{ }
53
54AsmMacro::AsmMacro(const AsmSourcePos& _pos, Array<AsmMacroArg>&& _args)
55        : contentLineNo(0), sourcePos(_pos), args(std::move(_args))
56{ }
57
58void AsmMacro::addLine(RefPtr<const AsmMacroSubst> macro, RefPtr<const AsmSource> source,
59           const std::vector<LineTrans>& colTrans, size_t lineSize, const char* line)
60{
61    content.insert(content.end(), line, line+lineSize);
62    // line can be empty and can be not finished by newline
63    if (lineSize==0 || (lineSize > 0 && line[lineSize-1] != '\n'))
64        content.push_back('\n');
65    colTranslations.insert(colTranslations.end(), colTrans.begin(), colTrans.end());
66    if (!macro)
67    {
68        if (sourceTranslations.empty() || sourceTranslations.back().source != source)
69            sourceTranslations.push_back({contentLineNo, source});
70    }
71    else
72    {
73        // with macro
74        bool doAdd = sourceTranslations.empty();
75        /* add macro source information to line source translations if:
76         * it is first line at source, if macro source differs against previous */
77        if (!doAdd)
78        {
79            doAdd = sourceTranslations.back().source->type != AsmSourceType::MACRO;
80            if (!doAdd)
81            {
82                RefPtr<const AsmMacroSource> macroSource = sourceTranslations.back()
83                            .source.staticCast<const AsmMacroSource>();
84                doAdd = macroSource->source!=source || macroSource->macro!=macro;
85            }
86        }
87        if (doAdd)
88            sourceTranslations.push_back({contentLineNo, RefPtr<const AsmSource>(
89                new AsmMacroSource{macro, source})});
90    }
91    contentLineNo++;
92}
93
94/* Asm Repeat */
95AsmRepeat::AsmRepeat(const AsmSourcePos& _pos, uint64_t _repeatsNum)
96        : contentLineNo(0), sourcePos(_pos), repeatsNum(_repeatsNum)
97{ }
98
99AsmRepeat::~AsmRepeat()
100{ }
101
102// add line to repetition
103void AsmRepeat::addLine(RefPtr<const AsmMacroSubst> macro, RefPtr<const AsmSource> source,
104            const std::vector<LineTrans>& colTrans, size_t lineSize, const char* line)
105{
106    content.insert(content.end(), line, line+lineSize);
107    // line can be empty and can be not finished by newline
108    if (lineSize==0 || (lineSize > 0 && line[lineSize-1] != '\n'))
109        content.push_back('\n');
110    colTranslations.insert(colTranslations.end(), colTrans.begin(), colTrans.end());
111    if (sourceTranslations.empty() || sourceTranslations.back().source != source ||
112        sourceTranslations.back().macro != macro)
113        sourceTranslations.push_back({contentLineNo, macro, source});
114    contentLineNo++;
115}
116
117AsmFor::AsmFor(const AsmSourcePos& _pos, void* _iterSymEntry,
118                AsmExpression* _condExpr, AsmExpression* _nextExpr)
119        : AsmRepeat(_pos, 0), iterSymEntry(_iterSymEntry), condExpr(_condExpr),
120                    nextExpr(_nextExpr)
121{ }
122
123AsmFor::~AsmFor()
124{ }
125
126AsmIRP::AsmIRP(const AsmSourcePos& _pos, const CString& _symbolName,
127               const Array<CString>& _symValues)
128        : AsmRepeat(_pos, _symValues.size()), irpc(false),
129          symbolName(_symbolName), symValues(_symValues)
130{ }
131
132AsmIRP::AsmIRP(const AsmSourcePos& _pos, const CString& _symbolName,
133               Array<CString>&& _symValues)
134        : AsmRepeat(_pos, _symValues.size()), irpc(false), symbolName(_symbolName),
135          symValues(std::move(_symValues))
136{ }
137
138AsmIRP::AsmIRP(const AsmSourcePos& _pos, const CString& _symbolName,
139               const CString& _symValString)
140        : AsmRepeat(_pos, std::max(_symValString.size(), size_t(1))), irpc(true),
141          symbolName(_symbolName), symValues({_symValString})
142{ }
143
144/* AsmInputFilter */
145
146AsmInputFilter::~AsmInputFilter()
147{ }
148
149LineCol AsmInputFilter::translatePos(size_t position) const
150{
151    // find in reverse order with reverse comparison:
152    // find equal or less element (instead equal or greater)
153    auto found = std::lower_bound(colTranslations.rbegin(), colTranslations.rend(),
154         LineTrans({ ssize_t(position), 0 }),
155         [](const LineTrans& t1, const LineTrans& t2)
156         { return t1.position > t2.position; });
157    return { found->lineNo, position-found->position+1 };
158}
159
160/*
161 * AsmStreamInputFilter
162 */
163
164static const size_t AsmParserLineMaxSize = 100;
165
166AsmStreamInputFilter::AsmStreamInputFilter(const CString& filename)
167    : AsmInputFilter(AsmInputFilterType::STREAM), managed(true),
168        stream(nullptr), mode(LineMode::NORMAL), stmtPos(0)
169{
170    try
171    {
172        source = RefPtr<const AsmSource>(new AsmFile(filename));
173        stream = new std::ifstream(filename.c_str(), std::ios::binary);
174        if (!*stream)
175            throw AsmException(std::string("Can't open source file '")+
176                    filename.c_str()+"'");
177        stream->exceptions(std::ios::badbit);
178        buffer.reserve(AsmParserLineMaxSize);
179    }
180    catch(...)
181    {
182        delete stream;
183        throw;
184    }
185}
186
187AsmStreamInputFilter::AsmStreamInputFilter(std::istream& is, const CString& filename)
188    : AsmInputFilter(AsmInputFilterType::STREAM),
189      managed(false), stream(&is), mode(LineMode::NORMAL), stmtPos(0)
190{
191    source = RefPtr<const AsmSource>(new AsmFile(filename));
192    stream->exceptions(std::ios::badbit);
193    buffer.reserve(AsmParserLineMaxSize);
194}
195
196AsmStreamInputFilter::AsmStreamInputFilter(const AsmSourcePos& pos,
197           const CString& filename)
198    : AsmInputFilter(AsmInputFilterType::STREAM),
199      managed(true), stream(nullptr), mode(LineMode::NORMAL), stmtPos(0)
200{
201    try
202    {
203        if (!pos.macro)
204            source = RefPtr<const AsmSource>(new AsmFile(pos.source, pos.lineNo,
205                             pos.colNo, filename));
206        else // if inside macro
207            source = RefPtr<const AsmSource>(new AsmFile(
208                RefPtr<const AsmSource>(new AsmMacroSource(pos.macro, pos.source)),
209                     pos.lineNo, pos.colNo, filename));
210       
211        // open file
212        stream = new std::ifstream(filename.c_str(), std::ios::binary);
213        if (!*stream)
214            throw AsmException(std::string("Can't open source file '")+
215                        filename.c_str()+"'");
216        stream->exceptions(std::ios::badbit);
217        buffer.reserve(AsmParserLineMaxSize);
218    }
219    catch(...)
220    {
221        delete stream;
222        throw;
223    }
224}
225
226AsmStreamInputFilter::AsmStreamInputFilter(const AsmSourcePos& pos, std::istream& is,
227        const CString& filename) : AsmInputFilter(AsmInputFilterType::STREAM),
228        managed(false), stream(&is), mode(LineMode::NORMAL), stmtPos(0)
229{
230    if (!pos.macro)
231        source = RefPtr<const AsmSource>(new AsmFile(pos.source, pos.lineNo,
232                             pos.colNo, filename));
233    else // if inside macro
234        source = RefPtr<const AsmSource>(new AsmFile(
235            RefPtr<const AsmSource>(new AsmMacroSource(pos.macro, pos.source)),
236                 pos.lineNo, pos.colNo, filename));
237    stream->exceptions(std::ios::badbit);
238    buffer.reserve(AsmParserLineMaxSize);
239}
240
241AsmStreamInputFilter::~AsmStreamInputFilter()
242{
243    if (managed)
244        delete stream;
245}
246
247const char* AsmStreamInputFilter::readLine(Assembler& assembler, size_t& lineSize)
248{
249    colTranslations.clear();
250    bool endOfLine = false;
251    size_t lineStart = pos;
252    size_t joinStart = pos; // join Start - physical line start
253    size_t destPos = pos;
254    size_t backslash = false;
255    bool prevAsterisk = false;
256    bool asterisk = false;
257    colTranslations.push_back({ssize_t(-stmtPos), lineNo});
258    while (!endOfLine)
259    {
260        switch(mode)
261        {
262            case LineMode::NORMAL:
263            {
264                if (pos < buffer.size() && !isSpace(buffer[pos]) && buffer[pos] != ';')
265                {
266                    // putting regular string (no spaces)
267                    do {
268                        backslash = (buffer[pos] == '\\');
269                        if (buffer[pos] == '*' &&
270                            destPos > 0 && buffer[destPos-1] == '/')
271                        {
272                            // if long comment
273                            prevAsterisk = false;
274                            asterisk = false;
275                            buffer[destPos-1] = ' ';
276                            buffer[destPos++] = ' ';
277                            mode = LineMode::LONG_COMMENT;
278                            pos++;
279                            break;
280                        }
281                        if (buffer[pos] == '#')
282                        {
283                            // if line comment
284                            buffer[destPos++] = ' ';
285                            mode = LineMode::LINE_COMMENT;
286                            pos++;
287                            break;
288                        }
289                       
290                        const char old = buffer[pos];
291                        buffer[destPos++] = buffer[pos++];
292                       
293                        if (old == '"')
294                        {
295                            // if string opened
296                            mode = LineMode::STRING;
297                            break;
298                        }
299                        else if (old == '\'')
300                        {
301                            // if string opened
302                            mode = LineMode::LSTRING;
303                            break;
304                        }
305                       
306                    } while (pos < buffer.size() && !isSpace(buffer[pos]) &&
307                                buffer[pos] != ';');
308                }
309                if (pos < buffer.size() && mode!=LineMode::LINE_COMMENT)
310                {
311                    // ignore for single line comment - because empty single comment
312                    // will be moved to next line!
313                    if (buffer[pos] == '\n')
314                    {
315                        lineNo++;
316                        endOfLine = (!backslash);
317                        if (backslash) 
318                        {
319                            destPos--;
320                            /* delete col translation at this position (if exists) and
321                             * add new with new lineNo */
322                            if (ssize_t(destPos-lineStart) ==
323                                colTranslations.back().position)
324                                colTranslations.pop_back();
325                            colTranslations.push_back(
326                                {ssize_t(destPos-lineStart), lineNo});
327                        }
328                        stmtPos = 0;
329                        pos++;
330                        joinStart = pos;
331                        backslash = false;
332                        break;
333                    }
334                    else if (buffer[pos] == ';' && mode == LineMode::NORMAL)
335                    {
336                        /* treat statement as separate line */
337                        endOfLine = true;
338                        pos++;
339                        stmtPos += pos-joinStart;
340                        joinStart = pos;
341                        backslash = false;
342                        break;
343                    }
344                    else if (mode == LineMode::NORMAL)
345                    {
346                        /* replace space character by 0x20 (space) */
347                        backslash = false;
348                        do {
349                            buffer[destPos++] = ' ';
350                            pos++;
351                        } while (pos < buffer.size() && buffer[pos] != '\n' &&
352                            isSpace(buffer[pos]));
353                    }
354                }
355                break;
356            }
357            case LineMode::LINE_COMMENT:
358            {
359                while (pos < buffer.size() && buffer[pos] != '\n')
360                {
361                    // skipping bytes until newline or buffer end
362                    backslash = (buffer[pos] == '\\');
363                    pos++;
364                    buffer[destPos++] = ' ';
365                }
366                if (pos < buffer.size())
367                {
368                    lineNo++;
369                    endOfLine = (!backslash);
370                    if (backslash)
371                    {
372                        // continue comment after line splitting
373                        destPos--;
374                        if (ssize_t(destPos-lineStart) == colTranslations.back().position)
375                            colTranslations.pop_back();
376                        colTranslations.push_back({ssize_t(destPos-lineStart), lineNo});
377                    }
378                    else
379                        mode = LineMode::NORMAL;
380                    pos++;
381                    joinStart = pos;
382                    backslash = false;
383                    stmtPos = 0;
384                }
385                break;
386            }
387            case LineMode::LONG_COMMENT:
388            {
389                // go to end of long comment '*/' or to end of line
390                while (pos < buffer.size() && buffer[pos] != '\n' &&
391                    (!asterisk || buffer[pos] != '/'))
392                {
393                    backslash = (buffer[pos] == '\\');
394                    prevAsterisk = asterisk;
395                    asterisk = (buffer[pos] == '*');
396                    pos++;
397                    buffer[destPos++] = ' ';
398                }
399                if (pos < buffer.size())
400                {
401                    if ((asterisk && buffer[pos] == '/'))
402                    {
403                        // end of multi line comment, set normal mode
404                        pos++;
405                        buffer[destPos++] = ' ';
406                        mode = LineMode::NORMAL;
407                    }
408                    else
409                    {
410                        // newline
411                        lineNo++;
412                        endOfLine = (!backslash);
413                        if (backslash)
414                        {
415                            asterisk = prevAsterisk;
416                            prevAsterisk = false;
417                            destPos--;
418                            /* delete col translation at this position (if exists) and
419                             * add new with new lineNo */
420                            if (ssize_t(destPos-lineStart) ==
421                                colTranslations.back().position)
422                                colTranslations.pop_back();
423                            colTranslations.push_back(
424                                {ssize_t(destPos-lineStart), lineNo});
425                        }
426                        pos++;
427                        joinStart = pos;
428                        backslash = false;
429                        stmtPos = 0;
430                    }
431                }
432                break;
433            }
434            case LineMode::STRING:
435            case LineMode::LSTRING:
436            {
437                const char quoteChar = (mode == LineMode::STRING)?'"':'\'';
438                // go to end of string '"' or "'" or to new line
439                while (pos < buffer.size() && buffer[pos] != '\n' &&
440                    ((backslash&1) || buffer[pos] != quoteChar))
441                {
442                    if (buffer[pos] == '\\')
443                        backslash++;
444                    else
445                        backslash = 0;
446                    buffer[destPos++] = buffer[pos];
447                    pos++;
448                }
449                if (pos < buffer.size())
450                {
451                    if ((backslash&1)==0 && buffer[pos] == quoteChar)
452                    {
453                        // if qoutation character exists and it not escaped, we ends string
454                        pos++;
455                        mode = LineMode::NORMAL;
456                        buffer[destPos++] = quoteChar;
457                    }
458                    else
459                    {
460                        lineNo++;
461                        endOfLine = ((backslash&1)==0);
462                        if (backslash&1)
463                        {
464                            destPos--; // ignore last backslash
465                            colTranslations.push_back(
466                                {ssize_t(destPos-lineStart), lineNo});
467                        }
468                        else
469                            assembler.printWarning({lineNo, pos-joinStart+stmtPos+1},
470                                        "Unterminated string: newline inserted");
471                        pos++;
472                        joinStart = pos;
473                        stmtPos = 0;
474                    }
475                    backslash = false;
476                }
477                break;
478            }
479            default:
480                break;
481        }
482       
483        if (endOfLine)
484            break;
485       
486        if (pos >= buffer.size())
487        {
488            /* get from buffer */
489            if (lineStart != 0)
490            {
491                // use backward copying for moving buffer content back to begin
492                std::copy_backward(buffer.begin()+lineStart, buffer.begin()+pos,
493                       buffer.begin() + pos-lineStart);
494                destPos -= lineStart;
495                joinStart -= pos-destPos;
496                pos = destPos;
497                lineStart = 0;
498            }
499            if (pos == buffer.size())
500                buffer.resize(std::max(AsmParserLineMaxSize, (pos>>1)+pos));
501           
502            stream->read(buffer.data()+pos, buffer.size()-pos);
503            const size_t readed = stream->gcount();
504            buffer.resize(pos+readed);
505            if (readed == 0)
506            {
507                // end of file. check comments
508                if (mode == LineMode::LONG_COMMENT && lineStart!=pos)
509                    assembler.printError({lineNo, pos-joinStart+stmtPos+1},
510                           "Unterminated multi-line comment");
511                if (destPos-lineStart == 0)
512                {
513                    lineSize = 0;
514                    return nullptr;
515                }
516                break;
517            }
518        }
519    }
520    lineSize = destPos-lineStart;
521    return buffer.data()+lineStart;
522}
523
524AsmMacroInputFilter::AsmMacroInputFilter(RefPtr<const AsmMacro> _macro,
525         const AsmSourcePos& pos, const MacroArgMap& _argMap, uint64_t _macroCount,
526         bool _alternateMacro)
527        : AsmInputFilter(AsmInputFilterType::MACROSUBST), macro(_macro),
528          argMap(_argMap), macroCount(_macroCount), contentLineNo(0), sourceTransIndex(0),
529          realLinePos(0), alternateMacro(_alternateMacro)
530{
531    if (macro->getSourceTransSize()!=0)
532        source = macro->getSourceTrans(0).source;
533    macroSubst = RefPtr<const AsmMacroSubst>(new AsmMacroSubst(pos.macro,
534                   pos.source, pos.lineNo, pos.colNo));
535    curColTrans = macro->getColTranslations().data();
536    buffer.reserve(AsmParserLineMaxSize);
537    lineNo = !macro->getColTranslations().empty() ? curColTrans[0].lineNo : 0;
538    if (!macro->getColTranslations().empty())
539        realLinePos = -curColTrans[0].position;
540}
541
542AsmMacroInputFilter::AsmMacroInputFilter(RefPtr<const AsmMacro> _macro,
543         const AsmSourcePos& pos, MacroArgMap&& _argMap, uint64_t _macroCount,
544         bool _alternateMacro)
545        : AsmInputFilter(AsmInputFilterType::MACROSUBST), macro(_macro),
546          argMap(std::move(_argMap)), macroCount(_macroCount),
547          contentLineNo(0), sourceTransIndex(0), realLinePos(0),
548          alternateMacro(_alternateMacro)
549{
550    if (macro->getSourceTransSize()!=0)
551        source = macro->getSourceTrans(0).source;
552    macroSubst = RefPtr<const AsmMacroSubst>(new AsmMacroSubst(pos.macro,
553                   pos.source, pos.lineNo, pos.colNo));
554    curColTrans = macro->getColTranslations().data();
555    buffer.reserve(AsmParserLineMaxSize);
556    lineNo = !macro->getColTranslations().empty() ? curColTrans[0].lineNo : 0;
557    if (!macro->getColTranslations().empty())
558        realLinePos = -curColTrans[0].position;
559}
560
561const char* AsmMacroInputFilter::readLine(Assembler& assembler, size_t& lineSize)
562{
563    buffer.clear();
564    colTranslations.clear();
565    const std::vector<LineTrans>& macroColTrans = macro->getColTranslations();
566    const LineTrans* colTransEnd = macroColTrans.data()+ macroColTrans.size();
567    const size_t contentSize = macro->getContent().size();
568    if (pos == contentSize)
569    {
570        lineSize = 0;
571        return nullptr;
572    }
573   
574    const char* content = macro->getContent().data();
575   
576    size_t nextLinePos = pos;
577    while (nextLinePos < contentSize && content[nextLinePos] != '\n')
578        nextLinePos++;
579   
580    const size_t linePos = pos;
581    size_t destPos = 0;
582    size_t toCopyPos = pos;
583    // determine start of destination line (real line, with real newline)
584    size_t destLineStart = 0;
585    // first curColTrans
586    colTranslations.push_back({ ssize_t(-realLinePos), curColTrans->lineNo});
587    // colTransThreshold is position of next column translation (e.g line splitting)
588    size_t colTransThreshold = (curColTrans+1 != colTransEnd) ?
589            (curColTrans[1].position>0 ? curColTrans[1].position + linePos :
590                    nextLinePos) : SIZE_MAX;
591   
592    const char* localStmtStart = nullptr;
593    std::vector<std::pair<CString, const char*> > localNames;
594    const char* stmtStartPtr = content + pos;
595    /* parse local statement */
596    if (alternateMacro)
597    {
598        // try to parse local statement
599        const char* linePtr = stmtStartPtr;
600        const char* end = content+nextLinePos;
601        // before we skip labels at current statement
602        skipSpacesAndLabels(linePtr, end);
603        localStmtStart = linePtr;
604        if (linePtr+6 < end && ::strncasecmp(linePtr, "local", 5)==0 && linePtr[5]==' ')
605        {
606            // if local
607            linePtr+=5;
608            while (true)
609            {
610                skipSpacesToEnd(linePtr, end);
611                if (linePtr == end)
612                    break; // end of list
613                const char* symNamePlace = linePtr;
614                const CString localName = extractSymName(linePtr, end, false);
615                if (!localName.empty())
616                {
617                    localNames.push_back({localName, symNamePlace});
618                    skipSpacesToEnd(linePtr, end);
619                    if (linePtr!=end && *linePtr==',')
620                        linePtr++; // skip ','
621                }
622                else // is not symbol
623                    break;
624            }
625           
626            skipSpacesToEnd(linePtr, end);
627            if (linePtr!=end)
628                localStmtStart = nullptr; // this is not local stmt
629        }
630        else
631            localStmtStart = nullptr; // this is not local stmt
632    }
633   
634    // indicate length of name to copy to buffer (skip)
635    size_t wordSkip = 0;
636    /* loop move position to backslash. if backslash encountered then copy content
637     * to content and handles backsash with substitutions */
638    while (pos < contentSize && content[pos] != '\n')
639    {
640        if (alternateMacro && localStmtStart!=nullptr && content+pos == localStmtStart)
641        {
642            /* if end of labels in 'local' statement',
643             * we just replaces character by spaces */
644            // put remaining text from source (to local stmt start position)
645            buffer.resize(destPos + pos-toCopyPos);
646            std::copy(content + toCopyPos, content + pos, buffer.begin() + destPos);
647            destPos += pos-toCopyPos;
648            toCopyPos = pos;
649            // put col translations and spaces to buffer
650            while (pos < contentSize && content[pos] != '\n')
651            {
652                if (pos >= colTransThreshold)
653                {
654                    // put column translation
655                    curColTrans++;
656                    colTranslations.push_back({ssize_t(destPos + pos-toCopyPos),
657                                curColTrans->lineNo});
658                    if (curColTrans->position >= 0)
659                    {
660                        /// real new line, reset real line position
661                        realLinePos = 0;
662                        destLineStart = destPos + pos-toCopyPos;
663                    }
664                    colTransThreshold = (curColTrans+1 != colTransEnd) ?
665                            (curColTrans[1].position>0 ? curColTrans[1].position + linePos :
666                                    nextLinePos) : SIZE_MAX;
667                }
668                pos++;
669                buffer.push_back(' '); // put space instead of character to ignore later
670            }
671            toCopyPos = pos;
672            break; // end of line of statement if local statement occurrent
673        }
674       
675        bool tryParseSubstition = false;
676        bool altMacroSyntax = false; // indicate if currently used altmacro syntax
677        if (content[pos] != '\\')
678        {
679            if (pos >= colTransThreshold)
680            {
681                curColTrans++;
682                colTranslations.push_back({ssize_t(destPos + pos-toCopyPos),
683                            curColTrans->lineNo});
684                if (curColTrans->position >= 0)
685                {
686                    /// real new line, reset real line position
687                    realLinePos = 0;
688                    destLineStart = destPos + pos-toCopyPos;
689                }
690                colTransThreshold = (curColTrans+1 != colTransEnd) ?
691                        (curColTrans[1].position>0 ? curColTrans[1].position + linePos :
692                                nextLinePos) : SIZE_MAX;
693            }
694            if (alternateMacro && wordSkip==0 && pos < contentSize &&
695                (isAlpha(content[pos]) || content[pos]=='.' || content[pos]=='$' ||
696                 content[pos]=='_'))
697            {
698                // try parse substitution (altmacro mode)
699                tryParseSubstition = true;
700                altMacroSyntax = true; // disables '@' and '()' use altmacro
701            }
702            else
703            {
704                /* otherwise consume one character */
705                if (wordSkip!=0)
706                    // after unmatched alternate substitution, we copy unmatched name
707                    wordSkip--;
708                pos++;
709            }
710        }
711        else
712        {
713            // backslash
714            if (pos >= colTransThreshold)
715            {
716                // put column translation
717                curColTrans++;
718                colTranslations.push_back({ssize_t(destPos + pos-toCopyPos),
719                            curColTrans->lineNo});
720                if (curColTrans->position >= 0)
721                {
722                    /// real new line, reset real line position
723                    realLinePos = 0;
724                    destLineStart = destPos + pos-toCopyPos;
725                }
726                colTransThreshold = (curColTrans+1 != colTransEnd) ?
727                        (curColTrans[1].position>0 ? curColTrans[1].position + linePos :
728                                nextLinePos) : SIZE_MAX;
729            }
730            // copy chars to buffer, fast copy regular content of macro (no substitution)
731            if (pos > toCopyPos)
732            {
733                buffer.resize(destPos + pos-toCopyPos);
734                std::copy(content + toCopyPos, content + pos, buffer.begin() + destPos);
735                destPos += pos-toCopyPos;
736            }
737            pos++;
738            tryParseSubstition = true;
739        }
740        if (tryParseSubstition)
741        {
742            bool skipColTransBetweenMacroArg = true;
743            if (pos < contentSize)
744            {
745                if (!altMacroSyntax &&
746                    content[pos] == '(' && pos+1 < contentSize && content[pos+1]==')')
747                    pos += 2;   // skip this separator
748                else
749                {
750                    // extract argName
751                    const char* thisPos = content + pos;
752                    const CString symName = extractSymName(
753                                thisPos, content+contentSize, false);
754                    auto it = argMap.end();
755                    auto localIt = localMap.end();
756                    if (!symName.empty()) // find only if not empty symName
757                    {
758                        it = binaryMapFind(argMap.begin(), argMap.end(), symName);
759                        if (it == argMap.end())
760                            localIt = localMap.find(symName);
761                    }
762                    if (altMacroSyntax && (it!=argMap.end() || localIt!=localMap.end()))
763                    {
764                        /* copy previous content, missing copy before alternate
765                         * substitution */
766                        buffer.resize(destPos + pos-toCopyPos);
767                        std::copy(content + toCopyPos, content + pos,
768                                  buffer.begin() + destPos);
769                        destPos += pos-toCopyPos;
770                    }
771                   
772                    if (it != argMap.end())
773                    {
774                        // if found
775                        buffer.insert(buffer.end(), it->second.begin(),
776                              it->second.begin() + it->second.size());
777                        destPos += it->second.size();
778                        pos = thisPos-content;
779                    }
780                    else if (localIt != localMap.end())
781                    {
782                        // substitute local definition
783                        char buf[32];
784                        ::memcpy(buf, ".LL", 3);
785                        size_t bufSize = itocstrCStyle(localIt->second, buf+3, 29)+3;
786                        buffer.insert(buffer.end(), buf, buf+bufSize);
787                        destPos += bufSize;
788                        pos = thisPos-content;
789                    }
790                    else if (!altMacroSyntax && content[pos] == '@')
791                    {
792                        char numBuf[32];
793                        const size_t numLen = itocstrCStyle(macroCount, numBuf, 32);
794                        pos++;
795                        buffer.insert(buffer.end(), numBuf, numBuf+numLen);
796                        destPos += numLen;
797                    }
798                    else
799                    {
800                        if (!altMacroSyntax)
801                        {
802                            buffer.push_back('\\');
803                            destPos++;
804                        }
805                        else // continue consuming to copy
806                        {
807                            // and set name to copy to buffer (skip)
808                            wordSkip = symName.size();
809                            continue;
810                        }
811                        // do not skip column translation, because no substitution!
812                        skipColTransBetweenMacroArg = false;
813                    }
814                }
815            }
816            toCopyPos = pos;
817            // skip colTrans between macroarg or separator
818            if (skipColTransBetweenMacroArg)
819            {
820                while (pos > colTransThreshold)
821                {
822                    curColTrans++;
823                    if (curColTrans->position >= 0)
824                    {
825                        /// real new line, reset real line position
826                        realLinePos = 0;
827                        destLineStart = destPos + pos-toCopyPos;
828                    }
829                    colTransThreshold = (curColTrans+1 != colTransEnd) ?
830                            curColTrans[1].position : SIZE_MAX;
831                }
832            }
833        }
834    }
835    // last copying of content of line (rest of line)
836    if (pos > toCopyPos)
837    {
838        buffer.resize(destPos + pos-toCopyPos);
839        std::copy(content + toCopyPos, content + pos, buffer.begin() + destPos);
840        destPos += pos-toCopyPos;
841    }
842    lineSize = buffer.size();
843    /// if not end of content (just newline)
844    if (pos < contentSize)
845    {
846        if (curColTrans+1 != colTransEnd)
847        {
848            curColTrans++;
849            if (curColTrans->position >= 0) /// real new line, reset real line position
850                realLinePos = 0;
851            else    // otherwise determine position in destination source
852                realLinePos += lineSize - destLineStart+1;
853        }
854        pos++; // skip newline
855    }
856    lineNo = curColTrans->lineNo;
857    // move to next source translation
858    if (sourceTransIndex+1 < macro->getSourceTransSize())
859    {
860        const AsmMacro::SourceTrans& fpos = macro->getSourceTrans(sourceTransIndex+1);
861        if (fpos.lineNo == contentLineNo)
862        {
863            source = fpos.source;
864            sourceTransIndex++;
865        }
866    }
867    contentLineNo++;
868    if (localStmtStart!=nullptr)
869    {
870        // if really is local statement, we add local defs to map
871        for (const auto& elem: localNames)
872            if (!addLocal(elem.first, assembler.localCount))
873                // error report error if duplicate
874                assembler.printError(getSourcePos(elem.second-stmtStartPtr),
875                     (std::string("Name '")+elem.first.c_str()+
876                     "' was already used by local or macro argument").c_str());
877            else
878                assembler.localCount++;
879    }
880    return (!buffer.empty()) ? buffer.data() : "";
881}
882
883bool AsmMacroInputFilter::addLocal(const CString& name, uint64_t localNo)
884{
885    if (binaryMapFind(argMap.begin(), argMap.end(), name) != argMap.end())
886        return false; // if found in argument list
887    return localMap.insert(std::make_pair(name, localNo)).second;
888}
889
890/*
891 * AsmRepeatInputFilter
892 */
893
894AsmRepeatInputFilter::AsmRepeatInputFilter(const AsmRepeat* _repeat) :
895          AsmInputFilter(AsmInputFilterType::REPEAT), repeat(_repeat),
896          repeatCount(0), contentLineNo(0), sourceTransIndex(0)
897{
898    if (_repeat->getSourceTransSize()!=0)
899    {
900        source = RefPtr<const AsmSource>(new AsmRepeatSource(
901                    _repeat->getSourceTrans(0).source, 0, _repeat->getRepeatsNum()));
902        macroSubst = _repeat->getSourceTrans(0).macro;
903    }
904    else
905        source = RefPtr<const AsmSource>(new AsmRepeatSource(
906                    RefPtr<const AsmSource>(), 0, _repeat->getRepeatsNum()));
907    curColTrans = _repeat->getColTranslations().data();
908    lineNo = !_repeat->getColTranslations().empty() ? curColTrans[0].lineNo : 0;
909}
910
911const char* AsmRepeatInputFilter::readLine(Assembler& assembler, size_t& lineSize)
912{
913    colTranslations.clear();
914    const std::vector<LineTrans>& repeatColTrans = repeat->getColTranslations();
915    const LineTrans* colTransEnd = repeatColTrans.data()+ repeatColTrans.size();
916    const size_t contentSize = repeat->getContent().size();
917    if (pos == contentSize)
918    {
919        repeatCount++;
920        if (repeatCount == repeat->getRepeatsNum() || contentSize==0)
921        {
922            lineSize = 0;
923            return nullptr;
924        }
925        sourceTransIndex = 0;
926        curColTrans = repeat->getColTranslations().data();
927        pos = 0;
928        contentLineNo = 0;
929        source = RefPtr<const AsmSource>(new AsmRepeatSource(
930            repeat->getSourceTrans(0).source, repeatCount, repeat->getRepeatsNum()));
931    }
932    const char* content = repeat->getContent().data();
933    size_t oldPos = pos;
934    while (pos < contentSize && content[pos] != '\n')
935        pos++;
936   
937    lineSize = pos - oldPos; // set new linesize
938    if (pos < contentSize)
939        pos++; // skip newline
940   
941    const LineTrans* oldCurColTrans = curColTrans;
942    curColTrans++;
943    while (curColTrans != colTransEnd && curColTrans->position > 0)
944        curColTrans++;
945    colTranslations.assign(oldCurColTrans, curColTrans);
946   
947    lineNo = (curColTrans != colTransEnd) ? curColTrans->lineNo : repeatColTrans[0].lineNo;
948    if (sourceTransIndex+1 < repeat->getSourceTransSize())
949    {
950        const AsmRepeat::SourceTrans& fpos = repeat->getSourceTrans(sourceTransIndex+1);
951        if (fpos.lineNo == contentLineNo)
952        {
953            macroSubst = fpos.macro;
954            sourceTransIndex++;
955            source = RefPtr<const AsmSource>(new AsmRepeatSource(
956                fpos.source, repeatCount, repeat->getRepeatsNum()));
957        }
958    }
959    contentLineNo++;
960    return content + oldPos;
961}
962
963AsmForInputFilter::AsmForInputFilter(const AsmFor* forRpt) :
964        AsmRepeatInputFilter(forRpt)
965{ }
966
967const char* AsmForInputFilter::readLine(Assembler& assembler, size_t& lineSize)
968{
969    colTranslations.clear();
970    const std::vector<LineTrans>& repeatColTrans = repeat->getColTranslations();
971    const AsmFor* asmFor = static_cast<const AsmFor*>(repeat.get());
972    const LineTrans* colTransEnd = repeatColTrans.data()+ repeatColTrans.size();
973    const size_t contentSize = repeat->getContent().size();
974    if (pos == contentSize)
975    {
976        repeatCount++;
977        uint64_t value = 0;
978        cxuint sectionId = ASMSECT_ABS;
979        bool good = true;
980        if (asmFor->getNextExpr() != nullptr)
981        {
982            std::unique_ptr<AsmExpression> nextEvExpr(asmFor->getNextExpr()->
983                        createExprToEvaluate(assembler));
984            uint64_t nextValue = 0;
985            cxuint nextSectionId = ASMSECT_ABS;
986            if (nextEvExpr != nullptr &&
987                nextEvExpr->evaluate(assembler, nextValue, nextSectionId) &&
988                        nextSectionId == ASMSECT_ABS)
989                assembler.setSymbol(*(AsmSymbolEntry*)asmFor->getIterSymEntry(),
990                                    nextValue, ASMSECT_ABS);
991            else
992                good = false;
993        }
994        if (good)
995        {
996            std::unique_ptr<AsmExpression> condEvExpr(asmFor->getCondExpr()->
997                        createExprToEvaluate(assembler));
998            if (condEvExpr==nullptr || !condEvExpr->evaluate(assembler, value, sectionId) ||
999                        sectionId != ASMSECT_ABS)
1000                value = 0;
1001        }
1002       
1003        if (!good || value==0 || contentSize==0)
1004        {
1005            lineSize = 0;
1006            return nullptr;
1007        }
1008       
1009        sourceTransIndex = 0;
1010        curColTrans = repeat->getColTranslations().data();
1011        pos = 0;
1012        contentLineNo = 0;
1013        source = RefPtr<const AsmSource>(new AsmRepeatSource(
1014            repeat->getSourceTrans(0).source, repeatCount, repeat->getRepeatsNum()));
1015    }
1016    const char* content = repeat->getContent().data();
1017    size_t oldPos = pos;
1018    while (pos < contentSize && content[pos] != '\n')
1019        pos++;
1020   
1021    lineSize = pos - oldPos; // set new linesize
1022    if (pos < contentSize)
1023        pos++; // skip newline
1024   
1025    const LineTrans* oldCurColTrans = curColTrans;
1026    curColTrans++;
1027    while (curColTrans != colTransEnd && curColTrans->position > 0)
1028        curColTrans++;
1029    colTranslations.assign(oldCurColTrans, curColTrans);
1030   
1031    lineNo = (curColTrans != colTransEnd) ? curColTrans->lineNo : repeatColTrans[0].lineNo;
1032    if (sourceTransIndex+1 < repeat->getSourceTransSize())
1033    {
1034        const AsmRepeat::SourceTrans& fpos = repeat->getSourceTrans(sourceTransIndex+1);
1035        if (fpos.lineNo == contentLineNo)
1036        {
1037            macroSubst = fpos.macro;
1038            sourceTransIndex++;
1039            source = RefPtr<const AsmSource>(new AsmRepeatSource(
1040                fpos.source, repeatCount, repeat->getRepeatsNum()));
1041        }
1042    }
1043    contentLineNo++;
1044    return content + oldPos;
1045}
1046
1047AsmIRPInputFilter::AsmIRPInputFilter(const AsmIRP* _irp) :
1048        AsmInputFilter(AsmInputFilterType::REPEAT), irp(_irp),
1049        repeatCount(0), contentLineNo(0), sourceTransIndex(0), realLinePos(0)
1050{
1051    if (_irp->getSourceTransSize()!=0)
1052    {
1053        source = RefPtr<const AsmSource>(new AsmRepeatSource(
1054                    _irp->getSourceTrans(0).source, 0, _irp->getRepeatsNum()));
1055        macroSubst = _irp->getSourceTrans(0).macro;
1056    }
1057    else
1058        source = RefPtr<const AsmSource>(new AsmRepeatSource(
1059                    RefPtr<const AsmSource>(), 0, _irp->getRepeatsNum()));
1060    curColTrans = _irp->getColTranslations().data();
1061    lineNo = !_irp->getColTranslations().empty() ? curColTrans[0].lineNo : 0;
1062   
1063    if (!_irp->getColTranslations().empty())
1064        realLinePos = -curColTrans[0].position;
1065    buffer.reserve(AsmParserLineMaxSize);
1066}
1067
1068const char* AsmIRPInputFilter::readLine(Assembler& assembler, size_t& lineSize)
1069{
1070    buffer.clear();
1071    colTranslations.clear();
1072    const std::vector<LineTrans>& macroColTrans = irp->getColTranslations();
1073    const LineTrans* colTransEnd = macroColTrans.data()+ macroColTrans.size();
1074    const size_t contentSize = irp->getContent().size();
1075    if (pos == contentSize)
1076    {
1077        repeatCount++;
1078        if (repeatCount == irp->getRepeatsNum() || contentSize==0)
1079        {
1080            lineSize = 0;
1081            return nullptr;
1082        }
1083        sourceTransIndex = 0;
1084        curColTrans = irp->getColTranslations().data();
1085        realLinePos = -curColTrans[0].position;
1086        pos = contentLineNo = 0;
1087        source = RefPtr<const AsmSource>(new AsmRepeatSource(
1088            irp->getSourceTrans(0).source, repeatCount, irp->getRepeatsNum()));
1089    }
1090   
1091    const CString& expectedSymName = irp->getSymbolName();
1092    const CString& symValue = !irp->isIRPC() ? irp->getSymbolValue(repeatCount) :
1093            irp->getSymbolValue(0);
1094    size_t symValueSize = symValue.size();
1095    const char* content = irp->getContent().data();
1096   
1097    size_t nextLinePos = pos;
1098    while (nextLinePos < contentSize && content[nextLinePos] != '\n')
1099        nextLinePos++;
1100   
1101    const size_t linePos = pos;
1102    size_t destPos = 0;
1103    size_t toCopyPos = pos;
1104    // determine start of destination line (real line, with real newline)
1105    size_t destLineStart = 0;
1106    colTranslations.push_back({ ssize_t(-realLinePos), curColTrans->lineNo});
1107    // colTransThreshold is position of next column translation (e.g line splitting)
1108    size_t colTransThreshold = (curColTrans+1 != colTransEnd) ?
1109            (curColTrans[1].position>0 ? curColTrans[1].position + linePos :
1110                    nextLinePos) : SIZE_MAX;
1111   
1112    /* loop move position to backslash. if backslash encountered then copy content
1113     * to content and handles backsash with substitutions */
1114    while (pos < contentSize && content[pos] != '\n')
1115    {
1116        if (content[pos] != '\\')
1117        {
1118            if (pos >= colTransThreshold)
1119            {
1120                // put column translation
1121                curColTrans++;
1122                colTranslations.push_back({ssize_t(destPos + pos-toCopyPos),
1123                            curColTrans->lineNo});
1124                if (curColTrans->position >= 0)
1125                {
1126                    /// real new line, reset real line position
1127                    realLinePos = 0;
1128                    destLineStart = destPos + pos-toCopyPos;
1129                }
1130                colTransThreshold = (curColTrans+1 != colTransEnd) ?
1131                        (curColTrans[1].position>0 ? curColTrans[1].position + linePos :
1132                                nextLinePos) : SIZE_MAX;
1133            }
1134            pos++;
1135        }
1136        else
1137        {
1138            // backslash
1139            if (pos >= colTransThreshold)
1140            {
1141                // put column translation
1142                curColTrans++;
1143                colTranslations.push_back({ssize_t(destPos + pos-toCopyPos),
1144                            curColTrans->lineNo});
1145                if (curColTrans->position >= 0)
1146                {
1147                    /// real new line, reset real line position
1148                    realLinePos = 0;
1149                    destLineStart = destPos + pos-toCopyPos;
1150                }
1151                colTransThreshold = (curColTrans+1 != colTransEnd) ?
1152                        (curColTrans[1].position>0 ? curColTrans[1].position + linePos :
1153                                nextLinePos) : SIZE_MAX;
1154            }
1155            // copy chars to buffer
1156            if (pos > toCopyPos)
1157            {
1158                buffer.resize(destPos + pos-toCopyPos);
1159                std::copy(content + toCopyPos, content + pos, buffer.begin() + destPos);
1160                destPos += pos-toCopyPos;
1161            }
1162            pos++;
1163            bool skipColTransBetweenMacroArg = true;
1164            if (pos < contentSize)
1165            {
1166                if (content[pos] == '(' && pos+1 < contentSize && content[pos+1]==')')
1167                    pos += 2;   // skip this separator
1168                else
1169                {
1170                    // extract argName
1171                    const char* thisPos = content+pos;
1172                    const CString symName = extractSymName(
1173                                thisPos, content+contentSize, false);
1174                    if (expectedSymName == symName)
1175                    {
1176                        // if found
1177                        if (!irp->isIRPC())
1178                        {
1179                            buffer.insert(buffer.end(), symValue.begin(),
1180                                  symValue.begin() + symValueSize);
1181                            destPos += symValueSize;
1182                        }
1183                        else if (!symValue.empty())
1184                        {
1185                            buffer.push_back(symValue[repeatCount]);
1186                            destPos++;
1187                        }
1188                        pos = thisPos-content;
1189                    }
1190                    else
1191                    {
1192                        buffer.push_back('\\');
1193                        destPos++;
1194                        // do not skip column translation, because no substitution!
1195                        skipColTransBetweenMacroArg = false;
1196                    }
1197                }
1198            }
1199            toCopyPos = pos;
1200            // skip colTrans between macroarg or separator
1201            if (skipColTransBetweenMacroArg)
1202            {
1203                while (pos > colTransThreshold)
1204                {
1205                    curColTrans++;
1206                    if (curColTrans->position >= 0)
1207                    {
1208                        /// real new line, reset real line position
1209                        realLinePos = 0;
1210                        destLineStart = destPos + pos-toCopyPos;
1211                    }
1212                    colTransThreshold = (curColTrans+1 != colTransEnd) ?
1213                            curColTrans[1].position : SIZE_MAX;
1214                }
1215            }
1216        }
1217    }
1218    if (pos > toCopyPos)
1219    {
1220        buffer.resize(destPos + pos-toCopyPos);
1221        std::copy(content + toCopyPos, content + pos, buffer.begin() + destPos);
1222        destPos += pos-toCopyPos;
1223    }
1224    lineSize = buffer.size();
1225    // not content end (just newline at end of line)
1226    if (pos < contentSize)
1227    {
1228        if (curColTrans != colTransEnd)
1229        {
1230            curColTrans++;
1231            if (curColTrans != colTransEnd)
1232            {
1233                if (curColTrans->position >= 0)
1234                    /// real new line, reset real line position
1235                    realLinePos = 0;
1236                else // otherwise determine position in destination source
1237                    realLinePos += lineSize - destLineStart+1;
1238            }
1239        }
1240        pos++; // skip newline
1241    }
1242    lineNo = (curColTrans != colTransEnd) ? curColTrans->lineNo : macroColTrans[0].lineNo;
1243    // move to next source translation
1244    if (sourceTransIndex+1 < irp->getSourceTransSize())
1245    {
1246        const AsmRepeat::SourceTrans& fpos = irp->getSourceTrans(sourceTransIndex+1);
1247        if (fpos.lineNo == contentLineNo)
1248        {
1249            macroSubst = fpos.macro;
1250            sourceTransIndex++;
1251            source = RefPtr<const AsmSource>(new AsmRepeatSource(
1252                fpos.source, repeatCount, irp->getRepeatsNum()));
1253        }
1254    }
1255    contentLineNo++;
1256    return (!buffer.empty()) ? buffer.data() : "";
1257}
1258
1259/*
1260 * source pos
1261 */
1262
1263static void printIndent(std::ostream& os, cxuint indentLevel)
1264{
1265    for (; indentLevel != 0; indentLevel--)
1266        os.write("    ", 4);
1267}
1268
1269static RefPtr<const AsmSource> printAsmRepeats(std::ostream& os,
1270           RefPtr<const AsmSource> source, cxuint indentLevel)
1271{
1272    bool firstDepth = true;
1273    while (source->type == AsmSourceType::REPT)
1274    {
1275        auto sourceRept = source.staticCast<const AsmRepeatSource>();
1276        printIndent(os, indentLevel);
1277        os.write((firstDepth)?"In repetition ":"              ", 14);
1278        // print: REPEATSCOUNT/REPEATSNUM:
1279        char numBuf[64];
1280        size_t size = itocstrCStyle(sourceRept->repeatCount+1, numBuf, 32);
1281        numBuf[size++] = '/';
1282        if (sourceRept->repeatsNum!=0)
1283            size += itocstrCStyle(sourceRept->repeatsNum, numBuf+size, 32-size);
1284        else // print '?'. we don't know where is end
1285            numBuf[size++] = '?';
1286        numBuf[size++] = ':';
1287        numBuf[size++] = '\n';
1288        os.write(numBuf, size);
1289        source = sourceRept->source;
1290        firstDepth = false;
1291    }
1292    return source;
1293}
1294
1295void AsmSourcePos::print(std::ostream& os, cxuint indentLevel) const
1296{
1297    if ((!macro && !source) || colNo==0 || lineNo==0)
1298        return; // do not print asm source
1299    if (indentLevel == 10)
1300    {
1301        printIndent(os, indentLevel);
1302        os.write("Can't print all tree trace due to too big depth level\n", 53);
1303        return;
1304    }
1305    const AsmSourcePos* thisPos = this;
1306    bool exprFirstDepth = true;
1307    char numBuf[32];
1308    // print expression source positions
1309    while (thisPos->exprSourcePos!=nullptr)
1310    {
1311        AsmSourcePos sourcePosToPrint = *(thisPos->exprSourcePos);
1312        sourcePosToPrint.exprSourcePos = nullptr;
1313        printIndent(os, indentLevel);
1314        if (sourcePosToPrint.source->type == AsmSourceType::FILE)
1315        {
1316            RefPtr<const AsmFile> file = sourcePosToPrint.source.
1317                        staticCast<const AsmFile>();
1318            if (!file->parent)
1319            {
1320                os.write((exprFirstDepth) ? "Expression evaluation from " :
1321                        "                      from ", 27);
1322                os.write(file->file.c_str(), file->file.size());
1323                // print: :LINENO:COLNO: (COLNO is optional)
1324                numBuf[0] = ':';
1325                size_t size = 1+itocstrCStyle(sourcePosToPrint.lineNo, numBuf+1, 31);
1326                os.write(numBuf, size);
1327                if (colNo != 0)
1328                {
1329                    numBuf[0] = ':';
1330                    size = 1+itocstrCStyle(sourcePosToPrint.colNo, numBuf+1, 29);
1331                    numBuf[size++] = ':';
1332                    os.write(numBuf, size);
1333                }
1334                os.put('\n');
1335                exprFirstDepth = false;
1336                thisPos = thisPos->exprSourcePos;
1337                continue;
1338            }
1339        }
1340        exprFirstDepth = true;
1341        os.write("Expression evaluation from\n", 27);
1342        sourcePosToPrint.print(os, indentLevel+1);
1343        os.put('\n');
1344        thisPos = thisPos->exprSourcePos;
1345    }
1346    /* print macro tree */
1347    RefPtr<const AsmMacroSubst> curMacro = macro;
1348    RefPtr<const AsmMacroSubst> parentMacro;
1349    bool firstDepth = true;
1350    while(curMacro)
1351    {
1352        parentMacro = curMacro->parent;
1353       
1354        if (curMacro->source->type != AsmSourceType::MACRO)
1355        {
1356            /* if file */
1357            RefPtr<const AsmFile> curFile = curMacro->source.staticCast<const AsmFile>();
1358            if (curMacro->source->type == AsmSourceType::REPT || curFile->parent)
1359            {
1360                if (firstDepth)
1361                {
1362                    printIndent(os, indentLevel);
1363                    os.write("In macro substituted from\n", 26);
1364                }
1365                AsmSourcePos nextLevelPos = { RefPtr<const AsmMacroSubst>(),
1366                    curMacro->source, curMacro->lineNo, curMacro->colNo };
1367                nextLevelPos.print(os, indentLevel+1);
1368                os.write((parentMacro) ? ";\n" : ":\n", 2);
1369                firstDepth = true;
1370            }
1371            else
1372            {
1373                printIndent(os, indentLevel);
1374                os.write((firstDepth) ? "In macro substituted from " :
1375                        "                     from ", 26);
1376                // leaf
1377                curFile = curMacro->source.staticCast<const AsmFile>();
1378                if (!curFile->file.empty())
1379                    os.write(curFile->file.c_str(), curFile->file.size());
1380                else // stdin
1381                    os.write("<stdin>", 7);
1382                // print: :LINENO:COLNO or :LINENO:COLNO;
1383                numBuf[0] = ':';
1384                size_t size = 1+itocstrCStyle(curMacro->lineNo, numBuf+1, 29);
1385                numBuf[size++] = ':';
1386                os.write(numBuf, size);
1387                size = itocstrCStyle(curMacro->colNo, numBuf, 29);
1388                numBuf[size++] = (parentMacro) ? ';' : ':';
1389                numBuf[size++] = '\n';
1390                os.write(numBuf, size);
1391                firstDepth = false;
1392            }
1393        }
1394        else
1395        {
1396            // if macro
1397            printIndent(os, indentLevel);
1398            os.write("In macro substituted from macro content:\n", 41);
1399            RefPtr<const AsmMacroSource> curMacroPos =
1400                    curMacro->source.staticCast<const AsmMacroSource>();
1401            AsmSourcePos macroPos = { curMacroPos->macro, curMacroPos->source,
1402                curMacro->lineNo, curMacro->colNo };
1403            macroPos.print(os, indentLevel+1);
1404            os.write((parentMacro) ? ";\n" : ":\n", 2);
1405            firstDepth = true;
1406        }
1407       
1408        curMacro = parentMacro;
1409    }
1410    /* print source tree */
1411    RefPtr<const AsmSource> curSource = source;
1412    while (curSource->type == AsmSourceType::REPT)
1413        curSource = curSource.staticCast<const AsmRepeatSource>()->source;
1414   
1415    if (curSource->type != AsmSourceType::MACRO)
1416    {
1417        // if file
1418        RefPtr<const AsmFile> curFile = curSource.staticCast<const AsmFile>();
1419        if (curFile->parent)
1420        {
1421            RefPtr<const AsmSource> parentSource;
1422            bool firstDepth = true;
1423            while (curFile->parent)
1424            {
1425                parentSource = curFile->parent;
1426               
1427                parentSource = printAsmRepeats(os, parentSource, indentLevel);
1428                if (!firstDepth)
1429                    firstDepth = (curFile->parent != parentSource); // if repeats
1430               
1431                printIndent(os, indentLevel);
1432                if (parentSource->type != AsmSourceType::MACRO)
1433                {
1434                    RefPtr<const AsmFile> parentFile =
1435                            parentSource.staticCast<const AsmFile>();
1436                    os.write(firstDepth ? "In file included from " :
1437                            "                 from ", 22);
1438                    if (!parentFile->file.empty())
1439                        os.write(parentFile->file.c_str(), parentFile->file.size());
1440                    else // stdin
1441                        os.write("<stdin>", 7);
1442                   
1443                    // print: :LINENO:COLNO: or :LINENO:COLNO,
1444                    numBuf[0] = ':';
1445                    size_t size = 1+itocstrCStyle(curFile->lineNo, numBuf+1, 29);
1446                    numBuf[size++] = ':';
1447                    os.write(numBuf, size);
1448                    size = itocstrCStyle(curFile->colNo, numBuf, 30);
1449                    curFile = parentFile.staticCast<const AsmFile>();
1450                    numBuf[size++] = curFile->parent ? ',' : ':';
1451                    numBuf[size++] = '\n';
1452                    os.write(numBuf, size);
1453                    firstDepth = false;
1454                }
1455                else
1456                {
1457                    /* if macro */
1458                    os.write("In file included from macro content:\n", 37);
1459                    RefPtr<const AsmMacroSource> curMacroPos =
1460                            parentSource.staticCast<const AsmMacroSource>();
1461                    AsmSourcePos macroPos = { curMacroPos->macro, curMacroPos->source,
1462                        curFile->lineNo, curFile->colNo };
1463                    macroPos.print(os, indentLevel+1);
1464                    os.write(":\n", 2);
1465                    break;
1466                }
1467            }
1468        }
1469        // leaf
1470        printAsmRepeats(os, source, indentLevel);
1471        printIndent(os, indentLevel);
1472        if (!curSource.staticCast<const AsmFile>()->file.empty())
1473            os.write(curSource.staticCast<const AsmFile>()->file.c_str(),
1474                     curSource.staticCast<const AsmFile>()->file.size());
1475        else // stdin
1476            os.write("<stdin>", 7);
1477        numBuf[0] = ':';
1478        size_t size = 1+itocstrCStyle(lineNo, numBuf+1, 31);
1479        os.write(numBuf, size);
1480        if (colNo != 0)
1481        {
1482            numBuf[0] = ':';
1483            size = 1+itocstrCStyle(colNo, numBuf+1, 31);
1484            os.write(numBuf, size);
1485        }
1486    }
1487    else
1488    {
1489        // if macro
1490        printAsmRepeats(os, source, indentLevel);
1491        printIndent(os, indentLevel);
1492        os.write("In macro content:\n", 18);
1493        RefPtr<const AsmMacroSource> curMacroPos =
1494                curSource.staticCast<const AsmMacroSource>();
1495        AsmSourcePos macroPos = { curMacroPos->macro, curMacroPos->source, lineNo, colNo };
1496        macroPos.print(os, indentLevel+1);
1497    }
1498}
Note: See TracBrowser for help on using the repository browser.