Commit b1297aa0 authored by Robert Griesemer's avatar Robert Griesemer

- move error handling out of scanner

- use more of the existing library code

R=r
OCL=19957
CL=19959
parent 9a5c7eab
......@@ -29,15 +29,100 @@ export type Flags struct {
}
type ErrorHandler struct {
filename string;
src string;
nerrors int;
nwarnings int;
errpos int;
columns bool;
}
func (h *ErrorHandler) Init(filename, src string, columns bool) {
h.filename = filename;
h.src = src;
h.nerrors = 0;
h.nwarnings = 0;
h.errpos = 0;
h.columns = columns;
}
// Compute (line, column) information for a given source position.
func (h *ErrorHandler) LineCol(pos int) (line, col int) {
line = 1;
lpos := 0;
src := h.src;
if pos > len(src) {
pos = len(src);
}
for i := 0; i < pos; i++ {
if src[i] == '\n' {
line++;
lpos = i;
}
}
return line, pos - lpos;
}
func (h *ErrorHandler) ErrorMsg(pos int, msg string) {
print(h.filename, ":");
if pos >= 0 {
// print position
line, col := h.LineCol(pos);
print(line, ":");
if h.columns {
print(col, ":");
}
}
print(" ", msg, "\n");
h.nerrors++;
h.errpos = pos;
if h.nerrors >= 10 {
sys.exit(1);
}
}
func (h *ErrorHandler) Error(pos int, msg string) {
// only report errors that are sufficiently far away from the previous error
// in the hope to avoid most follow-up errors
const errdist = 20;
delta := pos - h.errpos; // may be negative!
if delta < 0 {
delta = -delta;
}
if delta > errdist || h.nerrors == 0 /* always report first error */ {
h.ErrorMsg(pos, msg);
}
}
func (h *ErrorHandler) Warning(pos int, msg string) {
panic("UNIMPLEMENTED");
}
export func Compile(src_file string, flags *Flags) (*AST.Program, int) {
src, ok := Platform.ReadSourceFile(src_file);
if !ok {
print("cannot open ", src_file, "\n");
return nil, 1;
}
var err ErrorHandler;
err.Init(src_file, src, flags.columns);
var scanner Scanner.Scanner;
scanner.Open(src_file, src, flags.columns, flags.testmode);
scanner.Init(&err, src, flags.testmode);
var tstream *<-chan *Scanner.Token;
if flags.tokenchan {
......@@ -48,7 +133,7 @@ export func Compile(src_file string, flags *Flags) (*AST.Program, int) {
parser.Open(flags.verbose, flags.sixg, flags.deps, &scanner, tstream);
prog := parser.ParseProgram();
return prog, scanner.nerrors;
return prog, err.nerrors;
}
......
......@@ -3,6 +3,8 @@
// license that can be found in the LICENSE file.
package Scanner
import "utf8"
import Utils "utils"
......@@ -276,15 +278,17 @@ func digit_val(ch int) int {
}
export type ErrorHandler interface {
Error(pos int, msg string);
Warning(pos int, msg string);
}
export type Scanner struct {
// error handling
filename string; // error reporting only
nerrors int; // number of errors
errpos int; // last error position
columns bool; // if set, print columns in error messages
err ErrorHandler;
// scanning
src string; // scanned source
src string; // source
pos int; // current reading position
ch int; // one char look-ahead
chpos int; // position of ch
......@@ -304,7 +308,7 @@ func (S *Scanner) Next() {
r, w := int(S.src[S.pos]), 1;
if r >= 0x80 {
// not ascii
r, w = sys.stringtorune(S.src, S.pos);
r, w = utf8.DecodeRuneInString(S.src, S.pos);
}
S.ch = r;
S.chpos = S.pos;
......@@ -313,144 +317,6 @@ func (S *Scanner) Next() {
S.ch = -1; // eof
S.chpos = len(S.src);
}
/*
const (
Bit1 = 7;
Bitx = 6;
Bit2 = 5;
Bit3 = 4;
Bit4 = 3;
T1 = (1 << (Bit1 + 1) - 1) ^ 0xFF; // 0000 0000
Tx = (1 << (Bitx + 1) - 1) ^ 0xFF; // 1000 0000
T2 = (1 << (Bit2 + 1) - 1) ^ 0xFF; // 1100 0000
T3 = (1 << (Bit3 + 1) - 1) ^ 0xFF; // 1110 0000
T4 = (1 << (Bit4 + 1) - 1) ^ 0xFF; // 1111 0000
Rune1 = 1 << (Bit1 + 0*Bitx) - 1; // 0000 0000 0111 1111
Rune2 = 1 << (Bit2 + 1*Bitx) - 1; // 0000 0111 1111 1111
Rune3 = 1 << (Bit3 + 2*Bitx) - 1; // 1111 1111 1111 1111
Maskx = 0x3F; // 1 << Bitx - 1; // 0011 1111
Testx = 0xC0; // Maskx ^ 0xFF; // 1100 0000
Bad = 0xFFFD; // Runeerror
);
src := S.src;
lim := len(src);
pos := S.pos;
// 1-byte sequence
// 0000-007F => T1
if pos >= lim {
S.ch = -1; // end of file
S.chpos = lim;
return;
}
c0 := int(src[pos]);
pos++;
if c0 < Tx {
S.ch = c0;
S.chpos = S.pos;
S.pos = pos;
return;
}
// 2-byte sequence
// 0080-07FF => T2 Tx
if pos >= lim {
goto bad;
}
c1 := int(src[pos]) ^ Tx;
pos++;
if c1 & Testx != 0 {
goto bad;
}
if c0 < T3 {
if c0 < T2 {
goto bad;
}
r := (c0 << Bitx | c1) & Rune2;
if r <= Rune1 {
goto bad;
}
S.ch = r;
S.chpos = S.pos;
S.pos = pos;
return;
}
// 3-byte sequence
// 0800-FFFF => T3 Tx Tx
if pos >= lim {
goto bad;
}
c2 := int(src[pos]) ^ Tx;
pos++;
if c2 & Testx != 0 {
goto bad;
}
if c0 < T4 {
r := (((c0 << Bitx | c1) << Bitx) | c2) & Rune3;
if r <= Rune2 {
goto bad;
}
S.ch = r;
S.chpos = S.pos;
S.pos = pos;
return;
}
// bad encoding
bad:
S.ch = Bad;
S.chpos = S.pos;
S.pos += 1;
return;
*/
}
// Compute (line, column) information for a given source position.
func (S *Scanner) LineCol(pos int) (line, col int) {
line = 1;
lpos := 0;
src := S.src;
if pos > len(src) {
pos = len(src);
}
for i := 0; i < pos; i++ {
if src[i] == '\n' {
line++;
lpos = i;
}
}
return line, pos - lpos;
}
func (S *Scanner) ErrorMsg(pos int, msg string) {
print(S.filename, ":");
if pos >= 0 {
// print position
line, col := S.LineCol(pos);
print(line, ":");
if S.columns {
print(col, ":");
}
}
print(" ", msg, "\n");
S.nerrors++;
S.errpos = pos;
if S.nerrors >= 10 {
sys.exit(1);
}
}
......@@ -464,17 +330,7 @@ func (S *Scanner) Error(pos int, msg string) {
return;
}
// only report errors that are sufficiently far away from the previous error
// in the hope to avoid most follow-up errors
const errdist = 20;
delta := pos - S.errpos; // may be negative!
if delta < 0 {
delta = -delta;
}
if delta > errdist || S.nerrors == 0 /* always report first error */ {
S.ErrorMsg(pos, msg);
}
S.err.Error(pos, msg);
}
......@@ -485,11 +341,8 @@ func (S *Scanner) ExpectNoErrors() {
}
func (S *Scanner) Open(filename, src string, columns, testmode bool) {
S.filename = filename;
S.nerrors = 0;
S.errpos = 0;
S.columns = columns;
func (S *Scanner) Init(err ErrorHandler, src string, testmode bool) {
S.err = err;
S.src = src;
S.pos = 0;
......@@ -600,7 +453,7 @@ exit:
if 0 <= oldpos && oldpos <= len(S.src) {
// the previous error was not found
S.ErrorMsg(oldpos, "ERROR not found");
S.Error(oldpos, "ERROR not found"); // TODO this should call ErrorMsg
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment