27
27
#include " utf8.h"
28
28
#include " string_parser.h"
29
29
#include " ../../gflib/characters.h"
30
+ #include " io.h"
30
31
31
- AsmFile::AsmFile (std::string filename) : m_filename(filename)
32
+ AsmFile::AsmFile (std::string filename, bool isStdin, bool doEnum ) : m_filename(filename)
32
33
{
33
- FILE *fp = std::fopen (filename.c_str (), " rb" );
34
-
35
- if (fp == NULL )
36
- FATAL_ERROR (" Failed to open \" %s\" for reading.\n " , filename.c_str ());
37
-
38
- std::fseek (fp, 0 , SEEK_END);
39
-
40
- m_size = std::ftell (fp);
41
-
42
- if (m_size < 0 )
43
- FATAL_ERROR (" File size of \" %s\" is less than zero.\n " , filename.c_str ());
44
- else if (m_size == 0 )
45
- return ; // Empty file
46
-
47
- m_buffer = new char [m_size + 1 ];
48
-
49
- std::rewind (fp);
50
-
51
- if (std::fread (m_buffer, m_size, 1 , fp) != 1 )
52
- FATAL_ERROR (" Failed to read \" %s\" .\n " , filename.c_str ());
53
-
54
- m_buffer[m_size] = 0 ;
55
-
56
- std::fclose (fp);
34
+ m_buffer = ReadFileToBuffer (filename.c_str (), isStdin, &m_size);
35
+ m_doEnum = doEnum;
57
36
58
37
m_pos = 0 ;
59
38
m_lineNum = 1 ;
@@ -65,6 +44,7 @@ AsmFile::AsmFile(std::string filename) : m_filename(filename)
65
44
AsmFile::AsmFile (AsmFile&& other) : m_filename(std::move(other.m_filename))
66
45
{
67
46
m_buffer = other.m_buffer ;
47
+ m_doEnum = other.m_doEnum ;
68
48
m_pos = other.m_pos ;
69
49
m_size = other.m_size ;
70
50
m_lineNum = other.m_lineNum ;
@@ -174,6 +154,8 @@ Directive AsmFile::GetDirective()
174
154
return Directive::String;
175
155
else if (CheckForDirective (" .braille" ))
176
156
return Directive::Braille;
157
+ else if (CheckForDirective (" enum" ))
158
+ return Directive::Enum;
177
159
else
178
160
return Directive::Unknown;
179
161
}
@@ -527,6 +509,70 @@ void AsmFile::OutputLine()
527
509
}
528
510
}
529
511
512
+ // parses an assumed C `enum`. Returns false if `enum { ...` is not matched
513
+ bool AsmFile::ParseEnum ()
514
+ {
515
+ if (!m_doEnum)
516
+ return false ;
517
+
518
+ long fallbackPosition = m_pos;
519
+ std::string headerFilename = " " ;
520
+ long currentHeaderLine = SkipWhitespaceAndEol ();
521
+ std::string enumName = ReadIdentifier ();
522
+ currentHeaderLine += SkipWhitespaceAndEol ();
523
+ long enumCounter = 0 ;
524
+ long symbolCount = 0 ;
525
+
526
+ if (m_buffer[m_pos] != ' {' ) // assume assembly macro, otherwise assume enum and report errors accordingly
527
+ {
528
+ m_pos = fallbackPosition - 4 ;
529
+ return false ;
530
+ }
531
+
532
+ currentHeaderLine += FindLastLineNumber (headerFilename);
533
+ m_pos++;
534
+ for (;;)
535
+ {
536
+ currentHeaderLine += SkipWhitespaceAndEol ();
537
+ std::string currentIdentName = ReadIdentifier ();
538
+ if (!currentIdentName.empty ())
539
+ {
540
+ std::printf (" # %ld \" %s\"\n " , currentHeaderLine, headerFilename.c_str ());
541
+ currentHeaderLine += SkipWhitespaceAndEol ();
542
+ if (m_buffer[m_pos] == ' =' )
543
+ {
544
+ m_pos++;
545
+ currentHeaderLine += SkipWhitespaceAndEol ();
546
+ enumCounter = ReadInteger (headerFilename, currentHeaderLine);
547
+ currentHeaderLine += SkipWhitespaceAndEol ();
548
+ }
549
+ std::printf (" .equiv %s, %ld\n " , currentIdentName.c_str (), enumCounter);
550
+ enumCounter++;
551
+ symbolCount++;
552
+ }
553
+ else if (symbolCount == 0 )
554
+ {
555
+ RaiseError (" %s:%ld: empty enum is invalid" , headerFilename.c_str (), currentHeaderLine);
556
+ }
557
+
558
+ if (m_buffer[m_pos] != ' ,' )
559
+ {
560
+ currentHeaderLine += SkipWhitespaceAndEol ();
561
+ if (m_buffer[m_pos++] == ' }' && m_buffer[m_pos++] == ' ;' )
562
+ {
563
+ ExpectEmptyRestOfLine ();
564
+ break ;
565
+ }
566
+ else
567
+ {
568
+ RaiseError (" unterminated enum from included file %s:%ld" , headerFilename.c_str (), currentHeaderLine);
569
+ }
570
+ }
571
+ m_pos++;
572
+ }
573
+ return true ;
574
+ }
575
+
530
576
// Asserts that the rest of the line is empty and moves to the next one.
531
577
void AsmFile::ExpectEmptyRestOfLine ()
532
578
{
@@ -599,3 +645,130 @@ void AsmFile::RaiseWarning(const char* format, ...)
599
645
{
600
646
DO_REPORT (" warning" );
601
647
}
648
+
649
+ // Skips Whitespace including newlines and returns the amount of newlines skipped
650
+ int AsmFile::SkipWhitespaceAndEol ()
651
+ {
652
+ int newlines = 0 ;
653
+ while (m_buffer[m_pos] == ' \t ' || m_buffer[m_pos] == ' ' || m_buffer[m_pos] == ' \n ' )
654
+ {
655
+ if (m_buffer[m_pos] == ' \n ' )
656
+ newlines++;
657
+ m_pos++;
658
+ }
659
+ return newlines;
660
+ }
661
+
662
+ // returns the last line indicator and its corresponding file name without modifying the token index
663
+ int AsmFile::FindLastLineNumber (std::string& filename)
664
+ {
665
+ long pos = m_pos;
666
+ long linebreaks = 0 ;
667
+ while (m_buffer[pos] != ' #' && pos >= 0 )
668
+ {
669
+ if (m_buffer[pos] == ' \n ' )
670
+ linebreaks++;
671
+ pos--;
672
+ }
673
+
674
+ if (pos < 0 )
675
+ RaiseError (" line indicator for header file not found before `enum`" );
676
+
677
+ pos++;
678
+ while (m_buffer[pos] == ' ' || m_buffer[pos] == ' \t ' )
679
+ pos++;
680
+
681
+ if (!IsAsciiDigit (m_buffer[pos]))
682
+ RaiseError (" malformatted line indicator found before `enum`, expected line number" );
683
+
684
+ unsigned n = 0 ;
685
+ int digit = 0 ;
686
+ while ((digit = ConvertDigit (m_buffer[pos++], 10 )) != -1 )
687
+ n = 10 * n + digit;
688
+
689
+ while (m_buffer[pos] == ' ' || m_buffer[pos] == ' \t ' )
690
+ pos++;
691
+
692
+ if (m_buffer[pos++] != ' "' )
693
+ RaiseError (" malformatted line indicator found before `enum`, expected filename" );
694
+
695
+ while (m_buffer[pos] != ' "' )
696
+ {
697
+ unsigned char c = m_buffer[pos++];
698
+
699
+ if (c == 0 )
700
+ {
701
+ if (pos >= m_size)
702
+ RaiseError (" unexpected EOF in line indicator" );
703
+ else
704
+ RaiseError (" unexpected null character in line indicator" );
705
+ }
706
+
707
+ if (!IsAsciiPrintable (c))
708
+ RaiseError (" unexpected character '\\ x%02X' in line indicator" , c);
709
+
710
+ if (c == ' \\ ' )
711
+ {
712
+ c = m_buffer[pos];
713
+ RaiseError (" unexpected escape '\\ %c' in line indicator" , c);
714
+ }
715
+
716
+ filename += c;
717
+ }
718
+
719
+ return n + linebreaks - 1 ;
720
+ }
721
+
722
+ std::string AsmFile::ReadIdentifier ()
723
+ {
724
+ long start = m_pos;
725
+ if (!IsIdentifierStartingChar (m_buffer[m_pos]))
726
+ return std::string ();
727
+
728
+ m_pos++;
729
+
730
+ while (IsIdentifierChar (m_buffer[m_pos]))
731
+ m_pos++;
732
+
733
+ return std::string (&m_buffer[start], m_pos - start);
734
+ }
735
+
736
+ long AsmFile::ReadInteger (std::string filename, long line)
737
+ {
738
+ bool negate = false ;
739
+ int radix = 10 ;
740
+ if (!IsAsciiDigit (m_buffer[m_pos]))
741
+ {
742
+ if (m_buffer[m_pos++] == ' -' )
743
+ negate = true ;
744
+ else
745
+ RaiseError (" expected number in included file %s:%ld" , filename.c_str (), line);
746
+ }
747
+
748
+ if (m_buffer[m_pos] == ' 0' && m_buffer[m_pos + 1 ] == ' x' )
749
+ {
750
+ radix = 16 ;
751
+ m_pos += 2 ;
752
+ }
753
+ else if (m_buffer[m_pos] == ' 0' && m_buffer[m_pos + 1 ] == ' b' )
754
+ {
755
+ radix = 2 ;
756
+ m_pos += 2 ;
757
+ }
758
+ else if (m_buffer[m_pos] == ' 0' && IsAsciiDigit (m_buffer[m_pos+1 ]))
759
+ {
760
+ radix = 8 ;
761
+ m_pos++;
762
+ }
763
+
764
+ long n = 0 ;
765
+ int digit;
766
+
767
+ while ((digit = ConvertDigit (m_buffer[m_pos], radix)) != -1 )
768
+ {
769
+ n = n * radix + digit;
770
+ m_pos++;
771
+ }
772
+
773
+ return negate ? -n : n;
774
+ }
0 commit comments